idf-build-apps 2.9.0__tar.gz → 2.10.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.
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/.pre-commit-config.yaml +1 -1
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/CHANGELOG.md +6 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/PKG-INFO +1 -1
- idf_build_apps-2.10.0/docs/en/guides/custom_app.md +80 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/en/index.rst +2 -1
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/__init__.py +1 -1
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/args.py +3 -4
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/main.py +14 -2
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/pyproject.toml +1 -1
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/setup.py +1 -1
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/tests/test_build.py +103 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/.editorconfig +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/.git-blame-ignore-revs +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/.gitattributes +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/.github/dependabot.yml +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/.github/workflows/publish-pypi.yml +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/.github/workflows/sync-jira.yml +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/.github/workflows/test-build-docs.yml +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/.github/workflows/test-build-idf-apps.yml +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/.gitignore +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/.readthedocs.yml +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/CONTRIBUTING.md +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/LICENSE +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/README.md +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/_apidoc_templates/module.rst_t +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/_apidoc_templates/package.rst_t +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/_apidoc_templates/toc.rst_t +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/_static/espressif-logo.svg +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/_static/theme_overrides.css +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/_templates/layout.html +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/conf_common.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/en/Makefile +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/en/conf.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/en/explanations/build.rst +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/en/explanations/config_rules.rst +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/en/explanations/dependency_driven_build.rst +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/en/explanations/find.rst +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/en/guides/1.x_to_2.x.md +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/en/others/CHANGELOG.md +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/en/others/CONTRIBUTING.md +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/en/references/cli.rst +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/en/references/config_file.rst +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/en/references/manifest.rst +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/__main__.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/app.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/autocompletions.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/constants.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/finder.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/junit/__init__.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/junit/report.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/junit/utils.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/log.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/manifest/__init__.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/manifest/manifest.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/manifest/soc_header.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/py.typed +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/session_args.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/utils.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/vendors/__init__.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/vendors/pydantic_sources.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/yaml/__init__.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/idf_build_apps/yaml/parser.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/license_header.txt +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/tests/conftest.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/tests/test_app.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/tests/test_args.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/tests/test_cmd.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/tests/test_finder.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/tests/test_manifest.py +0 -0
- {idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/tests/test_utils.py +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Custom App Classes
|
|
2
|
+
|
|
3
|
+
`idf-build-apps` allows you to create custom app classes by subclassing the base `App` class. This is useful when you need to implement custom build logic or handle special project types.
|
|
4
|
+
|
|
5
|
+
## Creating a Custom App Class
|
|
6
|
+
|
|
7
|
+
Here's an example of creating a custom app class:
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from idf_build_apps import App
|
|
11
|
+
from idf_build_apps.constants import BuildStatus
|
|
12
|
+
import os
|
|
13
|
+
from typing import Literal # Python 3.8+ only. from typing_extensions import Literal for earlier versions
|
|
14
|
+
|
|
15
|
+
class CustomApp(App):
|
|
16
|
+
build_system: Literal['custom'] = 'custom' # Must be unique to identify your custom app type
|
|
17
|
+
|
|
18
|
+
def build(self, *args, **kwargs):
|
|
19
|
+
# Implement your custom build logic here
|
|
20
|
+
os.makedirs(self.build_path, exist_ok=True)
|
|
21
|
+
with open(os.path.join(self.build_path, 'dummy.txt'), 'w') as f:
|
|
22
|
+
f.write('Custom build successful')
|
|
23
|
+
self.build_status = BuildStatus.SUCCESS
|
|
24
|
+
print('Custom build successful')
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def is_app(cls, path: str) -> bool:
|
|
28
|
+
# Implement logic to determine if a path contains your custom app type
|
|
29
|
+
return True
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Using Custom App Classes
|
|
33
|
+
|
|
34
|
+
You can use custom app classes in two ways:
|
|
35
|
+
|
|
36
|
+
### Via CLI
|
|
37
|
+
|
|
38
|
+
```shell
|
|
39
|
+
idf-build-apps build -p /path/to/app --target esp32 --build-system custom:CustomApp
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Where `custom:CustomApp` is in the format `module:class`. The module must be in your Python path.
|
|
43
|
+
|
|
44
|
+
### Via Python API
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from idf_build_apps import find_apps
|
|
48
|
+
|
|
49
|
+
apps = find_apps(
|
|
50
|
+
paths=['/path/to/app'],
|
|
51
|
+
target='esp32',
|
|
52
|
+
build_system=CustomApp,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
for app in apps:
|
|
56
|
+
app.build()
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Important Notes
|
|
60
|
+
|
|
61
|
+
- Your custom app class must subclass `App`
|
|
62
|
+
- The `build_system` attribute must be unique to identify your app type
|
|
63
|
+
- You must implement the `is_app()` class method to identify your app type
|
|
64
|
+
- For JSON serialization support, you need to pass your custom class to `json_to_app()` when deserializing
|
|
65
|
+
|
|
66
|
+
## Example: JSON Serialization
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from idf_build_apps import json_to_app
|
|
70
|
+
|
|
71
|
+
# Serialize
|
|
72
|
+
json_str = custom_app.to_json()
|
|
73
|
+
|
|
74
|
+
# Deserialize
|
|
75
|
+
deserialized_app = json_to_app(json_str, extra_classes=[CustomApp])
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Available Methods and Properties
|
|
79
|
+
|
|
80
|
+
Please refer to the [API reference of the class `App`](https://docs.espressif.com/projects/idf-build-apps/en/latest/references/api/idf_build_apps.html#idf_build_apps.app.App)
|
|
@@ -414,10 +414,9 @@ class FindBuildArguments(DependencyDrivenBuildArguments):
|
|
|
414
414
|
default='all', # type: ignore
|
|
415
415
|
)
|
|
416
416
|
build_system: t.Union[str, t.Type[App]] = field(
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
description='Filter the apps by build system. By default set to "cmake"',
|
|
417
|
+
None,
|
|
418
|
+
description='Filter the apps by build system. By default set to "cmake". '
|
|
419
|
+
'Can be either "cmake", "make" or a custom App class path in format "module:class"',
|
|
421
420
|
default='cmake', # type: ignore
|
|
422
421
|
)
|
|
423
422
|
recursive: bool = field(
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
# SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
|
|
6
6
|
import argparse
|
|
7
|
+
import importlib
|
|
7
8
|
import json
|
|
8
9
|
import logging
|
|
9
10
|
import os
|
|
@@ -90,13 +91,24 @@ def find_apps(
|
|
|
90
91
|
|
|
91
92
|
app_cls: t.Type[App]
|
|
92
93
|
if isinstance(find_arguments.build_system, str):
|
|
93
|
-
# backwards compatible
|
|
94
94
|
if find_arguments.build_system == 'cmake':
|
|
95
95
|
app_cls = CMakeApp
|
|
96
96
|
elif find_arguments.build_system == 'make':
|
|
97
97
|
app_cls = MakeApp
|
|
98
|
+
elif ':' in find_arguments.build_system:
|
|
99
|
+
# Custom App class in format "module:class"
|
|
100
|
+
try:
|
|
101
|
+
module_path, class_name = find_arguments.build_system.split(':')
|
|
102
|
+
module = importlib.import_module(module_path)
|
|
103
|
+
app_cls = getattr(module, class_name)
|
|
104
|
+
if not issubclass(app_cls, App):
|
|
105
|
+
raise ValueError(f'Class {class_name} must be a subclass of App')
|
|
106
|
+
except (ValueError, ImportError, AttributeError) as e:
|
|
107
|
+
raise ValueError(f'Invalid custom App class path: {find_arguments.build_system}. Error: {e!s}')
|
|
98
108
|
else:
|
|
99
|
-
raise ValueError(
|
|
109
|
+
raise ValueError(
|
|
110
|
+
'build_system must be either "cmake", "make" or a custom App class path in format "module:class"'
|
|
111
|
+
)
|
|
100
112
|
else:
|
|
101
113
|
app_cls = find_arguments.build_system
|
|
102
114
|
|
|
@@ -38,7 +38,7 @@ entry_points = \
|
|
|
38
38
|
{'console_scripts': ['idf-build-apps = idf_build_apps:main.main']}
|
|
39
39
|
|
|
40
40
|
setup(name='idf-build-apps',
|
|
41
|
-
version='2.
|
|
41
|
+
version='2.10.0',
|
|
42
42
|
description='Tools for building ESP-IDF related apps.',
|
|
43
43
|
author=None,
|
|
44
44
|
author_email='Fu Hanxi <fuhanxi@espressif.com>',
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
|
|
4
4
|
import os
|
|
5
5
|
import shutil
|
|
6
|
+
import subprocess
|
|
6
7
|
from copy import (
|
|
7
8
|
deepcopy,
|
|
8
9
|
)
|
|
10
|
+
from pathlib import Path
|
|
9
11
|
from xml.etree import (
|
|
10
12
|
ElementTree,
|
|
11
13
|
)
|
|
@@ -20,6 +22,7 @@ from idf_build_apps import (
|
|
|
20
22
|
find_apps,
|
|
21
23
|
)
|
|
22
24
|
from idf_build_apps.app import (
|
|
25
|
+
App,
|
|
23
26
|
CMakeApp,
|
|
24
27
|
)
|
|
25
28
|
from idf_build_apps.args import BuildArguments
|
|
@@ -27,6 +30,7 @@ from idf_build_apps.constants import (
|
|
|
27
30
|
IDF_PATH,
|
|
28
31
|
BuildStatus,
|
|
29
32
|
)
|
|
33
|
+
from idf_build_apps.utils import Literal
|
|
30
34
|
|
|
31
35
|
|
|
32
36
|
@pytest.mark.skipif(not shutil.which('idf.py'), reason='idf.py not found')
|
|
@@ -205,6 +209,105 @@ class TestBuild:
|
|
|
205
209
|
assert test_suite.findall('testcase')[0].attrib['name'] == 'foo/bar/build'
|
|
206
210
|
|
|
207
211
|
|
|
212
|
+
class CustomClassApp(App):
|
|
213
|
+
build_system: Literal['custom_class'] = 'custom_class' # type: ignore
|
|
214
|
+
|
|
215
|
+
def build(self, *args, **kwargs):
|
|
216
|
+
# For testing, we'll just create a dummy build directory
|
|
217
|
+
if not self.dry_run:
|
|
218
|
+
os.makedirs(self.build_path, exist_ok=True)
|
|
219
|
+
with open(os.path.join(self.build_path, 'dummy.txt'), 'w') as f:
|
|
220
|
+
f.write('Custom build successful')
|
|
221
|
+
self.build_status = BuildStatus.SUCCESS
|
|
222
|
+
print('Custom build successful')
|
|
223
|
+
|
|
224
|
+
@classmethod
|
|
225
|
+
def is_app(cls, path: str) -> bool: # noqa: ARG003
|
|
226
|
+
return True
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@pytest.mark.skipif(not shutil.which('idf.py'), reason='idf.py not found')
|
|
230
|
+
class TestBuildWithCustomApp:
|
|
231
|
+
custom_app_code = """
|
|
232
|
+
from idf_build_apps import App
|
|
233
|
+
import os
|
|
234
|
+
from idf_build_apps.constants import BuildStatus
|
|
235
|
+
from idf_build_apps.utils import Literal
|
|
236
|
+
|
|
237
|
+
class CustomApp(App):
|
|
238
|
+
build_system: Literal['custom'] = 'custom'
|
|
239
|
+
|
|
240
|
+
def build(self, *args, **kwargs):
|
|
241
|
+
# For testing, we'll just create a dummy build directory
|
|
242
|
+
if not self.dry_run:
|
|
243
|
+
os.makedirs(self.build_path, exist_ok=True)
|
|
244
|
+
with open(os.path.join(self.build_path, 'dummy.txt'), 'w') as f:
|
|
245
|
+
f.write('Custom build successful')
|
|
246
|
+
self.build_status = BuildStatus.SUCCESS
|
|
247
|
+
print('Custom build successful')
|
|
248
|
+
|
|
249
|
+
@classmethod
|
|
250
|
+
def is_app(cls, path: str) -> bool:
|
|
251
|
+
return True
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
@pytest.fixture(autouse=True)
|
|
255
|
+
def _setup(self, tmp_path: Path, monkeypatch):
|
|
256
|
+
os.chdir(tmp_path)
|
|
257
|
+
|
|
258
|
+
test_app = tmp_path / 'test_app'
|
|
259
|
+
|
|
260
|
+
test_app.mkdir()
|
|
261
|
+
(test_app / 'main' / 'main.c').parent.mkdir(parents=True)
|
|
262
|
+
(test_app / 'main' / 'main.c').write_text('void app_main() {}')
|
|
263
|
+
|
|
264
|
+
# Create a custom app module
|
|
265
|
+
custom_module = tmp_path / 'custom.py'
|
|
266
|
+
custom_module.write_text(self.custom_app_code)
|
|
267
|
+
|
|
268
|
+
monkeypatch.setenv('PYTHONPATH', os.getenv('PYTHONPATH', '') + os.pathsep + str(tmp_path))
|
|
269
|
+
|
|
270
|
+
return test_app
|
|
271
|
+
|
|
272
|
+
def test_custom_app_cli(self, tmp_path):
|
|
273
|
+
subprocess.run(
|
|
274
|
+
[
|
|
275
|
+
'idf-build-apps',
|
|
276
|
+
'build',
|
|
277
|
+
'-p',
|
|
278
|
+
'test_app',
|
|
279
|
+
'--target',
|
|
280
|
+
'esp32',
|
|
281
|
+
'--build-system',
|
|
282
|
+
'custom:CustomApp',
|
|
283
|
+
],
|
|
284
|
+
check=True,
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
assert (tmp_path / 'test_app' / 'build' / 'dummy.txt').exists()
|
|
288
|
+
assert (tmp_path / 'test_app' / 'build' / 'dummy.txt').read_text() == 'Custom build successful'
|
|
289
|
+
|
|
290
|
+
def test_custom_app_function(self, tmp_path):
|
|
291
|
+
# Import the custom app class
|
|
292
|
+
# Find and build the app using the imported CustomApp class
|
|
293
|
+
apps = find_apps(
|
|
294
|
+
paths=['test_app'],
|
|
295
|
+
target='esp32',
|
|
296
|
+
build_system=CustomClassApp,
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
assert len(apps) == 1
|
|
300
|
+
app = apps[0]
|
|
301
|
+
assert isinstance(app, CustomClassApp)
|
|
302
|
+
assert app.build_system == 'custom_class'
|
|
303
|
+
|
|
304
|
+
# Build the app
|
|
305
|
+
app.build()
|
|
306
|
+
assert app.build_status == BuildStatus.SUCCESS
|
|
307
|
+
assert (tmp_path / 'test_app' / 'build' / 'dummy.txt').exists()
|
|
308
|
+
assert (tmp_path / 'test_app' / 'build' / 'dummy.txt').read_text() == 'Custom build successful'
|
|
309
|
+
|
|
310
|
+
|
|
208
311
|
def test_build_apps_collect_files_when_no_apps_built(tmp_path):
|
|
209
312
|
os.chdir(tmp_path)
|
|
210
313
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{idf_build_apps-2.9.0 → idf_build_apps-2.10.0}/docs/en/explanations/dependency_driven_build.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|