idf-build-apps 2.0.0rc0__py3-none-any.whl → 2.0.0rc1__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 +4 -3
- idf_build_apps/app.py +81 -69
- idf_build_apps/constants.py +3 -3
- idf_build_apps/main.py +42 -3
- idf_build_apps/manifest/manifest.py +11 -9
- idf_build_apps/session_args.py +17 -9
- idf_build_apps/utils.py +43 -14
- {idf_build_apps-2.0.0rc0.dist-info → idf_build_apps-2.0.0rc1.dist-info}/METADATA +1 -1
- {idf_build_apps-2.0.0rc0.dist-info → idf_build_apps-2.0.0rc1.dist-info}/RECORD +12 -12
- {idf_build_apps-2.0.0rc0.dist-info → idf_build_apps-2.0.0rc1.dist-info}/LICENSE +0 -0
- {idf_build_apps-2.0.0rc0.dist-info → idf_build_apps-2.0.0rc1.dist-info}/WHEEL +0 -0
- {idf_build_apps-2.0.0rc0.dist-info → idf_build_apps-2.0.0rc1.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-2024 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.0.
|
|
11
|
+
__version__ = '2.0.0rc1'
|
|
12
12
|
|
|
13
13
|
from .session_args import (
|
|
14
14
|
SessionArgs,
|
|
@@ -28,6 +28,7 @@ from .log import (
|
|
|
28
28
|
from .main import (
|
|
29
29
|
build_apps,
|
|
30
30
|
find_apps,
|
|
31
|
+
json_to_app,
|
|
31
32
|
)
|
|
32
33
|
|
|
33
34
|
__all__ = [
|
|
@@ -37,6 +38,6 @@ __all__ = [
|
|
|
37
38
|
'MakeApp',
|
|
38
39
|
'find_apps',
|
|
39
40
|
'build_apps',
|
|
41
|
+
'json_to_app',
|
|
40
42
|
'setup_logging',
|
|
41
|
-
'SESSION_ARGS',
|
|
42
43
|
]
|
idf_build_apps/app.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2022-
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import functools
|
|
@@ -8,11 +8,7 @@ import os
|
|
|
8
8
|
import re
|
|
9
9
|
import shutil
|
|
10
10
|
import sys
|
|
11
|
-
import tempfile
|
|
12
11
|
import typing as t
|
|
13
|
-
from copy import (
|
|
14
|
-
deepcopy,
|
|
15
|
-
)
|
|
16
12
|
from datetime import (
|
|
17
13
|
datetime,
|
|
18
14
|
)
|
|
@@ -28,10 +24,9 @@ from pydantic import (
|
|
|
28
24
|
computed_field,
|
|
29
25
|
)
|
|
30
26
|
|
|
31
|
-
from
|
|
27
|
+
from . import (
|
|
32
28
|
SESSION_ARGS,
|
|
33
29
|
)
|
|
34
|
-
|
|
35
30
|
from .build_apps_args import (
|
|
36
31
|
BuildAppsArgs,
|
|
37
32
|
)
|
|
@@ -132,12 +127,16 @@ class App(BaseModel):
|
|
|
132
127
|
|
|
133
128
|
# build status related
|
|
134
129
|
build_status: BuildStatus = BuildStatus.UNKNOWN
|
|
130
|
+
build_comment: t.Optional[str] = None
|
|
135
131
|
|
|
136
|
-
_build_comment: t.Optional[str] = None
|
|
137
132
|
_build_stage: t.Optional[BuildStage] = None
|
|
138
133
|
_build_duration: float = 0
|
|
139
134
|
_build_timestamp: t.Optional[datetime] = None
|
|
140
135
|
|
|
136
|
+
__EQ_IGNORE_FIELDS__ = [
|
|
137
|
+
'build_comment',
|
|
138
|
+
]
|
|
139
|
+
|
|
141
140
|
def __init__(
|
|
142
141
|
self,
|
|
143
142
|
app_dir: str,
|
|
@@ -164,6 +163,7 @@ class App(BaseModel):
|
|
|
164
163
|
|
|
165
164
|
self._build_log_filename = build_log_filename
|
|
166
165
|
self._size_json_filename = size_json_filename
|
|
166
|
+
self._is_build_log_path_temp = not bool(build_log_filename)
|
|
167
167
|
|
|
168
168
|
# pass all parameters to initialize hook method
|
|
169
169
|
kwargs.update(
|
|
@@ -297,25 +297,18 @@ class App(BaseModel):
|
|
|
297
297
|
|
|
298
298
|
return os.path.join(self.work_dir, self.build_dir)
|
|
299
299
|
|
|
300
|
-
@property
|
|
301
|
-
def build_comment(self) -> str:
|
|
302
|
-
return self._build_comment or ''
|
|
303
|
-
|
|
304
|
-
@build_comment.setter
|
|
305
|
-
def build_comment(self, value: str) -> None:
|
|
306
|
-
self._build_comment = value
|
|
307
|
-
|
|
308
300
|
@computed_field # type: ignore
|
|
309
301
|
@property
|
|
310
302
|
def build_log_filename(self) -> t.Optional[str]:
|
|
311
303
|
return self._expand(self._build_log_filename)
|
|
312
304
|
|
|
313
305
|
@property
|
|
314
|
-
def build_log_path(self) ->
|
|
306
|
+
def build_log_path(self) -> str:
|
|
315
307
|
if self.build_log_filename:
|
|
316
308
|
return os.path.join(self.build_path, self.build_log_filename)
|
|
317
309
|
|
|
318
|
-
|
|
310
|
+
# use a temp file if build log path is not specified
|
|
311
|
+
return os.path.join(self.build_path, f'.temp.build.{hash(self)}.log')
|
|
319
312
|
|
|
320
313
|
@computed_field # type: ignore
|
|
321
314
|
@property
|
|
@@ -340,17 +333,21 @@ class App(BaseModel):
|
|
|
340
333
|
real_sdkconfig_files: t.List[str] = []
|
|
341
334
|
sdkconfig_files_defined_target: t.Optional[str] = None
|
|
342
335
|
|
|
336
|
+
# put the expanded variable files in a temporary directory
|
|
337
|
+
# will remove if the content is the same as the original one
|
|
343
338
|
expanded_dir = os.path.join(self.work_dir, 'expanded_sdkconfig_files', os.path.basename(self.build_dir))
|
|
344
339
|
if not os.path.isdir(expanded_dir):
|
|
345
340
|
os.makedirs(expanded_dir)
|
|
346
341
|
|
|
347
342
|
for f in self.sdkconfig_defaults_candidates + ([self.sdkconfig_path] if self.sdkconfig_path else []):
|
|
348
|
-
if
|
|
349
|
-
f = os.path.join(self.work_dir, f)
|
|
350
|
-
|
|
343
|
+
# use filepath if abs/rel already point to itself
|
|
351
344
|
if not os.path.isfile(f):
|
|
352
|
-
|
|
353
|
-
|
|
345
|
+
# find it in the app_dir
|
|
346
|
+
self._logger.debug('sdkconfig file %s not found, checking under app_dir...', f)
|
|
347
|
+
f = os.path.join(self.app_dir, f)
|
|
348
|
+
if not os.path.isfile(f):
|
|
349
|
+
self._logger.debug('sdkconfig file %s not found, skipping...', f)
|
|
350
|
+
continue
|
|
354
351
|
|
|
355
352
|
expanded_fp = os.path.join(expanded_dir, os.path.basename(f))
|
|
356
353
|
with open(f) as fr:
|
|
@@ -469,14 +466,7 @@ class App(BaseModel):
|
|
|
469
466
|
|
|
470
467
|
return wrapper
|
|
471
468
|
|
|
472
|
-
|
|
473
|
-
def build(
|
|
474
|
-
self,
|
|
475
|
-
manifest_rootpath: t.Optional[str] = None,
|
|
476
|
-
modified_components: t.Union[t.List[str], str, None] = None,
|
|
477
|
-
modified_files: t.Union[t.List[str], str, None] = None,
|
|
478
|
-
check_app_dependencies: bool = False,
|
|
479
|
-
) -> None:
|
|
469
|
+
def _pre_build(self) -> None:
|
|
480
470
|
if self.dry_run:
|
|
481
471
|
self._build_stage = BuildStage.DRY_RUN
|
|
482
472
|
else:
|
|
@@ -518,26 +508,32 @@ class App(BaseModel):
|
|
|
518
508
|
if not self.dry_run:
|
|
519
509
|
os.unlink(sdkconfig_file)
|
|
520
510
|
|
|
521
|
-
if self.build_log_path:
|
|
522
|
-
self._logger.
|
|
511
|
+
if os.path.isfile(self.build_log_path):
|
|
512
|
+
self._logger.debug('Removed existing build log file: %s', self.build_log_path)
|
|
513
|
+
if not self.dry_run:
|
|
514
|
+
os.unlink(self.build_log_path)
|
|
515
|
+
elif not self.dry_run:
|
|
516
|
+
os.makedirs(os.path.dirname(self.build_log_path), exist_ok=True)
|
|
517
|
+
self._logger.info('Writing build log to %s', self.build_log_path)
|
|
523
518
|
|
|
524
519
|
if self.dry_run:
|
|
525
520
|
self.build_status = BuildStatus.SKIPPED
|
|
526
521
|
self.build_comment = 'dry run'
|
|
527
522
|
return
|
|
528
523
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
524
|
+
@record_build_duration # type: ignore
|
|
525
|
+
def build(
|
|
526
|
+
self,
|
|
527
|
+
*,
|
|
528
|
+
manifest_rootpath: t.Optional[str] = None,
|
|
529
|
+
modified_components: t.Union[t.List[str], str, None] = None,
|
|
530
|
+
modified_files: t.Union[t.List[str], str, None] = None,
|
|
531
|
+
check_app_dependencies: bool = False,
|
|
532
|
+
) -> None:
|
|
533
|
+
self._pre_build()
|
|
536
534
|
|
|
537
|
-
self._build_stage = BuildStage.BUILD
|
|
538
535
|
try:
|
|
539
536
|
self._build(
|
|
540
|
-
logfile=logfile,
|
|
541
537
|
manifest_rootpath=manifest_rootpath,
|
|
542
538
|
modified_components=to_list(modified_components),
|
|
543
539
|
modified_files=to_list(modified_files),
|
|
@@ -546,12 +542,17 @@ class App(BaseModel):
|
|
|
546
542
|
except BuildError as e:
|
|
547
543
|
self.build_status = BuildStatus.FAILED
|
|
548
544
|
self.build_comment = str(e)
|
|
549
|
-
finally:
|
|
550
|
-
logfile.close()
|
|
551
545
|
|
|
546
|
+
self._post_build()
|
|
547
|
+
|
|
548
|
+
def _post_build(self) -> None:
|
|
552
549
|
self._build_stage = BuildStage.POST_BUILD
|
|
550
|
+
|
|
551
|
+
if not os.path.isfile(self.build_log_path):
|
|
552
|
+
return
|
|
553
|
+
|
|
553
554
|
has_unignored_warning = False
|
|
554
|
-
with open(
|
|
555
|
+
with open(self.build_log_path) as fr:
|
|
555
556
|
lines = [line.rstrip() for line in fr.readlines() if line.rstrip()]
|
|
556
557
|
for line in lines:
|
|
557
558
|
is_error_or_warning, ignored = self.is_error_or_warning(line)
|
|
@@ -567,15 +568,14 @@ class App(BaseModel):
|
|
|
567
568
|
self._logger.error(
|
|
568
569
|
'Last %s lines from the build log "%s":',
|
|
569
570
|
self.LOG_DEBUG_LINES,
|
|
570
|
-
|
|
571
|
+
self.build_log_path,
|
|
571
572
|
)
|
|
572
573
|
for line in lines[-self.LOG_DEBUG_LINES :]:
|
|
573
574
|
self._logger.error('%s', line)
|
|
574
575
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
self._logger.debug('Removed temporary build log file: %s', logfile.name)
|
|
576
|
+
if self._is_build_log_path_temp and self.build_status == BuildStatus.SUCCESS:
|
|
577
|
+
os.unlink(self.build_log_path)
|
|
578
|
+
self._logger.debug('Removed success build temporary log file: %s', self.build_log_path)
|
|
579
579
|
|
|
580
580
|
# Generate Size Files
|
|
581
581
|
if self.build_status == BuildStatus.SUCCESS:
|
|
@@ -586,8 +586,7 @@ class App(BaseModel):
|
|
|
586
586
|
exclude_list = []
|
|
587
587
|
if self.size_json_path:
|
|
588
588
|
exclude_list.append(os.path.basename(self.size_json_path))
|
|
589
|
-
|
|
590
|
-
exclude_list.append(os.path.basename(self.build_log_path))
|
|
589
|
+
exclude_list.append(os.path.basename(self.build_log_path))
|
|
591
590
|
|
|
592
591
|
rmdir(
|
|
593
592
|
self.build_path,
|
|
@@ -604,13 +603,13 @@ class App(BaseModel):
|
|
|
604
603
|
|
|
605
604
|
def _build(
|
|
606
605
|
self,
|
|
607
|
-
|
|
606
|
+
*,
|
|
608
607
|
manifest_rootpath: t.Optional[str] = None,
|
|
609
608
|
modified_components: t.Optional[t.List[str]] = None,
|
|
610
609
|
modified_files: t.Optional[t.List[str]] = None,
|
|
611
610
|
check_app_dependencies: bool = False,
|
|
612
611
|
) -> None:
|
|
613
|
-
|
|
612
|
+
self._build_stage = BuildStage.BUILD
|
|
614
613
|
|
|
615
614
|
def _write_size_json(self) -> None:
|
|
616
615
|
if not self.size_json_path:
|
|
@@ -779,12 +778,19 @@ class MakeApp(App):
|
|
|
779
778
|
|
|
780
779
|
def _build(
|
|
781
780
|
self,
|
|
782
|
-
|
|
781
|
+
*,
|
|
783
782
|
manifest_rootpath: t.Optional[str] = None,
|
|
784
783
|
modified_components: t.Optional[t.List[str]] = None,
|
|
785
784
|
modified_files: t.Optional[t.List[str]] = None,
|
|
786
785
|
check_app_dependencies: bool = False,
|
|
787
786
|
) -> None:
|
|
787
|
+
super()._build(
|
|
788
|
+
manifest_rootpath=manifest_rootpath,
|
|
789
|
+
modified_components=modified_components,
|
|
790
|
+
modified_files=modified_files,
|
|
791
|
+
check_app_dependencies=check_app_dependencies,
|
|
792
|
+
)
|
|
793
|
+
|
|
788
794
|
# additional env variables
|
|
789
795
|
additional_env_dict = {
|
|
790
796
|
'IDF_TARGET': self.target,
|
|
@@ -801,8 +807,8 @@ class MakeApp(App):
|
|
|
801
807
|
for cmd in commands:
|
|
802
808
|
subprocess_run(
|
|
803
809
|
cmd,
|
|
804
|
-
log_terminal=
|
|
805
|
-
log_fs=
|
|
810
|
+
log_terminal=self._is_build_log_path_temp,
|
|
811
|
+
log_fs=self.build_log_path,
|
|
806
812
|
check=True,
|
|
807
813
|
additional_env_dict=additional_env_dict,
|
|
808
814
|
cwd=self.work_dir,
|
|
@@ -846,12 +852,19 @@ class CMakeApp(App):
|
|
|
846
852
|
|
|
847
853
|
def _build(
|
|
848
854
|
self,
|
|
849
|
-
|
|
855
|
+
*,
|
|
850
856
|
manifest_rootpath: t.Optional[str] = None,
|
|
851
857
|
modified_components: t.Optional[t.List[str]] = None,
|
|
852
858
|
modified_files: t.Optional[t.List[str]] = None,
|
|
853
859
|
check_app_dependencies: bool = False,
|
|
854
860
|
) -> None:
|
|
861
|
+
super()._build(
|
|
862
|
+
manifest_rootpath=manifest_rootpath,
|
|
863
|
+
modified_components=modified_components,
|
|
864
|
+
modified_files=modified_files,
|
|
865
|
+
check_app_dependencies=check_app_dependencies,
|
|
866
|
+
)
|
|
867
|
+
|
|
855
868
|
if not self._checked_should_build:
|
|
856
869
|
self._check_should_build(
|
|
857
870
|
manifest_rootpath=manifest_rootpath,
|
|
@@ -883,8 +896,8 @@ class CMakeApp(App):
|
|
|
883
896
|
if modified_components is not None and check_app_dependencies and self.build_status == BuildStatus.UNKNOWN:
|
|
884
897
|
subprocess_run(
|
|
885
898
|
common_args + ['reconfigure'],
|
|
886
|
-
log_terminal=
|
|
887
|
-
log_fs=
|
|
899
|
+
log_terminal=self._is_build_log_path_temp,
|
|
900
|
+
log_fs=self.build_log_path,
|
|
888
901
|
check=True,
|
|
889
902
|
additional_env_dict=additional_env_dict,
|
|
890
903
|
)
|
|
@@ -905,23 +918,22 @@ class CMakeApp(App):
|
|
|
905
918
|
return
|
|
906
919
|
|
|
907
920
|
# idf.py build
|
|
908
|
-
build_args = deepcopy(common_args)
|
|
909
921
|
if self.cmake_vars:
|
|
910
922
|
for key, val in self.cmake_vars.items():
|
|
911
|
-
|
|
923
|
+
common_args.append(f'-D{key}={val}')
|
|
912
924
|
if 'TEST_EXCLUDE_COMPONENTS' in self.cmake_vars and 'TEST_COMPONENTS' not in self.cmake_vars:
|
|
913
|
-
|
|
925
|
+
common_args.append('-DTESTS_ALL=1')
|
|
914
926
|
if 'CONFIG_APP_BUILD_BOOTLOADER' in self.cmake_vars:
|
|
915
927
|
# In case if secure_boot is enabled then for bootloader build need to add `bootloader` cmd
|
|
916
|
-
|
|
917
|
-
|
|
928
|
+
common_args.append('bootloader')
|
|
929
|
+
common_args.append('build')
|
|
918
930
|
if self.verbose:
|
|
919
|
-
|
|
931
|
+
common_args.append('-v')
|
|
920
932
|
|
|
921
933
|
subprocess_run(
|
|
922
|
-
|
|
923
|
-
log_terminal=
|
|
924
|
-
log_fs=
|
|
934
|
+
common_args,
|
|
935
|
+
log_terminal=self._is_build_log_path_temp,
|
|
936
|
+
log_fs=self.build_log_path,
|
|
925
937
|
check=True,
|
|
926
938
|
additional_env_dict=additional_env_dict,
|
|
927
939
|
)
|
idf_build_apps/constants.py
CHANGED
|
@@ -24,9 +24,9 @@ if _BUILDING_DOCS:
|
|
|
24
24
|
if _BUILDING_DOCS:
|
|
25
25
|
_idf_env = tempfile.gettempdir()
|
|
26
26
|
else:
|
|
27
|
-
_idf_env = os.getenv('IDF_PATH'
|
|
28
|
-
if not
|
|
29
|
-
|
|
27
|
+
_idf_env = os.getenv('IDF_PATH') or ''
|
|
28
|
+
if not _idf_env:
|
|
29
|
+
raise SystemExit('environment variable IDF_PATH must be set')
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
IDF_PATH = os.path.abspath(_idf_env)
|
idf_build_apps/main.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2022-
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import argparse
|
|
@@ -11,11 +11,17 @@ import sys
|
|
|
11
11
|
import textwrap
|
|
12
12
|
import typing as t
|
|
13
13
|
|
|
14
|
+
from pydantic import (
|
|
15
|
+
Field,
|
|
16
|
+
create_model,
|
|
17
|
+
)
|
|
18
|
+
|
|
14
19
|
from . import (
|
|
15
20
|
SESSION_ARGS,
|
|
16
21
|
)
|
|
17
22
|
from .app import (
|
|
18
23
|
App,
|
|
24
|
+
AppDeserializer,
|
|
19
25
|
CMakeApp,
|
|
20
26
|
MakeApp,
|
|
21
27
|
)
|
|
@@ -293,7 +299,6 @@ def build_apps(
|
|
|
293
299
|
if f and os.path.isfile(f):
|
|
294
300
|
os.remove(f)
|
|
295
301
|
LOGGER.debug('Remove existing collect file %s', f)
|
|
296
|
-
os.mknod(f)
|
|
297
302
|
|
|
298
303
|
exit_code = 0
|
|
299
304
|
for i, app in enumerate(apps):
|
|
@@ -742,7 +747,7 @@ def main():
|
|
|
742
747
|
os.makedirs(os.path.dirname(os.path.realpath(args.output)), exist_ok=True)
|
|
743
748
|
with open(args.output, 'w') as fw:
|
|
744
749
|
for app in apps:
|
|
745
|
-
fw.write(app.
|
|
750
|
+
fw.write(app.to_json() + '\n')
|
|
746
751
|
else:
|
|
747
752
|
for app in apps:
|
|
748
753
|
print(app)
|
|
@@ -791,3 +796,37 @@ def main():
|
|
|
791
796
|
print(f' {app}')
|
|
792
797
|
|
|
793
798
|
sys.exit(res)
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
def json_to_app(json_str: str, extra_classes: t.Optional[t.List[t.Type[App]]] = None) -> App:
|
|
802
|
+
"""
|
|
803
|
+
Deserialize json string to App object
|
|
804
|
+
|
|
805
|
+
.. note::
|
|
806
|
+
|
|
807
|
+
You can pass extra_cls to support custom App class. A custom App class must be a subclass of App, and have a
|
|
808
|
+
different value of `build_system`. For example, a custom CMake app
|
|
809
|
+
|
|
810
|
+
>>> class CustomApp(CMakeApp):
|
|
811
|
+
>>> build_system: Literal['custom_cmake'] = 'custom_cmake'
|
|
812
|
+
|
|
813
|
+
Then you can pass the CustomApp class to the `extra_cls` argument
|
|
814
|
+
|
|
815
|
+
>>> json_str = CustomApp('.', 'esp32').to_json()
|
|
816
|
+
>>> json_to_app(json_str, extra_classes=[CustomApp])
|
|
817
|
+
|
|
818
|
+
:param json_str: json string
|
|
819
|
+
:param extra_classes: extra App class
|
|
820
|
+
:return: App object
|
|
821
|
+
"""
|
|
822
|
+
types = [App, CMakeApp, MakeApp]
|
|
823
|
+
if extra_classes:
|
|
824
|
+
types.extend(extra_classes)
|
|
825
|
+
|
|
826
|
+
custom_deserializer = create_model(
|
|
827
|
+
'_CustomDeserializer',
|
|
828
|
+
app=(t.Union[tuple(types)], Field(discriminator='build_system')),
|
|
829
|
+
__base__=AppDeserializer,
|
|
830
|
+
)
|
|
831
|
+
|
|
832
|
+
return custom_deserializer.from_json(json_str)
|
|
@@ -58,15 +58,17 @@ class FolderRule:
|
|
|
58
58
|
) -> None:
|
|
59
59
|
self.folder = os.path.abspath(folder)
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
self.
|
|
61
|
+
def _clause_to_if_clause(clause: t.Dict[str, t.Any]) -> IfClause:
|
|
62
|
+
_kwargs = {'stmt': clause['if']}
|
|
63
|
+
if 'temporary' in clause:
|
|
64
|
+
_kwargs['temporary'] = clause['temporary']
|
|
65
|
+
if 'reason' in clause:
|
|
66
|
+
_kwargs['reason'] = clause['reason']
|
|
67
|
+
return IfClause(**_kwargs)
|
|
68
|
+
|
|
69
|
+
self.enable = [_clause_to_if_clause(clause) for clause in enable] if enable else []
|
|
70
|
+
self.disable = [_clause_to_if_clause(clause) for clause in disable] if disable else []
|
|
71
|
+
self.disable_test = [_clause_to_if_clause(clause) for clause in disable_test] if disable_test else []
|
|
70
72
|
self.depends_components = depends_components or []
|
|
71
73
|
self.depends_filepatterns = depends_filepatterns or []
|
|
72
74
|
|
idf_build_apps/session_args.py
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
+
import logging
|
|
4
5
|
import os
|
|
5
6
|
import re
|
|
6
7
|
import typing as t
|
|
7
8
|
|
|
9
|
+
LOGGER = logging.getLogger(__name__)
|
|
10
|
+
|
|
8
11
|
|
|
9
12
|
class SessionArgs:
|
|
10
13
|
workdir: str = os.getcwd()
|
|
@@ -35,27 +38,32 @@ class SessionArgs:
|
|
|
35
38
|
self.override_sdkconfig_file_path = override_sdkconfig_merged_file
|
|
36
39
|
|
|
37
40
|
def _get_override_sdkconfig_files_items(self, override_sdkconfig_files: t.Tuple[str]) -> t.Dict:
|
|
38
|
-
|
|
41
|
+
d = {}
|
|
39
42
|
for f in override_sdkconfig_files:
|
|
40
|
-
if
|
|
41
|
-
f = os.path.join(self.workdir, f)
|
|
43
|
+
# use filepath if abs/rel already point to itself
|
|
42
44
|
if not os.path.isfile(f):
|
|
43
|
-
|
|
45
|
+
# find it in the workdir
|
|
46
|
+
LOGGER.debug('override sdkconfig file %s not found, checking under app_dir...', f)
|
|
47
|
+
f = os.path.join(self.workdir, f)
|
|
48
|
+
if not os.path.isfile(f):
|
|
49
|
+
LOGGER.debug('override sdkconfig file %s not found, skipping...', f)
|
|
50
|
+
continue
|
|
51
|
+
|
|
44
52
|
with open(f) as fr:
|
|
45
53
|
for line in fr:
|
|
46
54
|
m = re.compile(r"^([^=]+)=\"?([^\"\n]*)\"?\n*$").match(line)
|
|
47
55
|
if not m:
|
|
48
56
|
continue
|
|
49
|
-
|
|
50
|
-
return
|
|
57
|
+
d[m.group(1)] = m.group(2)
|
|
58
|
+
return d
|
|
51
59
|
|
|
52
60
|
def _get_override_sdkconfig_items(self, override_sdkconfig_items: t.Tuple[str]) -> t.Dict:
|
|
53
|
-
|
|
61
|
+
d = {}
|
|
54
62
|
for line in override_sdkconfig_items:
|
|
55
63
|
m = re.compile(r"^([^=]+)=\"?([^\"\n]*)\"?\n*$").match(line)
|
|
56
64
|
if m:
|
|
57
|
-
|
|
58
|
-
return
|
|
65
|
+
d[m.group(1)] = m.group(2)
|
|
66
|
+
return d
|
|
59
67
|
|
|
60
68
|
def _create_override_sdkconfig_merged_file(self, override_sdkconfig_merged_items) -> t.Optional[str]:
|
|
61
69
|
if not override_sdkconfig_merged_items:
|
idf_build_apps/utils.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2022-
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import fnmatch
|
|
5
|
+
import functools
|
|
5
6
|
import glob
|
|
6
7
|
import logging
|
|
7
8
|
import os
|
|
@@ -134,7 +135,7 @@ def find_first_match(pattern: str, path: str) -> t.Optional[str]:
|
|
|
134
135
|
def subprocess_run(
|
|
135
136
|
cmd: t.List[str],
|
|
136
137
|
log_terminal: bool = True,
|
|
137
|
-
log_fs: t.
|
|
138
|
+
log_fs: t.Union[t.IO[str], str, None] = None,
|
|
138
139
|
check: bool = False,
|
|
139
140
|
additional_env_dict: t.Optional[t.Dict[str, str]] = None,
|
|
140
141
|
**kwargs,
|
|
@@ -157,16 +158,26 @@ def subprocess_run(
|
|
|
157
158
|
subprocess_env.update(additional_env_dict)
|
|
158
159
|
|
|
159
160
|
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=subprocess_env, **kwargs)
|
|
160
|
-
if p.stdout:
|
|
161
|
-
for line in p.stdout:
|
|
162
|
-
if isinstance(line, bytes):
|
|
163
|
-
line = line.decode('utf-8')
|
|
164
161
|
|
|
165
|
-
|
|
166
|
-
|
|
162
|
+
def _log_stdout(fs: t.Optional[t.IO[str]] = None):
|
|
163
|
+
if p.stdout:
|
|
164
|
+
for line in p.stdout:
|
|
165
|
+
if isinstance(line, bytes):
|
|
166
|
+
line = line.decode('utf-8')
|
|
167
|
+
|
|
168
|
+
if log_terminal:
|
|
169
|
+
sys.stdout.write(line)
|
|
170
|
+
|
|
171
|
+
if fs:
|
|
172
|
+
fs.write(line)
|
|
167
173
|
|
|
168
|
-
|
|
169
|
-
|
|
174
|
+
if p.stdout:
|
|
175
|
+
if log_fs:
|
|
176
|
+
if isinstance(log_fs, str):
|
|
177
|
+
with open(log_fs, 'a') as fa:
|
|
178
|
+
_log_stdout(fa)
|
|
179
|
+
else:
|
|
180
|
+
_log_stdout(log_fs)
|
|
170
181
|
|
|
171
182
|
returncode = p.wait()
|
|
172
183
|
if check and returncode != 0:
|
|
@@ -305,25 +316,43 @@ def files_matches_patterns(
|
|
|
305
316
|
return False
|
|
306
317
|
|
|
307
318
|
|
|
319
|
+
@functools.total_ordering
|
|
308
320
|
class BaseModel(_BaseModel):
|
|
309
321
|
"""
|
|
310
322
|
BaseModel that is hashable
|
|
311
323
|
"""
|
|
312
324
|
|
|
325
|
+
__EQ_IGNORE_FIELDS__: t.List[str] = []
|
|
326
|
+
|
|
313
327
|
def __lt__(self, other: t.Any) -> bool:
|
|
314
328
|
if isinstance(other, self.__class__):
|
|
315
329
|
for k in self.model_dump():
|
|
316
|
-
if
|
|
317
|
-
return getattr(self, k) < getattr(other, k)
|
|
318
|
-
else:
|
|
330
|
+
if k in self.__EQ_IGNORE_FIELDS__:
|
|
319
331
|
continue
|
|
320
332
|
|
|
333
|
+
self_attr = getattr(self, k, '') or ''
|
|
334
|
+
other_attr = getattr(other, k, '') or ''
|
|
335
|
+
|
|
336
|
+
if self_attr != other_attr:
|
|
337
|
+
return self_attr < other_attr
|
|
338
|
+
|
|
339
|
+
continue
|
|
340
|
+
|
|
341
|
+
return False
|
|
342
|
+
|
|
321
343
|
return NotImplemented
|
|
322
344
|
|
|
323
345
|
def __eq__(self, other: t.Any) -> bool:
|
|
324
346
|
if isinstance(other, self.__class__):
|
|
325
347
|
# we only care the public attributes
|
|
326
|
-
|
|
348
|
+
self_model_dump = self.model_dump()
|
|
349
|
+
other_model_dump = other.model_dump()
|
|
350
|
+
|
|
351
|
+
for _field in self.__EQ_IGNORE_FIELDS__:
|
|
352
|
+
self_model_dump.pop(_field, None)
|
|
353
|
+
other_model_dump.pop(_field, None)
|
|
354
|
+
|
|
355
|
+
return self_model_dump == other_model_dump
|
|
327
356
|
|
|
328
357
|
return NotImplemented
|
|
329
358
|
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
idf_build_apps/__init__.py,sha256=
|
|
1
|
+
idf_build_apps/__init__.py,sha256=WAwRTUCnGjoWIT8bl_n9qCOk7xmA8JdvjZfnYWNs1Qs,653
|
|
2
2
|
idf_build_apps/__main__.py,sha256=8E-5xHm2MlRun0L88XJleNh5U50dpE0Q1nK5KqomA7I,182
|
|
3
|
-
idf_build_apps/app.py,sha256=
|
|
3
|
+
idf_build_apps/app.py,sha256=KwZ7xrxUs_cVqEaDxtrPE7B4bo-_-RCJAEUX3iHR9A4,34537
|
|
4
4
|
idf_build_apps/build_apps_args.py,sha256=r6VCJDdCzE873X8OTputYkCBZPgECaKoNlAejfcamJk,1644
|
|
5
5
|
idf_build_apps/config.py,sha256=I75uOQGarCWVKGi16ZYpo0qTVU25BUP4eh6-RWCtbvw,2924
|
|
6
|
-
idf_build_apps/constants.py,sha256=
|
|
6
|
+
idf_build_apps/constants.py,sha256=xqclwUpWE5dEByL4kxdg2HaHjbAfkJtxodFfLZuAk8A,2818
|
|
7
7
|
idf_build_apps/finder.py,sha256=qw5moNq7U5mHSsR0CCfGkKE9p4QsWYNcfkxzeQ73HgM,6252
|
|
8
8
|
idf_build_apps/log.py,sha256=4P4q8EqV68iQw0LCoNI6ibBBpAkNgetDxZ0Cgbhp0Bo,2570
|
|
9
|
-
idf_build_apps/main.py,sha256=
|
|
10
|
-
idf_build_apps/session_args.py,sha256=
|
|
11
|
-
idf_build_apps/utils.py,sha256
|
|
9
|
+
idf_build_apps/main.py,sha256=jh2mZFK75OpjEeWzupNk-ZQFCIXFfyoL6-XyKi2hbnk,32896
|
|
10
|
+
idf_build_apps/session_args.py,sha256=LYgibgUGjHm0iAd6gBYcT9rpTCcdKfcblFMysAlv7UE,2996
|
|
11
|
+
idf_build_apps/utils.py,sha256=-o0yyYHAhwVD2ihRupUJdKEu0sAIOaGg4DnIRy6iJNA,9669
|
|
12
12
|
idf_build_apps/junit/__init__.py,sha256=GRyhJfZet00iWxe2PvUAG72CXhnhOZaV4B7Z7txKVAk,226
|
|
13
13
|
idf_build_apps/junit/report.py,sha256=2sBLEL5EnGW6h0ku2W-BOyEFMgQcu0OO-WcFyXH_Aqg,6341
|
|
14
14
|
idf_build_apps/junit/utils.py,sha256=gtibRs8WTE8IXTIAS73QR_k_jrJlOjCl2y-9KiP5_Nk,1304
|
|
15
15
|
idf_build_apps/manifest/__init__.py,sha256=Q2-cb3ngNjnl6_zWhUfzZZB10f_-Rv2JYNck3Lk7UkQ,133
|
|
16
16
|
idf_build_apps/manifest/if_parser.py,sha256=hS3khcDeFsoqfDLdRG931h91SU4bTALACxjcEiiDIBQ,6379
|
|
17
|
-
idf_build_apps/manifest/manifest.py,sha256=
|
|
17
|
+
idf_build_apps/manifest/manifest.py,sha256=oRy3BlR_JXfQ7avJQnAZ8__ZCcuhGM_wnFDqHYCqkIQ,7316
|
|
18
18
|
idf_build_apps/manifest/soc_header.py,sha256=TVT7wxzcxdeIdX8WAtPYr8bFV7EqTWkVo4h18MWsD8Q,4028
|
|
19
|
-
idf_build_apps-2.0.
|
|
20
|
-
idf_build_apps-2.0.
|
|
21
|
-
idf_build_apps-2.0.
|
|
22
|
-
idf_build_apps-2.0.
|
|
23
|
-
idf_build_apps-2.0.
|
|
19
|
+
idf_build_apps-2.0.0rc1.dist-info/entry_points.txt,sha256=3pVUirUEsb6jsDRikkQWNUt4hqLK2ci1HvW_Vf8b6uE,59
|
|
20
|
+
idf_build_apps-2.0.0rc1.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
21
|
+
idf_build_apps-2.0.0rc1.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
|
22
|
+
idf_build_apps-2.0.0rc1.dist-info/METADATA,sha256=EU1KK7_Meebf2ZdJ6mpyB2hS_VJj4HLjXVWri1q0RwU,4453
|
|
23
|
+
idf_build_apps-2.0.0rc1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|