idf-build-apps 2.11.1__tar.gz → 2.12.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.11.1 → idf_build_apps-2.12.0}/.pre-commit-config.yaml +2 -2
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/CHANGELOG.md +14 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/CONTRIBUTING.md +8 -12
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/PKG-INFO +1 -1
- idf_build_apps-2.12.0/docs/en/explanations/build_status.rst +122 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/en/index.rst +1 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/__init__.py +1 -1
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/app.py +110 -66
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/args.py +39 -7
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/finder.py +39 -55
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/main.py +1 -2
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/manifest/__init__.py +7 -2
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/manifest/manifest.py +17 -5
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/session_args.py +1 -2
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/pyproject.toml +2 -2
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/setup.py +1 -1
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/tests/test_app.py +6 -2
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/tests/test_args.py +182 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/tests/test_build.py +48 -0
- idf_build_apps-2.12.0/tests/test_disable_reasons.py +238 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/tests/test_finder.py +3 -2
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/.editorconfig +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/.git-blame-ignore-revs +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/.gitattributes +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/.github/dependabot.yml +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/.github/workflows/publish-pypi.yml +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/.github/workflows/sync-jira.yml +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/.github/workflows/test-build-docs.yml +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/.github/workflows/test-build-idf-apps.yml +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/.gitignore +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/.readthedocs.yml +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/LICENSE +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/README.md +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/_apidoc_templates/module.rst_t +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/_apidoc_templates/package.rst_t +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/_apidoc_templates/toc.rst_t +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/_static/espressif-logo.svg +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/_static/theme_overrides.css +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/_templates/layout.html +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/conf_common.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/en/Makefile +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/en/conf.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/en/explanations/build.rst +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/en/explanations/config_rules.rst +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/en/explanations/dependency_driven_build.rst +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/en/explanations/find.rst +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/en/guides/1.x_to_2.x.md +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/en/guides/custom_app.md +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/en/others/CHANGELOG.md +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/en/others/CONTRIBUTING.md +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/en/references/cli.rst +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/en/references/config_file.rst +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/docs/en/references/manifest.rst +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/__main__.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/autocompletions.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/constants.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/junit/__init__.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/junit/report.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/junit/utils.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/log.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/manifest/soc_header.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/py.typed +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/utils.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/vendors/__init__.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/vendors/pydantic_sources.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/yaml/__init__.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/idf_build_apps/yaml/parser.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/license_header.txt +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/tests/conftest.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/tests/test_cmd.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/tests/test_manifest.py +0 -0
- {idf_build_apps-2.11.1 → idf_build_apps-2.12.0}/tests/test_utils.py +0 -0
|
@@ -17,13 +17,13 @@ repos:
|
|
|
17
17
|
- --use-current-year
|
|
18
18
|
exclude: 'idf_build_apps/vendors/'
|
|
19
19
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
20
|
-
rev: 'v0.
|
|
20
|
+
rev: 'v0.12.5'
|
|
21
21
|
hooks:
|
|
22
22
|
- id: ruff
|
|
23
23
|
args: ['--fix']
|
|
24
24
|
- id: ruff-format
|
|
25
25
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
26
|
-
rev: 'v1.
|
|
26
|
+
rev: 'v1.17.0'
|
|
27
27
|
hooks:
|
|
28
28
|
- id: mypy
|
|
29
29
|
args: ['--warn-unused-ignores']
|
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## v2.12.0 (2025-08-11)
|
|
6
|
+
|
|
7
|
+
### Feat
|
|
8
|
+
|
|
9
|
+
- recording build_disable_reason and test_disable_reason
|
|
10
|
+
- support --archives, --archive-details ARCHIVE or --files args of idf.py size
|
|
11
|
+
- support config `manifest_exclude_regexes`
|
|
12
|
+
|
|
13
|
+
## v2.11.2 (2025-06-10)
|
|
14
|
+
|
|
15
|
+
### Fix
|
|
16
|
+
|
|
17
|
+
- missing `FolderRule` in .manifest
|
|
18
|
+
|
|
5
19
|
## v2.11.1 (2025-06-04)
|
|
6
20
|
|
|
7
21
|
### Fix
|
|
@@ -6,18 +6,14 @@ Hi! We're glad that you're interested in contributing to `idf-build-apps`. This
|
|
|
6
6
|
|
|
7
7
|
Here's a table shows the supported ESP-IDF versions and the corresponding Python versions.
|
|
8
8
|
|
|
9
|
-
| ESP-IDF Version | ESP-IDF
|
|
10
|
-
|
|
11
|
-
|
|
|
12
|
-
|
|
|
13
|
-
|
|
|
14
|
-
|
|
|
15
|
-
| 5.
|
|
16
|
-
|
|
|
17
|
-
| 5.2 | 3.7+ | main (2.x) |
|
|
18
|
-
| 5.3 | 3.8+ | main (2.x) |
|
|
19
|
-
| 5.4 | 3.8+ | main (2.x) |
|
|
20
|
-
| master (5.5) | 3.9+ | main (2.x) |
|
|
9
|
+
| ESP-IDF Version | ESP-IDF Version EOL | ESP-IDF Minimum Python Version | idf-build-apps Releases |
|
|
10
|
+
|-----------------|---------------------|--------------------------------|-------------------------|
|
|
11
|
+
| 5.1 | 2025.12.30 | 3.7 | 2.x |
|
|
12
|
+
| 5.2 | 2026.08.16 | 3.8 | 2.x |
|
|
13
|
+
| 5.3 | 2027.01.25 | 3.8 | 2.x |
|
|
14
|
+
| 5.4 | 2027.07.05 | 3.8 | 2.x |
|
|
15
|
+
| 5.5 | 2028.01.21 | 3.9 | 2.x |
|
|
16
|
+
| 6.0 (master) | N/A | 3.10 | 3.x WIP |
|
|
21
17
|
|
|
22
18
|
`idf-build-apps` is following the semantic versioning. The major version of `idf-build-apps` is the same as the ESP-IDF version it supports. For example, `idf-build-apps` 1.x supports ESP-IDF 4.x, and `idf-build-apps` 2.x supports ESP-IDF 5.x.
|
|
23
19
|
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
##############
|
|
2
|
+
Build Status
|
|
3
|
+
##############
|
|
4
|
+
|
|
5
|
+
This page explains the different build statuses that apps can have during the build process and what each status means.
|
|
6
|
+
|
|
7
|
+
Each app in `idf-build-apps` has a build status that indicates its current state in the build pipeline. Understanding these statuses is crucial for interpreting build results and troubleshooting issues.
|
|
8
|
+
|
|
9
|
+
********************
|
|
10
|
+
Available Statuses
|
|
11
|
+
********************
|
|
12
|
+
|
|
13
|
+
The following build statuses are available:
|
|
14
|
+
|
|
15
|
+
``unknown``
|
|
16
|
+
===========
|
|
17
|
+
|
|
18
|
+
The default status when an app is first discovered. The app's build status has not yet been determined.
|
|
19
|
+
|
|
20
|
+
This status indicates that:
|
|
21
|
+
|
|
22
|
+
- The app has been found but not yet processed
|
|
23
|
+
- Further ``idf.py reconfigure`` is needed to determine if the build can proceed
|
|
24
|
+
|
|
25
|
+
``disabled``
|
|
26
|
+
============
|
|
27
|
+
|
|
28
|
+
The app supports the target architecture, but has been disabled by manifest rules or configuration.
|
|
29
|
+
|
|
30
|
+
This status indicates that:
|
|
31
|
+
|
|
32
|
+
- The app is compatible with the target but explicitly disabled
|
|
33
|
+
- Manifest rules contain ``disable`` clauses that match this app and target combination
|
|
34
|
+
|
|
35
|
+
Apps with this status will not be built unless specifically included with ``--include-disabled-apps``.
|
|
36
|
+
|
|
37
|
+
``skipped``
|
|
38
|
+
===========
|
|
39
|
+
|
|
40
|
+
The app supports the target and could potentially be built, but has been skipped due to dependency-driven build logic or dry run mode.
|
|
41
|
+
|
|
42
|
+
This status indicates that:
|
|
43
|
+
|
|
44
|
+
- **Dependency-driven build**: The app doesn't depend on any of the modified components/files in the current build
|
|
45
|
+
- **Dry run mode**: The ``--dry-run`` flag was used, so no actual building occurs
|
|
46
|
+
|
|
47
|
+
Apps with this status will not be built unless specifically included with ``--include-skipped-apps``.
|
|
48
|
+
|
|
49
|
+
``should be built``
|
|
50
|
+
===================
|
|
51
|
+
|
|
52
|
+
The app should be built but hasn't been built yet.
|
|
53
|
+
|
|
54
|
+
This status indicates that:
|
|
55
|
+
|
|
56
|
+
- The app has passed all checks and is ready for building
|
|
57
|
+
- Dependency analysis shows the app should be included in this build
|
|
58
|
+
- The app has not been built yet in the current run
|
|
59
|
+
|
|
60
|
+
``build failed``
|
|
61
|
+
================
|
|
62
|
+
|
|
63
|
+
The app build process was attempted but failed.
|
|
64
|
+
|
|
65
|
+
This status indicates that:
|
|
66
|
+
|
|
67
|
+
- The build process started but encountered an error
|
|
68
|
+
- Compilation, linking, or other build steps failed
|
|
69
|
+
- The failure reason is typically available in the build comment and build logs
|
|
70
|
+
|
|
71
|
+
``build success``
|
|
72
|
+
=================
|
|
73
|
+
|
|
74
|
+
The app was successfully built.
|
|
75
|
+
|
|
76
|
+
This status indicates that:
|
|
77
|
+
|
|
78
|
+
- All build steps completed without errors
|
|
79
|
+
- The app binary was generated successfully
|
|
80
|
+
- The build process finished normally
|
|
81
|
+
|
|
82
|
+
************************
|
|
83
|
+
Status Transition Flow
|
|
84
|
+
************************
|
|
85
|
+
|
|
86
|
+
The typical flow of build statuses is:
|
|
87
|
+
|
|
88
|
+
#. **unknown** → Initial state when app is discovered
|
|
89
|
+
#. **unknown** → **disabled** (if app doesn't support target or is disabled by manifest)
|
|
90
|
+
#. **unknown** → **skipped** (if dependency checks show app shouldn't be built)
|
|
91
|
+
#. **unknown** → **should be built** (if app passes all checks)
|
|
92
|
+
#. **should be built** → **build failed** (if build encounters errors)
|
|
93
|
+
#. **should be built** → **build success** (if build completes successfully)
|
|
94
|
+
|
|
95
|
+
.. note::
|
|
96
|
+
|
|
97
|
+
Apps in ``disabled`` or ``skipped`` status will not transition to ``should be built`` unless the conditions change or specific inclusion flags are used.
|
|
98
|
+
|
|
99
|
+
**********************
|
|
100
|
+
Viewing Build Status
|
|
101
|
+
**********************
|
|
102
|
+
|
|
103
|
+
You can view the build status of apps in several ways:
|
|
104
|
+
|
|
105
|
+
- **JSON output**: Use ``--json-output`` to save detailed status information
|
|
106
|
+
- **Build logs**: Status and comments are included in build output
|
|
107
|
+
- **Summary reports**: Final status counts are shown at the end of builds
|
|
108
|
+
|
|
109
|
+
**************************
|
|
110
|
+
Including Apps by Status
|
|
111
|
+
**************************
|
|
112
|
+
|
|
113
|
+
By default, only apps with ``unknown``, ``should be built``, ``build failed``, and ``build success`` statuses are processed. You can include additional apps using:
|
|
114
|
+
|
|
115
|
+
- ``--include-disabled-apps``: Include apps with ``disabled`` status
|
|
116
|
+
- ``--include-skipped-apps``: Include apps with ``skipped`` status
|
|
117
|
+
|
|
118
|
+
This is useful for:
|
|
119
|
+
|
|
120
|
+
- Testing disabled apps during development
|
|
121
|
+
- Force-building apps that would normally be skipped
|
|
122
|
+
- Comprehensive testing regardless of dependency analysis
|
|
@@ -95,6 +95,7 @@ class App(BaseModel):
|
|
|
95
95
|
|
|
96
96
|
_build_log_filename: t.Optional[str] = None
|
|
97
97
|
_size_json_filename: t.Optional[str] = None
|
|
98
|
+
size_json_extra_args: t.Optional[t.List[str]] = None
|
|
98
99
|
|
|
99
100
|
dry_run: bool = False
|
|
100
101
|
verbose: bool = False
|
|
@@ -105,15 +106,16 @@ class App(BaseModel):
|
|
|
105
106
|
# build_apps() related
|
|
106
107
|
index: t.Optional[int] = None
|
|
107
108
|
|
|
108
|
-
# build status related
|
|
109
109
|
build_status: BuildStatus = BuildStatus.UNKNOWN
|
|
110
110
|
build_comment: t.Optional[str] = None
|
|
111
|
+
test_comment: t.Optional[str] = None
|
|
111
112
|
|
|
112
113
|
_build_duration: float = 0
|
|
113
114
|
_build_timestamp: t.Optional[datetime] = None
|
|
114
115
|
|
|
115
116
|
__EQ_IGNORE_FIELDS__ = [
|
|
116
117
|
'build_comment',
|
|
118
|
+
'test_comment',
|
|
117
119
|
]
|
|
118
120
|
__EQ_TUNE_FIELDS__ = {
|
|
119
121
|
'app_dir': lambda x: (os.path.realpath(os.path.expanduser(x))),
|
|
@@ -324,8 +326,7 @@ class App(BaseModel):
|
|
|
324
326
|
# put the expanded variable files in a temporary directory
|
|
325
327
|
# will remove if the content is the same as the original one
|
|
326
328
|
expanded_dir = os.path.join(self.work_dir, 'expanded_sdkconfig_files', os.path.basename(self.build_dir))
|
|
327
|
-
|
|
328
|
-
os.makedirs(expanded_dir)
|
|
329
|
+
os.makedirs(expanded_dir, exist_ok=True)
|
|
329
330
|
|
|
330
331
|
for f in self.sdkconfig_defaults_candidates + ([self.sdkconfig_path] if self.sdkconfig_path else []):
|
|
331
332
|
# use filepath if abs/rel already point to itself
|
|
@@ -338,57 +339,47 @@ class App(BaseModel):
|
|
|
338
339
|
continue
|
|
339
340
|
|
|
340
341
|
expanded_fp = os.path.join(expanded_dir, os.path.basename(f))
|
|
341
|
-
with open(f) as fr:
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
if
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
):
|
|
380
|
-
LOGGER.debug(
|
|
381
|
-
'Copy target-specific sdkconfig file %s to %s', target_specific_file, expanded_dir
|
|
382
|
-
)
|
|
383
|
-
shutil.copy(target_specific_file, expanded_dir)
|
|
384
|
-
|
|
385
|
-
# remove if expanded folder is empty
|
|
386
|
-
try:
|
|
387
|
-
os.rmdir(expanded_dir)
|
|
388
|
-
except OSError:
|
|
389
|
-
pass
|
|
342
|
+
with open(f) as fr, open(expanded_fp, 'w') as fw:
|
|
343
|
+
for line in fr:
|
|
344
|
+
line = os.path.expandvars(line)
|
|
345
|
+
|
|
346
|
+
m = self.SDKCONFIG_LINE_REGEX.match(line)
|
|
347
|
+
if m:
|
|
348
|
+
key, value = m.group(1), m.group(2)
|
|
349
|
+
if key == 'CONFIG_IDF_TARGET':
|
|
350
|
+
sdkconfig_files_defined_target = value
|
|
351
|
+
|
|
352
|
+
if isinstance(self, CMakeApp):
|
|
353
|
+
if key in self.SDKCONFIG_TEST_OPTS:
|
|
354
|
+
self.cmake_vars[key] = value
|
|
355
|
+
continue
|
|
356
|
+
if key in self.SDKCONFIG_IGNORE_OPTS:
|
|
357
|
+
continue
|
|
358
|
+
|
|
359
|
+
fw.write(line)
|
|
360
|
+
|
|
361
|
+
with open(f) as fr, open(expanded_fp) as new_fr:
|
|
362
|
+
if fr.read() == new_fr.read():
|
|
363
|
+
LOGGER.debug('Use sdkconfig file %s', f)
|
|
364
|
+
try:
|
|
365
|
+
os.unlink(expanded_fp)
|
|
366
|
+
except OSError:
|
|
367
|
+
LOGGER.debug('Failed to remove file %s', expanded_fp)
|
|
368
|
+
real_sdkconfig_files.append(f)
|
|
369
|
+
else:
|
|
370
|
+
LOGGER.debug('Expand sdkconfig file %s to %s', f, expanded_fp)
|
|
371
|
+
real_sdkconfig_files.append(expanded_fp)
|
|
372
|
+
# copy the related target-specific sdkconfig files
|
|
373
|
+
par_dir = os.path.abspath(os.path.join(f, '..'))
|
|
374
|
+
for target_specific_file in (
|
|
375
|
+
os.path.join(par_dir, str(p))
|
|
376
|
+
for p in Path(par_dir).glob(os.path.basename(f) + f'.{self.target}')
|
|
377
|
+
):
|
|
378
|
+
LOGGER.debug('Copy target-specific sdkconfig file %s to %s', target_specific_file, expanded_dir)
|
|
379
|
+
shutil.copy(target_specific_file, expanded_dir)
|
|
390
380
|
|
|
391
381
|
try:
|
|
382
|
+
os.rmdir(expanded_dir)
|
|
392
383
|
os.rmdir(os.path.join(self.work_dir, 'expanded_sdkconfig_files'))
|
|
393
384
|
except OSError:
|
|
394
385
|
pass
|
|
@@ -428,14 +419,14 @@ class App(BaseModel):
|
|
|
428
419
|
|
|
429
420
|
@property
|
|
430
421
|
def supported_targets(self) -> t.List[str]:
|
|
422
|
+
if self.sdkconfig_files_defined_idf_target:
|
|
423
|
+
return [self.sdkconfig_files_defined_idf_target]
|
|
424
|
+
|
|
431
425
|
if self.MANIFEST:
|
|
432
426
|
return self.MANIFEST.enable_build_targets(
|
|
433
427
|
self.app_dir, self.sdkconfig_files_defined_idf_target, self.config_name
|
|
434
428
|
)
|
|
435
429
|
|
|
436
|
-
if self.sdkconfig_files_defined_idf_target:
|
|
437
|
-
return [self.sdkconfig_files_defined_idf_target]
|
|
438
|
-
|
|
439
430
|
return DEFAULT_BUILD_TARGETS.get()
|
|
440
431
|
|
|
441
432
|
@property
|
|
@@ -656,11 +647,10 @@ class App(BaseModel):
|
|
|
656
647
|
[
|
|
657
648
|
sys.executable,
|
|
658
649
|
str(IDF_SIZE_PY),
|
|
659
|
-
|
|
660
|
-
+ (['--json'] if IDF_VERSION < Version('5.1') else ['--format', 'json'])
|
|
661
|
-
+ [
|
|
650
|
+
*(['--json'] if IDF_VERSION < Version('5.1') else ['--format', 'json']),
|
|
662
651
|
'-o',
|
|
663
652
|
self.size_json_path,
|
|
653
|
+
*(self.size_json_extra_args or []),
|
|
664
654
|
map_file,
|
|
665
655
|
],
|
|
666
656
|
check=True,
|
|
@@ -668,14 +658,13 @@ class App(BaseModel):
|
|
|
668
658
|
else:
|
|
669
659
|
with open(self.size_json_path, 'w') as fw:
|
|
670
660
|
subprocess_run(
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
),
|
|
661
|
+
[
|
|
662
|
+
sys.executable,
|
|
663
|
+
str(IDF_SIZE_PY),
|
|
664
|
+
'--json',
|
|
665
|
+
*(self.size_json_extra_args or []),
|
|
666
|
+
map_file,
|
|
667
|
+
],
|
|
679
668
|
log_terminal=False,
|
|
680
669
|
log_fs=fw,
|
|
681
670
|
check=True,
|
|
@@ -735,9 +724,35 @@ class App(BaseModel):
|
|
|
735
724
|
modified_components: t.Optional[t.List[str]] = None,
|
|
736
725
|
modified_files: t.Optional[t.List[str]] = None,
|
|
737
726
|
) -> None:
|
|
727
|
+
"""Check if this app should be built based on the modified files and components."""
|
|
738
728
|
if self.build_status != BuildStatus.UNKNOWN:
|
|
739
729
|
return
|
|
740
730
|
|
|
731
|
+
if self.target not in self.supported_targets:
|
|
732
|
+
# default error message
|
|
733
|
+
self.build_comment = (
|
|
734
|
+
f'Target {self.target} not in default build targets {",".join(DEFAULT_BUILD_TARGETS.get())}'
|
|
735
|
+
)
|
|
736
|
+
|
|
737
|
+
if self.MANIFEST:
|
|
738
|
+
rule = self.MANIFEST.most_suitable_rule(self.app_dir)
|
|
739
|
+
|
|
740
|
+
# disable > enable
|
|
741
|
+
for clause in rule.disable:
|
|
742
|
+
if clause.get_value(self.target, self.config_name or ''):
|
|
743
|
+
self.build_comment = f'Disabled by manifest rule: {clause}'
|
|
744
|
+
break
|
|
745
|
+
else:
|
|
746
|
+
# Check if it's not enabled by manifest rules
|
|
747
|
+
if rule.enable:
|
|
748
|
+
# Has enable rules but target not in enabled targets
|
|
749
|
+
self.build_comment = 'Not enabled by manifest rules:\n'
|
|
750
|
+
self.build_comment += '\n'.join(f'- {clause}' for clause in rule.enable)
|
|
751
|
+
|
|
752
|
+
self.build_status = BuildStatus.DISABLED
|
|
753
|
+
self._checked_should_build = True
|
|
754
|
+
return
|
|
755
|
+
|
|
741
756
|
if not check_app_dependencies:
|
|
742
757
|
self.build_status = BuildStatus.SHOULD_BE_BUILT
|
|
743
758
|
self._checked_should_build = True
|
|
@@ -804,6 +819,35 @@ class App(BaseModel):
|
|
|
804
819
|
self.build_comment = 'current build does not modify any components or files required by this app'
|
|
805
820
|
self._checked_should_build = True
|
|
806
821
|
|
|
822
|
+
def check_should_test(self) -> None:
|
|
823
|
+
"""Check if testing is disabled for this app and set test_disable_reason."""
|
|
824
|
+
if not self.MANIFEST:
|
|
825
|
+
return
|
|
826
|
+
|
|
827
|
+
rule = self.MANIFEST.most_suitable_rule(self.app_dir)
|
|
828
|
+
|
|
829
|
+
# Check if testing is enabled for this target
|
|
830
|
+
if self.target not in self.verified_targets:
|
|
831
|
+
# default error message
|
|
832
|
+
self.test_comment = f'Target {self.target} not in verified targets {",".join(self.verified_targets)}'
|
|
833
|
+
|
|
834
|
+
# disable_test > disable > enable
|
|
835
|
+
for clause in rule.disable_test:
|
|
836
|
+
if clause.get_value(self.target, self.config_name or ''):
|
|
837
|
+
self.test_comment = f'Disabled by manifest rule: {clause}'
|
|
838
|
+
return
|
|
839
|
+
|
|
840
|
+
# Check if disabled by general disable rules
|
|
841
|
+
for clause in rule.disable:
|
|
842
|
+
if clause.get_value(self.target, self.config_name or ''):
|
|
843
|
+
self.test_comment = f'Disabled by manifest rule: {clause}'
|
|
844
|
+
return
|
|
845
|
+
|
|
846
|
+
# If not explicitly disabled but not in enabled targets
|
|
847
|
+
if rule.enable:
|
|
848
|
+
self.test_comment = 'Not enabled by manifest rules:\n'
|
|
849
|
+
self.test_comment += '\n'.join(f'- {clause}' for clause in rule.enable)
|
|
850
|
+
|
|
807
851
|
|
|
808
852
|
class MakeApp(App):
|
|
809
853
|
MAKE_PROJECT_LINE: t.ClassVar[str] = r'include $(IDF_PATH)/make/project.mk'
|
|
@@ -240,14 +240,24 @@ class DependencyDrivenBuildArguments(GlobalArguments):
|
|
|
240
240
|
validate_method=[ValidateMethod.TO_LIST],
|
|
241
241
|
nargs='+',
|
|
242
242
|
),
|
|
243
|
-
description='space-separated list of file patterns to search for the manifest files. '
|
|
243
|
+
description='space-separated list of file glob patterns to search for the manifest files. '
|
|
244
244
|
'The matched files will be loaded as the manifest files.',
|
|
245
245
|
default=None, # type: ignore
|
|
246
246
|
)
|
|
247
|
+
manifest_exclude_regexes: t.Optional[t.List[str]] = field(
|
|
248
|
+
FieldMetadata(
|
|
249
|
+
validate_method=[ValidateMethod.TO_LIST],
|
|
250
|
+
nargs='+',
|
|
251
|
+
),
|
|
252
|
+
description='space-separated list of regex to exclude when searching for manifest files. '
|
|
253
|
+
'Files matching these patterns will be ignored. '
|
|
254
|
+
'By default excludes files under "managed_components" directories.',
|
|
255
|
+
default=['/managed_components/'], # type: ignore
|
|
256
|
+
)
|
|
247
257
|
manifest_rootpath: str = field(
|
|
248
258
|
None,
|
|
249
259
|
description='Root path to resolve the relative paths defined in the manifest files. '
|
|
250
|
-
'By default set to the current directory.
|
|
260
|
+
'By default set to the current directory.',
|
|
251
261
|
default=os.curdir, # type: ignore
|
|
252
262
|
)
|
|
253
263
|
modified_components: t.Optional[t.List[str]] = field(
|
|
@@ -337,6 +347,22 @@ class DependencyDrivenBuildArguments(GlobalArguments):
|
|
|
337
347
|
for pat in [to_absolute_path(p, self.manifest_rootpath) for p in self.manifest_filepatterns]:
|
|
338
348
|
matched_paths.update(glob.glob(str(pat), recursive=True))
|
|
339
349
|
|
|
350
|
+
exclude_regexes = {re.compile(regex) for regex in self.manifest_exclude_regexes or []}
|
|
351
|
+
|
|
352
|
+
# Filter out files matching excluded patterns
|
|
353
|
+
if matched_paths:
|
|
354
|
+
filtered_paths = set()
|
|
355
|
+
for path in matched_paths:
|
|
356
|
+
posix_path = Path(path).as_posix()
|
|
357
|
+
for regex in exclude_regexes:
|
|
358
|
+
if regex.search(posix_path):
|
|
359
|
+
LOGGER.debug(f'Excluding manifest file {path} due to excluded regex match')
|
|
360
|
+
break
|
|
361
|
+
else:
|
|
362
|
+
filtered_paths.add(path)
|
|
363
|
+
|
|
364
|
+
matched_paths = filtered_paths
|
|
365
|
+
|
|
340
366
|
if matched_paths:
|
|
341
367
|
if self.manifest_files:
|
|
342
368
|
self.manifest_files.extend(matched_paths)
|
|
@@ -482,6 +508,13 @@ class FindBuildArguments(DependencyDrivenBuildArguments):
|
|
|
482
508
|
validation_alias=AliasChoices('size_json_filename', 'size_file'),
|
|
483
509
|
default=None, # type: ignore
|
|
484
510
|
)
|
|
511
|
+
size_json_extra_args: t.Optional[t.List[str]] = field(
|
|
512
|
+
FieldMetadata(
|
|
513
|
+
validate_method=[ValidateMethod.TO_LIST],
|
|
514
|
+
),
|
|
515
|
+
description='Additional arguments to pass to esp_idf_size tool',
|
|
516
|
+
default=None, # type: ignore
|
|
517
|
+
)
|
|
485
518
|
config_rules: t.Optional[t.List[str]] = field(
|
|
486
519
|
FieldMetadata(
|
|
487
520
|
validate_method=[ValidateMethod.TO_LIST],
|
|
@@ -607,7 +640,7 @@ class FindBuildArguments(DependencyDrivenBuildArguments):
|
|
|
607
640
|
elif self.enable_preview_targets:
|
|
608
641
|
self.default_build_targets = deepcopy(ALL_TARGETS)
|
|
609
642
|
LOGGER.info('Overriding default build targets to %s', self.default_build_targets)
|
|
610
|
-
DEFAULT_BUILD_TARGETS.set(self.default_build_targets)
|
|
643
|
+
DEFAULT_BUILD_TARGETS.set(self.default_build_targets)
|
|
611
644
|
|
|
612
645
|
if self.disable_targets and DEFAULT_BUILD_TARGETS.get():
|
|
613
646
|
LOGGER.info('Disable targets: %s', self.disable_targets)
|
|
@@ -791,7 +824,7 @@ class BuildArguments(FindBuildArguments):
|
|
|
791
824
|
hidden=True,
|
|
792
825
|
),
|
|
793
826
|
description='Record size json filepath of the built apps to the specified file. '
|
|
794
|
-
'Each line is a json string. Can expand placeholders @p.
|
|
827
|
+
'Each line is a json string. Can expand placeholders @p.',
|
|
795
828
|
validation_alias=AliasChoices('collect_size_info_filename', 'collect_size_info'),
|
|
796
829
|
default=None, # type: ignore
|
|
797
830
|
exclude=True, # computed field is used
|
|
@@ -802,7 +835,7 @@ class BuildArguments(FindBuildArguments):
|
|
|
802
835
|
hidden=True,
|
|
803
836
|
),
|
|
804
837
|
description='Record serialized app model of the built apps to the specified file. '
|
|
805
|
-
'Each line is a json string. Can expand placeholders @p.
|
|
838
|
+
'Each line is a json string. Can expand placeholders @p.',
|
|
806
839
|
validation_alias=AliasChoices('collect_app_info_filename', 'collect_app_info'),
|
|
807
840
|
default=None, # type: ignore
|
|
808
841
|
exclude=True, # computed field is used
|
|
@@ -812,8 +845,7 @@ class BuildArguments(FindBuildArguments):
|
|
|
812
845
|
deprecates={'junitxml': {}},
|
|
813
846
|
hidden=True,
|
|
814
847
|
),
|
|
815
|
-
description='Path to the junitxml file to record the build results. Can expand placeholder @p.
|
|
816
|
-
'Support environment variables.',
|
|
848
|
+
description='Path to the junitxml file to record the build results. Can expand placeholder @p.',
|
|
817
849
|
validation_alias=AliasChoices('junitxml_filename', 'junitxml'),
|
|
818
850
|
default=None, # type: ignore
|
|
819
851
|
exclude=True, # computed field is used
|