idf-build-apps 2.5.3__py3-none-any.whl → 2.6.1__py3-none-any.whl
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/__init__.py +2 -2
- idf_build_apps/args.py +89 -65
- idf_build_apps/constants.py +11 -56
- idf_build_apps/finder.py +1 -0
- idf_build_apps/junit/utils.py +1 -1
- idf_build_apps/main.py +7 -5
- idf_build_apps/manifest/__init__.py +12 -1
- idf_build_apps/manifest/manifest.py +16 -8
- idf_build_apps/manifest/soc_header.py +3 -138
- idf_build_apps/py.typed +0 -0
- idf_build_apps/vendors/pydantic_sources.py +53 -34
- {idf_build_apps-2.5.3.dist-info → idf_build_apps-2.6.1.dist-info}/METADATA +5 -3
- idf_build_apps-2.6.1.dist-info/RECORD +27 -0
- {idf_build_apps-2.5.3.dist-info → idf_build_apps-2.6.1.dist-info}/WHEEL +1 -1
- idf_build_apps/manifest/if_parser.py +0 -240
- idf_build_apps-2.5.3.dist-info/RECORD +0 -27
- {idf_build_apps-2.5.3.dist-info → idf_build_apps-2.6.1.dist-info}/LICENSE +0 -0
- {idf_build_apps-2.5.3.dist-info → idf_build_apps-2.6.1.dist-info}/entry_points.txt +0 -0
idf_build_apps/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2022-
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
"""
|
|
@@ -8,7 +8,7 @@ Tools for building ESP-IDF related apps.
|
|
|
8
8
|
# ruff: noqa: E402
|
|
9
9
|
# avoid circular imports
|
|
10
10
|
|
|
11
|
-
__version__ = '2.
|
|
11
|
+
__version__ = '2.6.1'
|
|
12
12
|
|
|
13
13
|
from .session_args import (
|
|
14
14
|
SessionArgs,
|
idf_build_apps/args.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
|
1
|
+
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import argparse
|
|
@@ -27,7 +27,7 @@ from pydantic_settings import (
|
|
|
27
27
|
from typing_extensions import Concatenate, ParamSpec
|
|
28
28
|
|
|
29
29
|
from . import SESSION_ARGS, App, setup_logging
|
|
30
|
-
from .constants import ALL_TARGETS
|
|
30
|
+
from .constants import ALL_TARGETS, IDF_BUILD_APPS_TOML_FN
|
|
31
31
|
from .manifest.manifest import FolderRule, Manifest
|
|
32
32
|
from .utils import InvalidCommand, files_matches_patterns, semicolon_separated_str_to_list, to_absolute_path, to_list
|
|
33
33
|
from .vendors.pydantic_sources import PyprojectTomlConfigSettingsSource, TomlConfigSettingsSource
|
|
@@ -37,6 +37,7 @@ LOGGER = logging.getLogger(__name__)
|
|
|
37
37
|
|
|
38
38
|
class ValidateMethod(str, enum.Enum):
|
|
39
39
|
TO_LIST = 'to_list'
|
|
40
|
+
EXPAND_VARS = 'expand_vars'
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
@dataclass
|
|
@@ -114,11 +115,13 @@ def get_meta(f: FieldInfo) -> t.Optional[FieldMetadata]:
|
|
|
114
115
|
class BaseArguments(BaseSettings):
|
|
115
116
|
"""Base settings class for all settings classes"""
|
|
116
117
|
|
|
118
|
+
CONFIG_FILE_PATH: t.ClassVar[t.Optional[Path]] = None
|
|
119
|
+
|
|
117
120
|
model_config = SettingsConfigDict(
|
|
118
|
-
|
|
121
|
+
# these below two are supported in pydantic 2.6
|
|
119
122
|
pyproject_toml_table_header=('tool', 'idf-build-apps'),
|
|
120
123
|
pyproject_toml_depth=sys.maxsize,
|
|
121
|
-
extra='ignore',
|
|
124
|
+
extra='ignore', # we're supporting pydantic <2.6 as well, so we ignore extra fields
|
|
122
125
|
)
|
|
123
126
|
|
|
124
127
|
@classmethod
|
|
@@ -130,11 +133,15 @@ class BaseArguments(BaseSettings):
|
|
|
130
133
|
dotenv_settings: PydanticBaseSettingsSource, # noqa: ARG003
|
|
131
134
|
file_secret_settings: PydanticBaseSettingsSource, # noqa: ARG003
|
|
132
135
|
) -> t.Tuple[PydanticBaseSettingsSource, ...]:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
TomlConfigSettingsSource(settings_cls),
|
|
136
|
-
PyprojectTomlConfigSettingsSource(settings_cls),
|
|
137
|
-
|
|
136
|
+
sources: t.Tuple[PydanticBaseSettingsSource, ...] = (init_settings,)
|
|
137
|
+
if cls.CONFIG_FILE_PATH is None:
|
|
138
|
+
sources += (TomlConfigSettingsSource(settings_cls, toml_file=Path(IDF_BUILD_APPS_TOML_FN)),)
|
|
139
|
+
sources += (PyprojectTomlConfigSettingsSource(settings_cls, toml_file=Path('pyproject.toml')),)
|
|
140
|
+
else:
|
|
141
|
+
sources += (TomlConfigSettingsSource(settings_cls, toml_file=Path(cls.CONFIG_FILE_PATH)),)
|
|
142
|
+
sources += (PyprojectTomlConfigSettingsSource(settings_cls, toml_file=Path(cls.CONFIG_FILE_PATH)),)
|
|
143
|
+
|
|
144
|
+
return sources
|
|
138
145
|
|
|
139
146
|
@field_validator('*', mode='before')
|
|
140
147
|
@classmethod
|
|
@@ -143,8 +150,15 @@ class BaseArguments(BaseSettings):
|
|
|
143
150
|
f = cls.model_fields[info.field_name]
|
|
144
151
|
meta = get_meta(f)
|
|
145
152
|
if meta and meta.validate_method:
|
|
146
|
-
|
|
147
|
-
|
|
153
|
+
for method in meta.validate_method:
|
|
154
|
+
if method == ValidateMethod.TO_LIST:
|
|
155
|
+
v = to_list(v)
|
|
156
|
+
elif method == ValidateMethod.EXPAND_VARS:
|
|
157
|
+
v = os.path.expandvars(v)
|
|
158
|
+
else:
|
|
159
|
+
raise NotImplementedError(f'Unknown validate method: {method}')
|
|
160
|
+
|
|
161
|
+
return v
|
|
148
162
|
|
|
149
163
|
return v
|
|
150
164
|
|
|
@@ -156,19 +170,19 @@ class GlobalArguments(BaseArguments):
|
|
|
156
170
|
action='count',
|
|
157
171
|
),
|
|
158
172
|
description='Verbosity level. By default set to WARNING. Specify -v for INFO, -vv for DEBUG',
|
|
159
|
-
default=0,
|
|
173
|
+
default=0, # type: ignore
|
|
160
174
|
)
|
|
161
175
|
log_file: t.Optional[str] = field(
|
|
162
176
|
None,
|
|
163
177
|
description='Path to the log file, if not specified logs will be printed to stderr',
|
|
164
|
-
default=None,
|
|
178
|
+
default=None, # type: ignore
|
|
165
179
|
)
|
|
166
180
|
no_color: bool = field(
|
|
167
181
|
FieldMetadata(
|
|
168
182
|
action='store_true',
|
|
169
183
|
),
|
|
170
184
|
description='Disable colored output',
|
|
171
|
-
default=False,
|
|
185
|
+
default=False, # type: ignore
|
|
172
186
|
)
|
|
173
187
|
|
|
174
188
|
def model_post_init(self, __context: Any) -> None:
|
|
@@ -190,7 +204,7 @@ class DependencyDrivenBuildArguments(GlobalArguments):
|
|
|
190
204
|
),
|
|
191
205
|
description='Path to the manifest files which contains the build test rules of the apps',
|
|
192
206
|
validation_alias=AliasChoices('manifest_files', 'manifest_file'),
|
|
193
|
-
default=None,
|
|
207
|
+
default=None, # type: ignore
|
|
194
208
|
)
|
|
195
209
|
manifest_filepatterns: t.Optional[t.List[str]] = field(
|
|
196
210
|
FieldMetadata(
|
|
@@ -199,13 +213,15 @@ class DependencyDrivenBuildArguments(GlobalArguments):
|
|
|
199
213
|
),
|
|
200
214
|
description='space-separated list of file patterns to search for the manifest files. '
|
|
201
215
|
'The matched files will be loaded as the manifest files.',
|
|
202
|
-
default=None,
|
|
216
|
+
default=None, # type: ignore
|
|
203
217
|
)
|
|
204
218
|
manifest_rootpath: str = field(
|
|
205
|
-
|
|
219
|
+
FieldMetadata(
|
|
220
|
+
validate_method=[ValidateMethod.EXPAND_VARS],
|
|
221
|
+
),
|
|
206
222
|
description='Root path to resolve the relative paths defined in the manifest files. '
|
|
207
|
-
'By default set to the current directory',
|
|
208
|
-
default=os.curdir,
|
|
223
|
+
'By default set to the current directory. Support environment variables.',
|
|
224
|
+
default=os.curdir, # type: ignore
|
|
209
225
|
)
|
|
210
226
|
modified_components: t.Optional[t.List[str]] = field(
|
|
211
227
|
FieldMetadata(
|
|
@@ -215,7 +231,7 @@ class DependencyDrivenBuildArguments(GlobalArguments):
|
|
|
215
231
|
description='semicolon-separated list of modified components. '
|
|
216
232
|
'If set to "", the value would be considered as None. '
|
|
217
233
|
'If set to ";", the value would be considered as an empty list.',
|
|
218
|
-
default=None,
|
|
234
|
+
default=None, # type: ignore
|
|
219
235
|
)
|
|
220
236
|
modified_files: t.Optional[t.List[str]] = field(
|
|
221
237
|
FieldMetadata(
|
|
@@ -225,7 +241,7 @@ class DependencyDrivenBuildArguments(GlobalArguments):
|
|
|
225
241
|
description='semicolon-separated list of modified files. '
|
|
226
242
|
'If set to "", the value would be considered as None. '
|
|
227
243
|
'If set to ";", the value would be considered as an empty list.',
|
|
228
|
-
default=None,
|
|
244
|
+
default=None, # type: ignore
|
|
229
245
|
)
|
|
230
246
|
deactivate_dependency_driven_build_by_components: t.Optional[t.List[str]] = field(
|
|
231
247
|
FieldMetadata(
|
|
@@ -247,7 +263,7 @@ class DependencyDrivenBuildArguments(GlobalArguments):
|
|
|
247
263
|
validation_alias=AliasChoices(
|
|
248
264
|
'deactivate_dependency_driven_build_by_components', 'ignore_app_dependencies_components'
|
|
249
265
|
),
|
|
250
|
-
default=None,
|
|
266
|
+
default=None, # type: ignore
|
|
251
267
|
)
|
|
252
268
|
deactivate_dependency_driven_build_by_filepatterns: t.Optional[t.List[str]] = field(
|
|
253
269
|
FieldMetadata(
|
|
@@ -269,21 +285,21 @@ class DependencyDrivenBuildArguments(GlobalArguments):
|
|
|
269
285
|
validation_alias=AliasChoices(
|
|
270
286
|
'deactivate_dependency_driven_build_by_filepatterns', 'ignore_app_dependencies_filepatterns'
|
|
271
287
|
),
|
|
272
|
-
default=None,
|
|
288
|
+
default=None, # type: ignore
|
|
273
289
|
)
|
|
274
290
|
check_manifest_rules: bool = field(
|
|
275
291
|
FieldMetadata(
|
|
276
292
|
action='store_true',
|
|
277
293
|
),
|
|
278
294
|
description='Check if all folders defined in the manifest files exist. Fail if not',
|
|
279
|
-
default=False,
|
|
295
|
+
default=False, # type: ignore
|
|
280
296
|
)
|
|
281
297
|
compare_manifest_sha_filepath: t.Optional[str] = field(
|
|
282
298
|
None,
|
|
283
299
|
description='Path to the file containing the hash of the manifest rules. '
|
|
284
300
|
'Compare the hash with the current manifest rules. '
|
|
285
301
|
'All matched apps will be built if the corresponding manifest rule is modified',
|
|
286
|
-
default=None,
|
|
302
|
+
default=None, # type: ignore
|
|
287
303
|
)
|
|
288
304
|
|
|
289
305
|
def model_post_init(self, __context: Any) -> None:
|
|
@@ -377,28 +393,28 @@ class FindBuildArguments(DependencyDrivenBuildArguments):
|
|
|
377
393
|
nargs='*',
|
|
378
394
|
),
|
|
379
395
|
description='Paths to the directories containing the apps. By default set to the current directory',
|
|
380
|
-
default=os.curdir,
|
|
396
|
+
default=os.curdir, # type: ignore
|
|
381
397
|
)
|
|
382
398
|
target: str = field(
|
|
383
399
|
FieldMetadata(
|
|
384
400
|
shorthand='-t',
|
|
385
401
|
),
|
|
386
402
|
description='Filter the apps by target. By default set to "all"',
|
|
387
|
-
default='all',
|
|
403
|
+
default='all', # type: ignore
|
|
388
404
|
)
|
|
389
405
|
build_system: t.Union[str, t.Type[App]] = field(
|
|
390
406
|
FieldMetadata(
|
|
391
407
|
choices=['cmake', 'make'],
|
|
392
408
|
),
|
|
393
409
|
description='Filter the apps by build system. By default set to "cmake"',
|
|
394
|
-
default='cmake',
|
|
410
|
+
default='cmake', # type: ignore
|
|
395
411
|
)
|
|
396
412
|
recursive: bool = field(
|
|
397
413
|
FieldMetadata(
|
|
398
414
|
action='store_true',
|
|
399
415
|
),
|
|
400
416
|
description='Search for apps recursively under the specified paths',
|
|
401
|
-
default=False,
|
|
417
|
+
default=False, # type: ignore
|
|
402
418
|
)
|
|
403
419
|
exclude: t.Optional[t.List[str]] = field(
|
|
404
420
|
FieldMetadata(
|
|
@@ -407,20 +423,20 @@ class FindBuildArguments(DependencyDrivenBuildArguments):
|
|
|
407
423
|
),
|
|
408
424
|
description='Ignore the specified directories while searching recursively',
|
|
409
425
|
validation_alias=AliasChoices('exclude', 'exclude_list'),
|
|
410
|
-
default=None,
|
|
426
|
+
default=None, # type: ignore
|
|
411
427
|
)
|
|
412
428
|
work_dir: t.Optional[str] = field(
|
|
413
429
|
None,
|
|
414
430
|
description='Copy the app to this directory before building. '
|
|
415
431
|
'By default set to the app directory. Can expand placeholders',
|
|
416
|
-
default=None,
|
|
432
|
+
default=None, # type: ignore
|
|
417
433
|
)
|
|
418
434
|
build_dir: str = field(
|
|
419
435
|
None,
|
|
420
436
|
description='Build directory for the app. By default set to "build". '
|
|
421
437
|
'When set to relative path, it will be treated as relative to the app directory. '
|
|
422
438
|
'Can expand placeholders',
|
|
423
|
-
default='build',
|
|
439
|
+
default='build', # type: ignore
|
|
424
440
|
)
|
|
425
441
|
build_log_filename: t.Optional[str] = field(
|
|
426
442
|
FieldMetadata(
|
|
@@ -428,7 +444,7 @@ class FindBuildArguments(DependencyDrivenBuildArguments):
|
|
|
428
444
|
),
|
|
429
445
|
description='Log filename under the build directory instead of stdout. Can expand placeholders',
|
|
430
446
|
validation_alias=AliasChoices('build_log_filename', 'build_log'),
|
|
431
|
-
default=None,
|
|
447
|
+
default=None, # type: ignore
|
|
432
448
|
)
|
|
433
449
|
size_json_filename: t.Optional[str] = field(
|
|
434
450
|
FieldMetadata(
|
|
@@ -436,7 +452,7 @@ class FindBuildArguments(DependencyDrivenBuildArguments):
|
|
|
436
452
|
),
|
|
437
453
|
description='`idf.py size` output file under the build directory when specified. ' 'Can expand placeholders',
|
|
438
454
|
validation_alias=AliasChoices('size_json_filename', 'size_file'),
|
|
439
|
-
default=None,
|
|
455
|
+
default=None, # type: ignore
|
|
440
456
|
)
|
|
441
457
|
config_rules: t.Optional[t.List[str]] = field(
|
|
442
458
|
FieldMetadata(
|
|
@@ -454,31 +470,31 @@ class FindBuildArguments(DependencyDrivenBuildArguments):
|
|
|
454
470
|
'FILEPATTERN is the filename of the sdkconfig file with a single wildcard character (*). '
|
|
455
471
|
'The NAME is the value matched by the wildcard',
|
|
456
472
|
validation_alias=AliasChoices('config_rules', 'config_rules_str', 'config'),
|
|
457
|
-
default=None,
|
|
473
|
+
default=None, # type: ignore
|
|
458
474
|
)
|
|
459
475
|
override_sdkconfig_items: t.Optional[str] = field(
|
|
460
476
|
None,
|
|
461
477
|
description='A comma-separated list of key=value pairs to override the sdkconfig items',
|
|
462
|
-
default=None,
|
|
478
|
+
default=None, # type: ignore
|
|
463
479
|
)
|
|
464
480
|
override_sdkconfig_files: t.Optional[str] = field(
|
|
465
481
|
None,
|
|
466
482
|
description='A comma-separated list of sdkconfig files to override the sdkconfig items. '
|
|
467
483
|
'When set to relative path, it will be treated as relative to the current directory',
|
|
468
|
-
default=None,
|
|
484
|
+
default=None, # type: ignore
|
|
469
485
|
)
|
|
470
486
|
sdkconfig_defaults: t.Optional[str] = field(
|
|
471
487
|
None,
|
|
472
488
|
description='A semicolon-separated list of sdkconfig files passed to `idf.py -DSDKCONFIG_DEFAULTS`. '
|
|
473
489
|
'SDKCONFIG_DEFAULTS environment variable is used when not specified',
|
|
474
|
-
default=os.getenv('SDKCONFIG_DEFAULTS', None),
|
|
490
|
+
default=os.getenv('SDKCONFIG_DEFAULTS', None), # type: ignore
|
|
475
491
|
)
|
|
476
492
|
check_warnings: bool = field(
|
|
477
493
|
FieldMetadata(
|
|
478
494
|
action='store_true',
|
|
479
495
|
),
|
|
480
496
|
description='Check for warnings in the build output. Fail if any warnings are found',
|
|
481
|
-
default=False,
|
|
497
|
+
default=False, # type: ignore
|
|
482
498
|
)
|
|
483
499
|
default_build_targets: t.Optional[t.List[str]] = field(
|
|
484
500
|
FieldMetadata(
|
|
@@ -487,7 +503,7 @@ class FindBuildArguments(DependencyDrivenBuildArguments):
|
|
|
487
503
|
),
|
|
488
504
|
description='space-separated list of the default enabled build targets for the apps. '
|
|
489
505
|
'When not specified, the default value is the targets listed by `idf.py --list-targets`',
|
|
490
|
-
default=None,
|
|
506
|
+
default=None, # type: ignore
|
|
491
507
|
)
|
|
492
508
|
enable_preview_targets: bool = field(
|
|
493
509
|
FieldMetadata(
|
|
@@ -495,28 +511,28 @@ class FindBuildArguments(DependencyDrivenBuildArguments):
|
|
|
495
511
|
),
|
|
496
512
|
description='When enabled, the default build targets will be set to all apps, '
|
|
497
513
|
'including the preview targets. As the targets defined in `idf.py --list-targets --preview`',
|
|
498
|
-
default=False,
|
|
514
|
+
default=False, # type: ignore
|
|
499
515
|
)
|
|
500
516
|
include_skipped_apps: bool = field(
|
|
501
517
|
FieldMetadata(
|
|
502
518
|
action='store_true',
|
|
503
519
|
),
|
|
504
520
|
description='Include the skipped apps in the output, together with the enabled ones',
|
|
505
|
-
default=False,
|
|
521
|
+
default=False, # type: ignore
|
|
506
522
|
)
|
|
507
523
|
include_disabled_apps: bool = field(
|
|
508
524
|
FieldMetadata(
|
|
509
525
|
action='store_true',
|
|
510
526
|
),
|
|
511
527
|
description='Include the disabled apps in the output, together with the enabled ones',
|
|
512
|
-
default=False,
|
|
528
|
+
default=False, # type: ignore
|
|
513
529
|
)
|
|
514
530
|
include_all_apps: bool = field(
|
|
515
531
|
FieldMetadata(
|
|
516
532
|
action='store_true',
|
|
517
533
|
),
|
|
518
534
|
description='Include skipped, and disabled apps in the output, together with the enabled ones',
|
|
519
|
-
default=False,
|
|
535
|
+
default=False, # type: ignore
|
|
520
536
|
)
|
|
521
537
|
|
|
522
538
|
def model_post_init(self, __context: Any) -> None:
|
|
@@ -557,7 +573,7 @@ class FindArguments(FindBuildArguments):
|
|
|
557
573
|
shorthand='-o',
|
|
558
574
|
),
|
|
559
575
|
description='Record the found apps to the specified file instead of stdout',
|
|
560
|
-
default=None,
|
|
576
|
+
default=None, # type: ignore
|
|
561
577
|
)
|
|
562
578
|
output_format: str = field(
|
|
563
579
|
FieldMetadata(
|
|
@@ -566,7 +582,7 @@ class FindArguments(FindBuildArguments):
|
|
|
566
582
|
description='Output format of the found apps. '
|
|
567
583
|
'In "raw" format, each line is a json string serialized from the app model. '
|
|
568
584
|
'In "json" format, the output is a json list of the serialized app models',
|
|
569
|
-
default='raw',
|
|
585
|
+
default='raw', # type: ignore
|
|
570
586
|
)
|
|
571
587
|
|
|
572
588
|
def model_post_init(self, __context: Any) -> None:
|
|
@@ -587,7 +603,7 @@ class BuildArguments(FindBuildArguments):
|
|
|
587
603
|
action='store_true',
|
|
588
604
|
),
|
|
589
605
|
description='Enable verbose output of the build system',
|
|
590
|
-
default=False,
|
|
606
|
+
default=False, # type: ignore
|
|
591
607
|
)
|
|
592
608
|
parallel_count: int = field(
|
|
593
609
|
FieldMetadata(
|
|
@@ -597,7 +613,7 @@ class BuildArguments(FindBuildArguments):
|
|
|
597
613
|
'Specified together with --parallel-index. '
|
|
598
614
|
'The given apps will be divided into parallel_count parts, '
|
|
599
615
|
'and the current run will build the parallel_index-th part',
|
|
600
|
-
default=1,
|
|
616
|
+
default=1, # type: ignore
|
|
601
617
|
)
|
|
602
618
|
parallel_index: int = field(
|
|
603
619
|
FieldMetadata(
|
|
@@ -607,28 +623,28 @@ class BuildArguments(FindBuildArguments):
|
|
|
607
623
|
'Specified together with --parallel-count. '
|
|
608
624
|
'The given apps will be divided into parallel_count parts, '
|
|
609
625
|
'and the current run will build the parallel_index-th part',
|
|
610
|
-
default=1,
|
|
626
|
+
default=1, # type: ignore
|
|
611
627
|
)
|
|
612
628
|
dry_run: bool = field(
|
|
613
629
|
FieldMetadata(
|
|
614
630
|
action='store_true',
|
|
615
631
|
),
|
|
616
632
|
description='Skip the actual build, only print the build process',
|
|
617
|
-
default=False,
|
|
633
|
+
default=False, # type: ignore
|
|
618
634
|
)
|
|
619
635
|
keep_going: bool = field(
|
|
620
636
|
FieldMetadata(
|
|
621
637
|
action='store_true',
|
|
622
638
|
),
|
|
623
639
|
description='Continue building the next app when the current build fails',
|
|
624
|
-
default=False,
|
|
640
|
+
default=False, # type: ignore
|
|
625
641
|
)
|
|
626
642
|
no_preserve: bool = field(
|
|
627
643
|
FieldMetadata(
|
|
628
644
|
action='store_true',
|
|
629
645
|
),
|
|
630
646
|
description='Do not preserve the build directory after a successful build',
|
|
631
|
-
default=False,
|
|
647
|
+
default=False, # type: ignore
|
|
632
648
|
)
|
|
633
649
|
ignore_warning_strs: t.Optional[t.List[str]] = field(
|
|
634
650
|
FieldMetadata(
|
|
@@ -641,7 +657,7 @@ class BuildArguments(FindBuildArguments):
|
|
|
641
657
|
description='space-separated list of patterns. '
|
|
642
658
|
'Ignore the warnings in the build output that match the patterns',
|
|
643
659
|
validation_alias=AliasChoices('ignore_warning_strs', 'ignore_warning_str'),
|
|
644
|
-
default=None,
|
|
660
|
+
default=None, # type: ignore
|
|
645
661
|
)
|
|
646
662
|
ignore_warning_files: t.Optional[t.List[t.Union[str, TextIOWrapper]]] = field(
|
|
647
663
|
FieldMetadata(
|
|
@@ -656,14 +672,14 @@ class BuildArguments(FindBuildArguments):
|
|
|
656
672
|
),
|
|
657
673
|
description='Path to the files containing the patterns to ignore the warnings in the build output',
|
|
658
674
|
validation_alias=AliasChoices('ignore_warning_files', 'ignore_warning_file'),
|
|
659
|
-
default=None,
|
|
675
|
+
default=None, # type: ignore
|
|
660
676
|
)
|
|
661
677
|
copy_sdkconfig: bool = field(
|
|
662
678
|
FieldMetadata(
|
|
663
679
|
action='store_true',
|
|
664
680
|
),
|
|
665
681
|
description='Copy the sdkconfig file to the build directory',
|
|
666
|
-
default=False,
|
|
682
|
+
default=False, # type: ignore
|
|
667
683
|
)
|
|
668
684
|
|
|
669
685
|
# Attrs that support placeholders
|
|
@@ -675,7 +691,7 @@ class BuildArguments(FindBuildArguments):
|
|
|
675
691
|
description='Record size json filepath of the built apps to the specified file. '
|
|
676
692
|
'Each line is a json string. Can expand placeholders @p',
|
|
677
693
|
validation_alias=AliasChoices('collect_size_info_filename', 'collect_size_info'),
|
|
678
|
-
default=None,
|
|
694
|
+
default=None, # type: ignore
|
|
679
695
|
exclude=True, # computed field is used
|
|
680
696
|
)
|
|
681
697
|
collect_app_info_filename: t.Optional[str] = field(
|
|
@@ -686,7 +702,7 @@ class BuildArguments(FindBuildArguments):
|
|
|
686
702
|
description='Record serialized app model of the built apps to the specified file. '
|
|
687
703
|
'Each line is a json string. Can expand placeholders @p',
|
|
688
704
|
validation_alias=AliasChoices('collect_app_info_filename', 'collect_app_info'),
|
|
689
|
-
default=None,
|
|
705
|
+
default=None, # type: ignore
|
|
690
706
|
exclude=True, # computed field is used
|
|
691
707
|
)
|
|
692
708
|
junitxml_filename: t.Optional[str] = field(
|
|
@@ -696,7 +712,7 @@ class BuildArguments(FindBuildArguments):
|
|
|
696
712
|
),
|
|
697
713
|
description='Path to the junitxml file to record the build results. Can expand placeholder @p',
|
|
698
714
|
validation_alias=AliasChoices('junitxml_filename', 'junitxml'),
|
|
699
|
-
default=None,
|
|
715
|
+
default=None, # type: ignore
|
|
700
716
|
exclude=True, # computed field is used
|
|
701
717
|
)
|
|
702
718
|
# used for expanding placeholders
|
|
@@ -753,7 +769,7 @@ class DumpManifestShaArguments(GlobalArguments):
|
|
|
753
769
|
required=True,
|
|
754
770
|
),
|
|
755
771
|
description='Path to the manifest files which contains the build test rules of the apps',
|
|
756
|
-
default=None,
|
|
772
|
+
default=None, # type: ignore
|
|
757
773
|
)
|
|
758
774
|
|
|
759
775
|
output: t.Optional[str] = field(
|
|
@@ -762,7 +778,7 @@ class DumpManifestShaArguments(GlobalArguments):
|
|
|
762
778
|
required=True,
|
|
763
779
|
),
|
|
764
780
|
description='Path to the output file to record the sha256 hash of the manifest rules',
|
|
765
|
-
default=None,
|
|
781
|
+
default=None, # type: ignore
|
|
766
782
|
)
|
|
767
783
|
|
|
768
784
|
def model_post_init(self, __context: Any) -> None:
|
|
@@ -863,12 +879,20 @@ def add_args_to_obj_doc_as_params(argument_cls: t.Type[GlobalArguments], obj: t.
|
|
|
863
879
|
_obj.__doc__ = _doc_str
|
|
864
880
|
|
|
865
881
|
|
|
866
|
-
def apply_config_file(config_file: t.Optional[str]) -> None:
|
|
882
|
+
def apply_config_file(config_file: t.Optional[str] = None, reset: bool = False) -> None:
|
|
867
883
|
def _subclasses(klass: t.Type[T]) -> t.Set[t.Type[T]]:
|
|
868
884
|
return set(klass.__subclasses__()).union([s for c in klass.__subclasses__() for s in _subclasses(c)])
|
|
869
885
|
|
|
870
|
-
if
|
|
871
|
-
BaseArguments.
|
|
872
|
-
# modify all subclasses
|
|
886
|
+
if reset:
|
|
887
|
+
BaseArguments.CONFIG_FILE_PATH = None
|
|
873
888
|
for cls in _subclasses(BaseArguments):
|
|
874
|
-
cls.
|
|
889
|
+
cls.CONFIG_FILE_PATH = None
|
|
890
|
+
|
|
891
|
+
if config_file:
|
|
892
|
+
if os.path.isfile(config_file):
|
|
893
|
+
p = Path(config_file)
|
|
894
|
+
BaseArguments.CONFIG_FILE_PATH = p
|
|
895
|
+
for cls in _subclasses(BaseArguments):
|
|
896
|
+
cls.CONFIG_FILE_PATH = p
|
|
897
|
+
else:
|
|
898
|
+
LOGGER.warning(f'Config file {config_file} does not exist. Ignoring...')
|
idf_build_apps/constants.py
CHANGED
|
@@ -1,70 +1,25 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2022-
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import enum
|
|
5
|
-
import importlib
|
|
6
|
-
import logging
|
|
7
5
|
import os
|
|
8
|
-
import re
|
|
9
|
-
import sys
|
|
10
|
-
import typing as t
|
|
11
6
|
|
|
12
|
-
|
|
13
|
-
to_version,
|
|
14
|
-
)
|
|
7
|
+
import esp_bool_parser
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
_idf_env = os.getenv('IDF_PATH') or ''
|
|
19
|
-
if not _idf_env:
|
|
20
|
-
LOGGER.warning('IDF_PATH environment variable is not set. Entering test mode...')
|
|
21
|
-
LOGGER.warning('- Setting IDF_PATH to current directory...')
|
|
22
|
-
IDF_PATH = os.path.abspath(_idf_env)
|
|
9
|
+
IDF_PATH = esp_bool_parser.IDF_PATH
|
|
23
10
|
IDF_PY = os.path.join(IDF_PATH, 'tools', 'idf.py')
|
|
24
11
|
IDF_SIZE_PY = os.path.join(IDF_PATH, 'tools', 'idf_size.py')
|
|
12
|
+
|
|
25
13
|
PROJECT_DESCRIPTION_JSON = 'project_description.json'
|
|
26
14
|
DEFAULT_SDKCONFIG = 'sdkconfig.defaults'
|
|
27
15
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
'- Set supported/preview targets to empty list... (ESP-IDF constants.py module not found under %s)',
|
|
36
|
-
_idf_py_actions,
|
|
37
|
-
)
|
|
38
|
-
_idf_py_constant_py = object() # type: ignore
|
|
39
|
-
SUPPORTED_TARGETS = getattr(_idf_py_constant_py, 'SUPPORTED_TARGETS', [])
|
|
40
|
-
PREVIEW_TARGETS = getattr(_idf_py_constant_py, 'PREVIEW_TARGETS', [])
|
|
41
|
-
ALL_TARGETS = SUPPORTED_TARGETS + PREVIEW_TARGETS
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def _idf_version_from_cmake() -> t.Tuple[int, int, int]:
|
|
45
|
-
version_path = os.path.join(IDF_PATH, 'tools', 'cmake', 'version.cmake')
|
|
46
|
-
if not os.path.isfile(version_path):
|
|
47
|
-
LOGGER.warning('- Setting ESP-IDF version to 1.0.0... (ESP-IDF version.cmake not exists at %s)', version_path)
|
|
48
|
-
return 1, 0, 0
|
|
49
|
-
|
|
50
|
-
regex = re.compile(r'^\s*set\s*\(\s*IDF_VERSION_([A-Z]{5})\s+(\d+)')
|
|
51
|
-
ver = {}
|
|
52
|
-
try:
|
|
53
|
-
with open(version_path) as f:
|
|
54
|
-
for line in f:
|
|
55
|
-
m = regex.match(line)
|
|
56
|
-
|
|
57
|
-
if m:
|
|
58
|
-
ver[m.group(1)] = m.group(2)
|
|
59
|
-
|
|
60
|
-
return int(ver['MAJOR']), int(ver['MINOR']), int(ver['PATCH'])
|
|
61
|
-
except (KeyError, OSError):
|
|
62
|
-
raise ValueError(f'Cannot find ESP-IDF version in {version_path}')
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
IDF_VERSION_MAJOR, IDF_VERSION_MINOR, IDF_VERSION_PATCH = _idf_version_from_cmake()
|
|
66
|
-
|
|
67
|
-
IDF_VERSION = to_version(f'{IDF_VERSION_MAJOR}.{IDF_VERSION_MINOR}.{IDF_VERSION_PATCH}')
|
|
16
|
+
SUPPORTED_TARGETS = esp_bool_parser.SUPPORTED_TARGETS
|
|
17
|
+
PREVIEW_TARGETS = esp_bool_parser.PREVIEW_TARGETS
|
|
18
|
+
ALL_TARGETS = esp_bool_parser.ALL_TARGETS
|
|
19
|
+
IDF_VERSION_MAJOR = esp_bool_parser.IDF_VERSION_MAJOR
|
|
20
|
+
IDF_VERSION_MINOR = esp_bool_parser.IDF_VERSION_MINOR
|
|
21
|
+
IDF_VERSION_PATCH = esp_bool_parser.IDF_VERSION_PATCH
|
|
22
|
+
IDF_VERSION = esp_bool_parser.IDF_VERSION
|
|
68
23
|
|
|
69
24
|
|
|
70
25
|
class BuildStatus(str, enum.Enum):
|
idf_build_apps/finder.py
CHANGED
|
@@ -50,6 +50,7 @@ def _get_apps_from_path(
|
|
|
50
50
|
|
|
51
51
|
# for unknown ones, we keep them to the build stage to judge
|
|
52
52
|
if _app.build_status == BuildStatus.SKIPPED:
|
|
53
|
+
LOGGER.debug('=> Skipped. Reason: %s', _app.build_comment or 'Unknown')
|
|
53
54
|
return args.include_skipped_apps
|
|
54
55
|
|
|
55
56
|
return True
|
idf_build_apps/junit/utils.py
CHANGED
idf_build_apps/main.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# PYTHON_ARGCOMPLETE_OK
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: 2022-
|
|
3
|
+
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
|
4
4
|
# SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
|
|
6
6
|
import argparse
|
|
@@ -68,7 +68,8 @@ def find_apps(
|
|
|
68
68
|
|
|
69
69
|
:return: list of found apps
|
|
70
70
|
"""
|
|
71
|
-
|
|
71
|
+
if config_file:
|
|
72
|
+
apply_config_file(config_file)
|
|
72
73
|
|
|
73
74
|
# compatible with old usage
|
|
74
75
|
## `preserve`
|
|
@@ -132,7 +133,8 @@ def build_apps(
|
|
|
132
133
|
|
|
133
134
|
:return: exit code
|
|
134
135
|
"""
|
|
135
|
-
|
|
136
|
+
if config_file:
|
|
137
|
+
apply_config_file(config_file)
|
|
136
138
|
|
|
137
139
|
# compatible with old usage
|
|
138
140
|
## `check_app_dependencies`
|
|
@@ -385,8 +387,8 @@ def main():
|
|
|
385
387
|
kwargs = vars(args)
|
|
386
388
|
action = kwargs.pop('action')
|
|
387
389
|
config_file = kwargs.pop('config_file')
|
|
388
|
-
|
|
389
|
-
|
|
390
|
+
if config_file:
|
|
391
|
+
apply_config_file(config_file)
|
|
390
392
|
|
|
391
393
|
if action == 'dump-manifest-sha':
|
|
392
394
|
arguments = DumpManifestShaArguments(**drop_none_kwargs(kwargs))
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2022-
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
"""
|
|
5
5
|
Manifest file
|
|
6
6
|
"""
|
|
7
|
+
|
|
8
|
+
from esp_bool_parser import register_addition_attribute
|
|
9
|
+
|
|
10
|
+
from .manifest import FolderRule
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def folder_rule_attr(target, **kwargs):
|
|
14
|
+
return 1 if target in FolderRule.DEFAULT_BUILD_TARGETS else 0
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
register_addition_attribute('INCLUDE_DEFAULT', folder_rule_attr)
|