idf-build-apps 2.5.0rc1__py3-none-any.whl → 2.5.0rc2__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 +1 -1
- idf_build_apps/args.py +444 -667
- idf_build_apps/constants.py +1 -0
- idf_build_apps/finder.py +2 -2
- idf_build_apps/main.py +49 -13
- idf_build_apps/manifest/manifest.py +5 -4
- idf_build_apps/utils.py +5 -1
- idf_build_apps/vendors/__init__.py +0 -0
- idf_build_apps/vendors/pydantic_sources.py +120 -0
- idf_build_apps/yaml/parser.py +3 -1
- {idf_build_apps-2.5.0rc1.dist-info → idf_build_apps-2.5.0rc2.dist-info}/METADATA +2 -1
- idf_build_apps-2.5.0rc2.dist-info/RECORD +27 -0
- idf_build_apps/config.py +0 -108
- idf_build_apps-2.5.0rc1.dist-info/RECORD +0 -26
- {idf_build_apps-2.5.0rc1.dist-info → idf_build_apps-2.5.0rc2.dist-info}/LICENSE +0 -0
- {idf_build_apps-2.5.0rc1.dist-info → idf_build_apps-2.5.0rc2.dist-info}/WHEEL +0 -0
- {idf_build_apps-2.5.0rc1.dist-info → idf_build_apps-2.5.0rc2.dist-info}/entry_points.txt +0 -0
idf_build_apps/args.py
CHANGED
|
@@ -1,45 +1,40 @@
|
|
|
1
1
|
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
"""
|
|
4
|
-
Arguments used in the CLI, and functions.
|
|
5
|
-
|
|
6
|
-
The reason that does not use pydantic models, but dataclasses
|
|
7
|
-
|
|
8
|
-
- poor autocomplete in IDE when using pydantic custom Fields with extra metadata
|
|
9
|
-
- pydantic Field alias is nice, but hard to customize, when
|
|
10
|
-
- the deprecated field has a different nargs
|
|
11
|
-
"""
|
|
12
3
|
|
|
13
4
|
import argparse
|
|
5
|
+
import enum
|
|
14
6
|
import inspect
|
|
15
7
|
import logging
|
|
16
8
|
import os
|
|
17
9
|
import re
|
|
10
|
+
import sys
|
|
18
11
|
import typing as t
|
|
19
12
|
from copy import deepcopy
|
|
20
|
-
from dataclasses import
|
|
21
|
-
from
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
from pydantic import AliasChoices, Field, computed_field, field_validator
|
|
18
|
+
from pydantic.fields import FieldInfo
|
|
19
|
+
from pydantic_core.core_schema import ValidationInfo
|
|
20
|
+
from pydantic_settings import (
|
|
21
|
+
BaseSettings,
|
|
22
|
+
PydanticBaseSettingsSource,
|
|
23
|
+
SettingsConfigDict,
|
|
24
|
+
)
|
|
25
|
+
from typing_extensions import Concatenate, ParamSpec
|
|
22
26
|
|
|
23
|
-
from . import SESSION_ARGS, setup_logging
|
|
24
|
-
from .app import App
|
|
25
|
-
from .config import get_valid_config
|
|
27
|
+
from . import SESSION_ARGS, App, setup_logging
|
|
26
28
|
from .constants import ALL_TARGETS
|
|
27
29
|
from .manifest.manifest import FolderRule, Manifest
|
|
28
|
-
from .utils import
|
|
29
|
-
|
|
30
|
-
Self,
|
|
31
|
-
drop_none_kwargs,
|
|
32
|
-
files_matches_patterns,
|
|
33
|
-
semicolon_separated_str_to_list,
|
|
34
|
-
to_absolute_path,
|
|
35
|
-
to_list,
|
|
36
|
-
)
|
|
30
|
+
from .utils import InvalidCommand, files_matches_patterns, semicolon_separated_str_to_list, to_absolute_path, to_list
|
|
31
|
+
from .vendors.pydantic_sources import PyprojectTomlConfigSettingsSource, TomlConfigSettingsSource
|
|
37
32
|
|
|
38
33
|
LOGGER = logging.getLogger(__name__)
|
|
39
34
|
|
|
40
35
|
|
|
41
|
-
class
|
|
42
|
-
|
|
36
|
+
class ValidateMethod(str, enum.Enum):
|
|
37
|
+
TO_LIST = 'to_list'
|
|
43
38
|
|
|
44
39
|
|
|
45
40
|
@dataclass
|
|
@@ -48,7 +43,7 @@ class FieldMetadata:
|
|
|
48
43
|
dataclass field metadata. All fields are optional.
|
|
49
44
|
Some fields are used in argparse while running :func:`add_args_to_parser`.
|
|
50
45
|
|
|
51
|
-
:param
|
|
46
|
+
:param validate_method: validate method for the field
|
|
52
47
|
:param deprecates: deprecates field names, used in argparse
|
|
53
48
|
:param shorthand: shorthand for the argument, used in argparse
|
|
54
49
|
:param action: action for the argument, used in argparse
|
|
@@ -56,10 +51,10 @@ class FieldMetadata:
|
|
|
56
51
|
:param choices: choices for the argument, used in argparse
|
|
57
52
|
:param type: type for the argument, used in argparse
|
|
58
53
|
:param required: whether the argument is required, used in argparse
|
|
59
|
-
:param default: default value, used in argparse
|
|
60
54
|
"""
|
|
61
55
|
|
|
62
|
-
|
|
56
|
+
# validate method
|
|
57
|
+
validate_method: t.Optional[t.List[str]] = None
|
|
63
58
|
# the field description will be copied from the deprecates field if not specified
|
|
64
59
|
deprecates: t.Optional[t.Dict[str, t.Dict[str, t.Any]]] = None
|
|
65
60
|
shorthand: t.Optional[str] = None
|
|
@@ -73,243 +68,200 @@ class FieldMetadata:
|
|
|
73
68
|
default: t.Any = None
|
|
74
69
|
|
|
75
70
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
"""
|
|
79
|
-
Global arguments used in all commands
|
|
80
|
-
"""
|
|
71
|
+
P = ParamSpec('P')
|
|
72
|
+
T = t.TypeVar('T')
|
|
81
73
|
|
|
82
|
-
config_file: t.Optional[str] = field(
|
|
83
|
-
default=None,
|
|
84
|
-
metadata=asdict(
|
|
85
|
-
FieldMetadata(
|
|
86
|
-
description='Path to the configuration file',
|
|
87
|
-
shorthand='-c',
|
|
88
|
-
)
|
|
89
|
-
),
|
|
90
|
-
)
|
|
91
|
-
verbose: int = field(
|
|
92
|
-
default=0,
|
|
93
|
-
metadata=asdict(
|
|
94
|
-
FieldMetadata(
|
|
95
|
-
description='Verbosity level. By default set to WARNING. Specify -v for INFO, -vv for DEBUG',
|
|
96
|
-
shorthand='-v',
|
|
97
|
-
action='count',
|
|
98
|
-
)
|
|
99
|
-
),
|
|
100
|
-
)
|
|
101
|
-
log_file: t.Optional[str] = field(
|
|
102
|
-
default=None,
|
|
103
|
-
metadata=asdict(
|
|
104
|
-
FieldMetadata(
|
|
105
|
-
description='Path to the log file, if not specified logs will be printed to stderr',
|
|
106
|
-
)
|
|
107
|
-
),
|
|
108
|
-
)
|
|
109
|
-
no_color: bool = field(
|
|
110
|
-
default=False,
|
|
111
|
-
metadata=asdict(
|
|
112
|
-
FieldMetadata(
|
|
113
|
-
description='Disable colored output',
|
|
114
|
-
action='store_true',
|
|
115
|
-
)
|
|
116
|
-
),
|
|
117
|
-
)
|
|
118
74
|
|
|
119
|
-
|
|
75
|
+
def _wrap_with_metadata(
|
|
76
|
+
_: t.Callable[P, t.Any],
|
|
77
|
+
) -> t.Callable[[t.Callable[..., T]], t.Callable[Concatenate[t.Optional[FieldMetadata], P], T]]:
|
|
78
|
+
"""Patch the function signature with metadata args"""
|
|
120
79
|
|
|
121
|
-
def
|
|
122
|
-
|
|
123
|
-
_metadata = FieldMetadata(**f.metadata)
|
|
124
|
-
if _metadata.deprecates:
|
|
125
|
-
for depr_name in _metadata.deprecates:
|
|
126
|
-
cls._depr_name_to_new_name_dict[depr_name] = f.name
|
|
80
|
+
def return_func(func: t.Callable[..., T]) -> t.Callable[Concatenate[t.Optional[FieldMetadata], P], T]:
|
|
81
|
+
return t.cast(t.Callable[Concatenate[t.Optional[FieldMetadata], P], T], func)
|
|
127
82
|
|
|
128
|
-
|
|
83
|
+
return return_func
|
|
129
84
|
|
|
130
|
-
@classmethod
|
|
131
|
-
def from_dict(cls, d: t.Dict[str, t.Any]) -> Self:
|
|
132
|
-
"""
|
|
133
|
-
Create an instance from a dictionary. Ignore unknown keys.
|
|
134
85
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
86
|
+
@_wrap_with_metadata(Field)
|
|
87
|
+
def field(meta: t.Optional[FieldMetadata], *args, **kwargs):
|
|
88
|
+
"""field with metadata"""
|
|
89
|
+
f = Field(*args, **kwargs)
|
|
90
|
+
f.metadata.append(meta)
|
|
91
|
+
return f
|
|
139
92
|
|
|
140
|
-
def __post_init__(self):
|
|
141
|
-
self.apply_config()
|
|
142
93
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
"""
|
|
147
|
-
config_dict = get_valid_config(custom_path=self.config_file) or {}
|
|
94
|
+
def get_meta(f: FieldInfo) -> t.Optional[FieldMetadata]:
|
|
95
|
+
"""
|
|
96
|
+
Get the metadata of the field
|
|
148
97
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
98
|
+
:param f: field
|
|
99
|
+
:return: metadata of the field if exists, None otherwise
|
|
100
|
+
"""
|
|
101
|
+
for m in f.metadata:
|
|
102
|
+
if isinstance(m, FieldMetadata):
|
|
103
|
+
return m
|
|
104
|
+
|
|
105
|
+
return None
|
|
154
106
|
|
|
155
|
-
if config_dict:
|
|
156
|
-
for name, value in config_dict.items():
|
|
157
|
-
if hasattr(self, name):
|
|
158
|
-
setattr(self, name, value)
|
|
159
107
|
|
|
160
|
-
|
|
161
|
-
|
|
108
|
+
class BaseArguments(BaseSettings):
|
|
109
|
+
"""Base settings class for all settings classes"""
|
|
162
110
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
111
|
+
model_config = SettingsConfigDict(
|
|
112
|
+
toml_file='.idf_build_apps.toml',
|
|
113
|
+
pyproject_toml_table_header=('tool', 'idf-build-apps'),
|
|
114
|
+
pyproject_toml_depth=sys.maxsize,
|
|
115
|
+
)
|
|
166
116
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
117
|
+
@classmethod
|
|
118
|
+
def settings_customise_sources(
|
|
119
|
+
cls,
|
|
120
|
+
settings_cls: t.Type[BaseSettings],
|
|
121
|
+
init_settings: PydanticBaseSettingsSource,
|
|
122
|
+
env_settings: PydanticBaseSettingsSource, # noqa: ARG003
|
|
123
|
+
dotenv_settings: PydanticBaseSettingsSource, # noqa: ARG003
|
|
124
|
+
file_secret_settings: PydanticBaseSettingsSource, # noqa: ARG003
|
|
125
|
+
) -> t.Tuple[PydanticBaseSettingsSource, ...]:
|
|
126
|
+
return (
|
|
127
|
+
init_settings,
|
|
128
|
+
TomlConfigSettingsSource(settings_cls),
|
|
129
|
+
PyprojectTomlConfigSettingsSource(settings_cls),
|
|
170
130
|
)
|
|
171
|
-
if getattr(self, new_k) is not None:
|
|
172
|
-
LOGGER.warning(f'Field `{new_k}` is already set. Ignoring deprecated field `{depr_k}`')
|
|
173
|
-
return
|
|
174
131
|
|
|
175
|
-
|
|
132
|
+
@field_validator('*', mode='before')
|
|
133
|
+
@classmethod
|
|
134
|
+
def validate_by_validate_methods(cls, v: t.Any, info: ValidationInfo):
|
|
135
|
+
if info.field_name and info.field_name in cls.model_fields:
|
|
136
|
+
f = cls.model_fields[info.field_name]
|
|
137
|
+
meta = get_meta(f)
|
|
138
|
+
if meta and meta.validate_method and ValidateMethod.TO_LIST in meta.validate_method:
|
|
139
|
+
return to_list(v)
|
|
176
140
|
|
|
141
|
+
return v
|
|
177
142
|
|
|
178
|
-
@dataclass
|
|
179
|
-
class DependencyDrivenBuildArguments(GlobalArguments):
|
|
180
|
-
"""
|
|
181
|
-
Arguments used in the dependency-driven build feature.
|
|
182
|
-
"""
|
|
183
143
|
|
|
184
|
-
|
|
185
|
-
|
|
144
|
+
class GlobalArguments(BaseArguments):
|
|
145
|
+
verbose: int = field(
|
|
146
|
+
FieldMetadata(
|
|
147
|
+
shorthand='-v',
|
|
148
|
+
action='count',
|
|
149
|
+
),
|
|
150
|
+
description='Verbosity level. By default set to WARNING. Specify -v for INFO, -vv for DEBUG',
|
|
151
|
+
default=0,
|
|
152
|
+
)
|
|
153
|
+
log_file: t.Optional[str] = field(
|
|
154
|
+
None,
|
|
155
|
+
description='Path to the log file, if not specified logs will be printed to stderr',
|
|
186
156
|
default=None,
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
157
|
+
)
|
|
158
|
+
no_color: bool = field(
|
|
159
|
+
FieldMetadata(
|
|
160
|
+
action='store_true',
|
|
161
|
+
),
|
|
162
|
+
description='Disable colored output',
|
|
163
|
+
default=False,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
def model_post_init(self, __context: Any) -> None:
|
|
167
|
+
super().model_post_init(__context)
|
|
168
|
+
|
|
169
|
+
setup_logging(self.verbose, self.log_file, not self.no_color)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class DependencyDrivenBuildArguments(GlobalArguments):
|
|
173
|
+
manifest_files: t.Optional[t.List[t.Union[Path, str]]] = field(
|
|
174
|
+
FieldMetadata(
|
|
175
|
+
validate_method=[ValidateMethod.TO_LIST],
|
|
176
|
+
deprecates={
|
|
177
|
+
'manifest_file': {
|
|
178
|
+
'nargs': '+',
|
|
193
179
|
},
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
)
|
|
180
|
+
},
|
|
181
|
+
nargs='+',
|
|
197
182
|
),
|
|
183
|
+
description='Path to the manifest files which contains the build test rules of the apps',
|
|
184
|
+
validation_alias=AliasChoices('manifest_files', 'manifest_file'),
|
|
185
|
+
default=None,
|
|
198
186
|
)
|
|
199
187
|
manifest_rootpath: str = field(
|
|
188
|
+
None,
|
|
189
|
+
description='Root path to resolve the relative paths defined in the manifest files. '
|
|
190
|
+
'By default set to the current directory',
|
|
200
191
|
default=os.curdir,
|
|
201
|
-
metadata=asdict(
|
|
202
|
-
FieldMetadata(
|
|
203
|
-
description='Root path to resolve the relative paths defined in the manifest files. '
|
|
204
|
-
'By default set to the current directory',
|
|
205
|
-
)
|
|
206
|
-
),
|
|
207
192
|
)
|
|
208
193
|
modified_components: t.Optional[t.List[str]] = field(
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
description='semicolon-separated list of modified components',
|
|
213
|
-
type=semicolon_separated_str_to_list,
|
|
214
|
-
)
|
|
194
|
+
FieldMetadata(
|
|
195
|
+
validate_method=[ValidateMethod.TO_LIST],
|
|
196
|
+
type=semicolon_separated_str_to_list,
|
|
215
197
|
),
|
|
198
|
+
description='semicolon-separated list of modified components',
|
|
199
|
+
default=None,
|
|
216
200
|
)
|
|
217
201
|
modified_files: t.Optional[t.List[str]] = field(
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
description='semicolon-separated list of modified files',
|
|
222
|
-
type=semicolon_separated_str_to_list,
|
|
223
|
-
)
|
|
202
|
+
FieldMetadata(
|
|
203
|
+
validate_method=[ValidateMethod.TO_LIST],
|
|
204
|
+
type=semicolon_separated_str_to_list,
|
|
224
205
|
),
|
|
206
|
+
description='semicolon-separated list of modified files',
|
|
207
|
+
default=None,
|
|
225
208
|
)
|
|
226
|
-
ignore_app_dependencies_components: InitVar[t.Optional[t.List[str]]] = _Field.UNSET
|
|
227
209
|
deactivate_dependency_driven_build_by_components: t.Optional[t.List[str]] = field(
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
'
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
210
|
+
FieldMetadata(
|
|
211
|
+
validate_method=[ValidateMethod.TO_LIST],
|
|
212
|
+
deprecates={
|
|
213
|
+
'ignore_app_dependencies_components': {
|
|
214
|
+
'type': semicolon_separated_str_to_list,
|
|
215
|
+
'shorthand': '-ic',
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
type=semicolon_separated_str_to_list,
|
|
219
|
+
shorthand='-dc',
|
|
220
|
+
),
|
|
221
|
+
description='semicolon-separated list of components. '
|
|
222
|
+
'dependency-driven build feature will be deactivated when any of these components are modified',
|
|
223
|
+
validation_alias=AliasChoices(
|
|
224
|
+
'deactivate_dependency_driven_build_by_components', 'ignore_app_dependencies_components'
|
|
242
225
|
),
|
|
226
|
+
default=None,
|
|
243
227
|
)
|
|
244
|
-
ignore_app_dependencies_filepatterns: InitVar[t.Optional[t.List[str]]] = _Field.UNSET
|
|
245
228
|
deactivate_dependency_driven_build_by_filepatterns: t.Optional[t.List[str]] = field(
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
'
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
229
|
+
FieldMetadata(
|
|
230
|
+
validate_method=[ValidateMethod.TO_LIST],
|
|
231
|
+
deprecates={
|
|
232
|
+
'ignore_app_dependencies_filepatterns': {
|
|
233
|
+
'type': semicolon_separated_str_to_list,
|
|
234
|
+
'shorthand': '-if',
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
type=semicolon_separated_str_to_list,
|
|
238
|
+
shorthand='-df',
|
|
239
|
+
),
|
|
240
|
+
description='semicolon-separated list of file patterns. '
|
|
241
|
+
'dependency-driven build feature will be deactivated when any of matched files are modified',
|
|
242
|
+
validation_alias=AliasChoices(
|
|
243
|
+
'deactivate_dependency_driven_build_by_filepatterns', 'ignore_app_dependencies_filepatterns'
|
|
260
244
|
),
|
|
245
|
+
default=None,
|
|
261
246
|
)
|
|
262
247
|
check_manifest_rules: bool = field(
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
FieldMetadata(
|
|
266
|
-
description='Check if all folders defined in the manifest files exist. Fail if not',
|
|
267
|
-
action='store_true',
|
|
268
|
-
)
|
|
248
|
+
FieldMetadata(
|
|
249
|
+
action='store_true',
|
|
269
250
|
),
|
|
251
|
+
description='Check if all folders defined in the manifest files exist. Fail if not',
|
|
252
|
+
default=False,
|
|
270
253
|
)
|
|
271
254
|
compare_manifest_sha_filepath: t.Optional[str] = field(
|
|
255
|
+
None,
|
|
256
|
+
description='Path to the file containing the sha256 hash of the manifest rules. '
|
|
257
|
+
'Compare the hash with the current manifest rules. '
|
|
258
|
+
'All matched apps will be built if the corresponding manifest rule is modified',
|
|
272
259
|
default=None,
|
|
273
|
-
metadata=asdict(
|
|
274
|
-
FieldMetadata(
|
|
275
|
-
description='Path to the file containing the sha256 hash of the manifest rules. '
|
|
276
|
-
'Compare the hash with the current manifest rules. '
|
|
277
|
-
'All matched apps will be built if the cooresponding manifest rule is modified',
|
|
278
|
-
)
|
|
279
|
-
),
|
|
280
260
|
)
|
|
281
261
|
|
|
282
|
-
def
|
|
283
|
-
|
|
284
|
-
manifest_file: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
285
|
-
ignore_app_dependencies_components: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
286
|
-
ignore_app_dependencies_filepatterns: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
287
|
-
):
|
|
288
|
-
super().__post_init__()
|
|
262
|
+
def model_post_init(self, __context: Any) -> None:
|
|
263
|
+
super().model_post_init(__context)
|
|
289
264
|
|
|
290
|
-
self.set_deprecated_field('manifest_files', 'manifest_file', manifest_file)
|
|
291
|
-
self.set_deprecated_field(
|
|
292
|
-
'deactivate_dependency_driven_build_by_components',
|
|
293
|
-
'ignore_app_dependencies_components',
|
|
294
|
-
ignore_app_dependencies_components,
|
|
295
|
-
)
|
|
296
|
-
self.set_deprecated_field(
|
|
297
|
-
'deactivate_dependency_driven_build_by_filepatterns',
|
|
298
|
-
'ignore_app_dependencies_filepatterns',
|
|
299
|
-
ignore_app_dependencies_filepatterns,
|
|
300
|
-
)
|
|
301
|
-
|
|
302
|
-
self.manifest_files = to_list(self.manifest_files)
|
|
303
|
-
self.modified_components = to_list(self.modified_components)
|
|
304
|
-
self.modified_files = to_list(self.modified_files)
|
|
305
|
-
self.deactivate_dependency_driven_build_by_components = to_list(
|
|
306
|
-
self.deactivate_dependency_driven_build_by_components
|
|
307
|
-
)
|
|
308
|
-
self.deactivate_dependency_driven_build_by_filepatterns = to_list(
|
|
309
|
-
self.deactivate_dependency_driven_build_by_filepatterns
|
|
310
|
-
)
|
|
311
|
-
|
|
312
|
-
# Validation
|
|
313
265
|
Manifest.CHECK_MANIFEST_RULES = self.check_manifest_rules
|
|
314
266
|
if self.manifest_files:
|
|
315
267
|
App.MANIFEST = Manifest.from_files(
|
|
@@ -379,234 +331,156 @@ class DependencyDrivenBuildArguments(GlobalArguments):
|
|
|
379
331
|
return None
|
|
380
332
|
|
|
381
333
|
|
|
382
|
-
def _os_curdir_as_list() -> t.List[str]:
|
|
383
|
-
return [os.curdir]
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
@dataclass
|
|
387
334
|
class FindBuildArguments(DependencyDrivenBuildArguments):
|
|
388
|
-
"""
|
|
389
|
-
Arguments used in both find and build commands
|
|
390
|
-
"""
|
|
391
|
-
|
|
392
335
|
paths: t.List[str] = field(
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
description='Paths to the directories containing the apps. By default set to the current directory',
|
|
398
|
-
shorthand='-p',
|
|
399
|
-
nargs='*',
|
|
400
|
-
)
|
|
336
|
+
FieldMetadata(
|
|
337
|
+
validate_method=[ValidateMethod.TO_LIST],
|
|
338
|
+
shorthand='-p',
|
|
339
|
+
nargs='*',
|
|
401
340
|
),
|
|
341
|
+
description='Paths to the directories containing the apps. By default set to the current directory',
|
|
342
|
+
default=os.curdir,
|
|
402
343
|
)
|
|
403
344
|
target: str = field(
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
FieldMetadata(
|
|
407
|
-
description='Filter the apps by target. By default set to "all"',
|
|
408
|
-
shorthand='-t',
|
|
409
|
-
)
|
|
345
|
+
FieldMetadata(
|
|
346
|
+
shorthand='-t',
|
|
410
347
|
),
|
|
348
|
+
description='Filter the apps by target. By default set to "all"',
|
|
349
|
+
default='all',
|
|
411
350
|
)
|
|
412
351
|
build_system: t.Union[str, t.Type[App]] = field(
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
FieldMetadata(
|
|
416
|
-
description='Filter the apps by build system. By default set to "cmake"',
|
|
417
|
-
choices=['cmake', 'make'],
|
|
418
|
-
)
|
|
352
|
+
FieldMetadata(
|
|
353
|
+
choices=['cmake', 'make'],
|
|
419
354
|
),
|
|
355
|
+
description='Filter the apps by build system. By default set to "cmake"',
|
|
356
|
+
default='cmake',
|
|
420
357
|
)
|
|
421
358
|
recursive: bool = field(
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
FieldMetadata(
|
|
425
|
-
description='Search for apps recursively under the specified paths',
|
|
426
|
-
action='store_true',
|
|
427
|
-
)
|
|
359
|
+
FieldMetadata(
|
|
360
|
+
action='store_true',
|
|
428
361
|
),
|
|
362
|
+
description='Search for apps recursively under the specified paths',
|
|
363
|
+
default=False,
|
|
429
364
|
)
|
|
430
|
-
exclude_list: InitVar[t.Optional[t.List[str]]] = _Field.UNSET
|
|
431
365
|
exclude: t.Optional[t.List[str]] = field(
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
description='Ignore the specified directories while searching recursively',
|
|
436
|
-
nargs='+',
|
|
437
|
-
)
|
|
366
|
+
FieldMetadata(
|
|
367
|
+
validate_method=[ValidateMethod.TO_LIST],
|
|
368
|
+
nargs='+',
|
|
438
369
|
),
|
|
370
|
+
description='Ignore the specified directories while searching recursively',
|
|
371
|
+
validation_alias=AliasChoices('exclude', 'exclude_list'),
|
|
372
|
+
default=None,
|
|
439
373
|
)
|
|
440
374
|
work_dir: t.Optional[str] = field(
|
|
375
|
+
None,
|
|
376
|
+
description='Copy the app to this directory before building. '
|
|
377
|
+
'By default set to the app directory. Can expand placeholders',
|
|
441
378
|
default=None,
|
|
442
|
-
metadata=asdict(
|
|
443
|
-
FieldMetadata(
|
|
444
|
-
description='Copy the app to this directory before building. '
|
|
445
|
-
'By default set to the app directory. Can expand placeholders',
|
|
446
|
-
)
|
|
447
|
-
),
|
|
448
379
|
)
|
|
449
380
|
build_dir: str = field(
|
|
381
|
+
None,
|
|
382
|
+
description='Build directory for the app. By default set to "build". '
|
|
383
|
+
'When set to relative path, it will be treated as relative to the app directory. '
|
|
384
|
+
'Can expand placeholders',
|
|
450
385
|
default='build',
|
|
451
|
-
metadata=asdict(
|
|
452
|
-
FieldMetadata(
|
|
453
|
-
description='Build directory for the app. By default set to "build". '
|
|
454
|
-
'When set to relative path, it will be treated as relative to the app directory. '
|
|
455
|
-
'Can expand placeholders',
|
|
456
|
-
)
|
|
457
|
-
),
|
|
458
386
|
)
|
|
459
|
-
build_log: InitVar[t.Optional[str]] = _Field.UNSET
|
|
460
387
|
build_log_filename: t.Optional[str] = field(
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
FieldMetadata(
|
|
464
|
-
deprecates={'build_log': {}},
|
|
465
|
-
description='Log filename under the build directory instead of stdout. Can expand placeholders',
|
|
466
|
-
)
|
|
388
|
+
FieldMetadata(
|
|
389
|
+
deprecates={'build_log': {}},
|
|
467
390
|
),
|
|
391
|
+
description='Log filename under the build directory instead of stdout. Can expand placeholders',
|
|
392
|
+
validation_alias=AliasChoices('build_log_filename', 'build_log'),
|
|
393
|
+
default=None,
|
|
468
394
|
)
|
|
469
|
-
size_file: InitVar[t.Optional[str]] = _Field.UNSET
|
|
470
395
|
size_json_filename: t.Optional[str] = field(
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
FieldMetadata(
|
|
474
|
-
deprecates={'size_file': {}},
|
|
475
|
-
description='`idf.py size` output file under the build directory when specified. '
|
|
476
|
-
'Can expand placeholders',
|
|
477
|
-
)
|
|
396
|
+
FieldMetadata(
|
|
397
|
+
deprecates={'size_file': {}},
|
|
478
398
|
),
|
|
399
|
+
description='`idf.py size` output file under the build directory when specified. ' 'Can expand placeholders',
|
|
400
|
+
validation_alias=AliasChoices('size_json_filename', 'size_file'),
|
|
401
|
+
default=None,
|
|
479
402
|
)
|
|
480
|
-
config: InitVar[t.Union[t.List[str], str, None]] = _Field.UNSET # cli # type: ignore
|
|
481
|
-
config_rules_str: InitVar[t.Union[t.List[str], str, None]] = _Field.UNSET # func # type: ignore
|
|
482
403
|
config_rules: t.Optional[t.List[str]] = field(
|
|
404
|
+
FieldMetadata(
|
|
405
|
+
validate_method=[ValidateMethod.TO_LIST],
|
|
406
|
+
deprecates={
|
|
407
|
+
'config': {'nargs': '+'},
|
|
408
|
+
},
|
|
409
|
+
nargs='+',
|
|
410
|
+
),
|
|
411
|
+
description='Defines the rules of building the project with pre-set sdkconfig files. '
|
|
412
|
+
'Supports FILENAME[=NAME] or FILEPATTERN format. '
|
|
413
|
+
'FILENAME is the filename of the sdkconfig file, relative to the app directory. '
|
|
414
|
+
'Optional NAME is the name of the configuration. '
|
|
415
|
+
'if not specified, the filename is used as the name. '
|
|
416
|
+
'FILEPATTERN is the filename of the sdkconfig file with a single wildcard character (*). '
|
|
417
|
+
'The NAME is the value matched by the wildcard',
|
|
418
|
+
validation_alias=AliasChoices('config_rules', 'config_rules_str', 'config'),
|
|
483
419
|
default=None,
|
|
484
|
-
metadata=asdict(
|
|
485
|
-
FieldMetadata(
|
|
486
|
-
deprecates={
|
|
487
|
-
'config': {'nargs': '+'},
|
|
488
|
-
},
|
|
489
|
-
description='Defines the rules of building the project with pre-set sdkconfig files. '
|
|
490
|
-
'Supports FILENAME[=NAME] or FILEPATTERN format. '
|
|
491
|
-
'FILENAME is the filename of the sdkconfig file, relative to the app directory. '
|
|
492
|
-
'Optional NAME is the name of the configuration. '
|
|
493
|
-
'if not specified, the filename is used as the name. '
|
|
494
|
-
'FILEPATTERN is the filename of the sdkconfig file with a single wildcard character (*). '
|
|
495
|
-
'The NAME is the value matched by the wildcard',
|
|
496
|
-
nargs='+',
|
|
497
|
-
)
|
|
498
|
-
),
|
|
499
420
|
)
|
|
500
421
|
override_sdkconfig_items: t.Optional[str] = field(
|
|
422
|
+
None,
|
|
423
|
+
description='A comma-separated list of key=value pairs to override the sdkconfig items',
|
|
501
424
|
default=None,
|
|
502
|
-
metadata=asdict(
|
|
503
|
-
FieldMetadata(
|
|
504
|
-
description='A comma-separated list of key=value pairs to override the sdkconfig items',
|
|
505
|
-
)
|
|
506
|
-
),
|
|
507
425
|
)
|
|
508
426
|
override_sdkconfig_files: t.Optional[str] = field(
|
|
427
|
+
None,
|
|
428
|
+
description='A comma-separated list of sdkconfig files to override the sdkconfig items. '
|
|
429
|
+
'When set to relative path, it will be treated as relative to the current directory',
|
|
509
430
|
default=None,
|
|
510
|
-
metadata=asdict(
|
|
511
|
-
FieldMetadata(
|
|
512
|
-
description='A comma-separated list of sdkconfig files to override the sdkconfig items. '
|
|
513
|
-
'When set to relative path, it will be treated as relative to the current directory',
|
|
514
|
-
)
|
|
515
|
-
),
|
|
516
431
|
)
|
|
517
432
|
sdkconfig_defaults: t.Optional[str] = field(
|
|
433
|
+
None,
|
|
434
|
+
description='A semicolon-separated list of sdkconfig files passed to `idf.py -DSDKCONFIG_DEFAULTS`. '
|
|
435
|
+
'SDKCONFIG_DEFAULTS environment variable is used when not specified',
|
|
518
436
|
default=os.getenv('SDKCONFIG_DEFAULTS', None),
|
|
519
|
-
metadata=asdict(
|
|
520
|
-
FieldMetadata(
|
|
521
|
-
description='A semicolon-separated list of sdkconfig files passed to `idf.py -DSDKCONFIG_DEFAULTS`. '
|
|
522
|
-
'SDKCONFIG_DEFAULTS environment variable is used when not specified',
|
|
523
|
-
)
|
|
524
|
-
),
|
|
525
437
|
)
|
|
526
438
|
check_warnings: bool = field(
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
FieldMetadata(
|
|
530
|
-
description='Check for warnings in the build output. Fail if any warnings are found',
|
|
531
|
-
action='store_true',
|
|
532
|
-
)
|
|
439
|
+
FieldMetadata(
|
|
440
|
+
action='store_true',
|
|
533
441
|
),
|
|
442
|
+
description='Check for warnings in the build output. Fail if any warnings are found',
|
|
443
|
+
default=False,
|
|
534
444
|
)
|
|
535
445
|
default_build_targets: t.Optional[t.List[str]] = field(
|
|
446
|
+
None,
|
|
447
|
+
description='space-separated list of the default enabled build targets for the apps. '
|
|
448
|
+
'When not specified, the default value is the targets listed by `idf.py --list-targets`',
|
|
536
449
|
default=None,
|
|
537
|
-
metadata=asdict(
|
|
538
|
-
FieldMetadata(
|
|
539
|
-
description='space-separated list of the default enabled build targets for the apps. '
|
|
540
|
-
'When not specified, the default value is the targets listed by `idf.py --list-targets`',
|
|
541
|
-
)
|
|
542
|
-
),
|
|
543
450
|
)
|
|
544
451
|
enable_preview_targets: bool = field(
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
FieldMetadata(
|
|
548
|
-
description='When enabled, the default build targets will be set to all apps, '
|
|
549
|
-
'including the preview targets. As the targets defined in `idf.py --list-targets --preview`',
|
|
550
|
-
action='store_true',
|
|
551
|
-
)
|
|
452
|
+
FieldMetadata(
|
|
453
|
+
action='store_true',
|
|
552
454
|
),
|
|
455
|
+
description='When enabled, the default build targets will be set to all apps, '
|
|
456
|
+
'including the preview targets. As the targets defined in `idf.py --list-targets --preview`',
|
|
457
|
+
default=False,
|
|
553
458
|
)
|
|
554
459
|
include_skipped_apps: bool = field(
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
FieldMetadata(
|
|
558
|
-
description='Include the skipped apps in the output, together with the enabled ones',
|
|
559
|
-
action='store_true',
|
|
560
|
-
)
|
|
460
|
+
FieldMetadata(
|
|
461
|
+
action='store_true',
|
|
561
462
|
),
|
|
463
|
+
description='Include the skipped apps in the output, together with the enabled ones',
|
|
464
|
+
default=False,
|
|
562
465
|
)
|
|
563
466
|
include_disabled_apps: bool = field(
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
FieldMetadata(
|
|
567
|
-
description='Include the disabled apps in the output, together with the enabled ones',
|
|
568
|
-
action='store_true',
|
|
569
|
-
)
|
|
467
|
+
FieldMetadata(
|
|
468
|
+
action='store_true',
|
|
570
469
|
),
|
|
470
|
+
description='Include the disabled apps in the output, together with the enabled ones',
|
|
471
|
+
default=False,
|
|
571
472
|
)
|
|
572
473
|
include_all_apps: bool = field(
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
FieldMetadata(
|
|
576
|
-
description='Include skipped, and disabled apps in the output, together with the enabled ones',
|
|
577
|
-
action='store_true',
|
|
578
|
-
)
|
|
474
|
+
FieldMetadata(
|
|
475
|
+
action='store_true',
|
|
579
476
|
),
|
|
477
|
+
description='Include skipped, and disabled apps in the output, together with the enabled ones',
|
|
478
|
+
default=False,
|
|
580
479
|
)
|
|
581
480
|
|
|
582
|
-
def
|
|
583
|
-
|
|
584
|
-
manifest_file: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
585
|
-
ignore_app_dependencies_components: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
586
|
-
ignore_app_dependencies_filepatterns: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
587
|
-
exclude_list: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
588
|
-
build_log: t.Optional[str] = _Field.UNSET, # type: ignore
|
|
589
|
-
size_file: t.Optional[str] = _Field.UNSET, # type: ignore
|
|
590
|
-
config: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
591
|
-
config_rules_str: t.Union[t.List[str], str, None] = _Field.UNSET, # type: ignore
|
|
592
|
-
):
|
|
593
|
-
super().__post_init__(
|
|
594
|
-
manifest_file=manifest_file,
|
|
595
|
-
ignore_app_dependencies_components=ignore_app_dependencies_components,
|
|
596
|
-
ignore_app_dependencies_filepatterns=ignore_app_dependencies_filepatterns,
|
|
597
|
-
)
|
|
598
|
-
|
|
599
|
-
self.set_deprecated_field('exclude', 'exclude_list', exclude_list)
|
|
600
|
-
self.set_deprecated_field('build_log_filename', 'build_log', build_log)
|
|
601
|
-
self.set_deprecated_field('size_json_filename', 'size_file', size_file)
|
|
602
|
-
self.set_deprecated_field('config_rules', 'config', config)
|
|
603
|
-
self.set_deprecated_field('config_rules', 'config_rules_str', config_rules_str)
|
|
604
|
-
|
|
605
|
-
self.paths = to_list(self.paths)
|
|
606
|
-
self.config_rules = to_list(self.config_rules)
|
|
607
|
-
self.exclude = to_list(self.exclude)
|
|
481
|
+
def model_post_init(self, __context: Any) -> None:
|
|
482
|
+
super().model_post_init(__context)
|
|
608
483
|
|
|
609
|
-
# Validation
|
|
610
484
|
if not self.paths:
|
|
611
485
|
raise InvalidCommand('At least one path must be specified')
|
|
612
486
|
|
|
@@ -636,54 +510,26 @@ class FindBuildArguments(DependencyDrivenBuildArguments):
|
|
|
636
510
|
SESSION_ARGS.set(self)
|
|
637
511
|
|
|
638
512
|
|
|
639
|
-
@dataclass
|
|
640
513
|
class FindArguments(FindBuildArguments):
|
|
641
|
-
"""
|
|
642
|
-
Arguments used in the find command
|
|
643
|
-
"""
|
|
644
|
-
|
|
645
514
|
output: t.Optional[str] = field(
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
FieldMetadata(
|
|
649
|
-
description='Record the found apps to the specified file instead of stdout',
|
|
650
|
-
shorthand='-o',
|
|
651
|
-
)
|
|
515
|
+
FieldMetadata(
|
|
516
|
+
shorthand='-o',
|
|
652
517
|
),
|
|
518
|
+
description='Record the found apps to the specified file instead of stdout',
|
|
519
|
+
default=None,
|
|
653
520
|
)
|
|
654
521
|
output_format: str = field(
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
FieldMetadata(
|
|
658
|
-
description='Output format of the found apps. '
|
|
659
|
-
'In "raw" format, each line is a json string serialized from the app model. '
|
|
660
|
-
'In "json" format, the output is a json list of the serialized app models',
|
|
661
|
-
choices=['raw', 'json'],
|
|
662
|
-
)
|
|
522
|
+
FieldMetadata(
|
|
523
|
+
choices=['raw', 'json'],
|
|
663
524
|
),
|
|
525
|
+
description='Output format of the found apps. '
|
|
526
|
+
'In "raw" format, each line is a json string serialized from the app model. '
|
|
527
|
+
'In "json" format, the output is a json list of the serialized app models',
|
|
528
|
+
default='raw',
|
|
664
529
|
)
|
|
665
530
|
|
|
666
|
-
def
|
|
667
|
-
|
|
668
|
-
manifest_file: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
669
|
-
ignore_app_dependencies_components: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
670
|
-
ignore_app_dependencies_filepatterns: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
671
|
-
exclude_list: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
672
|
-
build_log: t.Optional[str] = _Field.UNSET, # type: ignore
|
|
673
|
-
size_file: t.Optional[str] = _Field.UNSET, # type: ignore
|
|
674
|
-
config: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
675
|
-
config_rules_str: t.Union[t.List[str], str, None] = _Field.UNSET, # type: ignore
|
|
676
|
-
):
|
|
677
|
-
super().__post_init__(
|
|
678
|
-
manifest_file=manifest_file,
|
|
679
|
-
ignore_app_dependencies_components=ignore_app_dependencies_components,
|
|
680
|
-
ignore_app_dependencies_filepatterns=ignore_app_dependencies_filepatterns,
|
|
681
|
-
exclude_list=exclude_list,
|
|
682
|
-
build_log=build_log,
|
|
683
|
-
size_file=size_file,
|
|
684
|
-
config=config,
|
|
685
|
-
config_rules_str=config_rules_str,
|
|
686
|
-
)
|
|
531
|
+
def model_post_init(self, __context: Any) -> None:
|
|
532
|
+
super().model_post_init(__context)
|
|
687
533
|
|
|
688
534
|
if self.include_all_apps:
|
|
689
535
|
self.include_skipped_apps = True
|
|
@@ -694,163 +540,114 @@ class FindArguments(FindBuildArguments):
|
|
|
694
540
|
self.output_format = 'json'
|
|
695
541
|
|
|
696
542
|
|
|
697
|
-
@dataclass
|
|
698
543
|
class BuildArguments(FindBuildArguments):
|
|
699
544
|
build_verbose: bool = field(
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
FieldMetadata(
|
|
703
|
-
description='Enable verbose output of the build system',
|
|
704
|
-
action='store_true',
|
|
705
|
-
)
|
|
545
|
+
FieldMetadata(
|
|
546
|
+
action='store_true',
|
|
706
547
|
),
|
|
548
|
+
description='Enable verbose output of the build system',
|
|
549
|
+
default=False,
|
|
707
550
|
)
|
|
708
551
|
parallel_count: int = field(
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
FieldMetadata(
|
|
712
|
-
description='Number of parallel build jobs in total. '
|
|
713
|
-
'Specified together with --parallel-index. '
|
|
714
|
-
'The given apps will be divided into parallel_count parts, '
|
|
715
|
-
'and the current run will build the parallel_index-th part',
|
|
716
|
-
type=int,
|
|
717
|
-
)
|
|
552
|
+
FieldMetadata(
|
|
553
|
+
type=int,
|
|
718
554
|
),
|
|
555
|
+
description='Number of parallel build jobs in total. '
|
|
556
|
+
'Specified together with --parallel-index. '
|
|
557
|
+
'The given apps will be divided into parallel_count parts, '
|
|
558
|
+
'and the current run will build the parallel_index-th part',
|
|
559
|
+
default=1,
|
|
719
560
|
)
|
|
720
561
|
parallel_index: int = field(
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
FieldMetadata(
|
|
724
|
-
description='Index (1-based) of the parallel build job. '
|
|
725
|
-
'Specified together with --parallel-count. '
|
|
726
|
-
'The given apps will be divided into parallel_count parts, '
|
|
727
|
-
'and the current run will build the parallel_index-th part',
|
|
728
|
-
type=int,
|
|
729
|
-
)
|
|
562
|
+
FieldMetadata(
|
|
563
|
+
type=int,
|
|
730
564
|
),
|
|
565
|
+
description='Index (1-based) of the parallel build job. '
|
|
566
|
+
'Specified together with --parallel-count. '
|
|
567
|
+
'The given apps will be divided into parallel_count parts, '
|
|
568
|
+
'and the current run will build the parallel_index-th part',
|
|
569
|
+
default=1,
|
|
731
570
|
)
|
|
732
571
|
dry_run: bool = field(
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
FieldMetadata(
|
|
736
|
-
description='Skip the actual build, only print the build process',
|
|
737
|
-
action='store_true',
|
|
738
|
-
)
|
|
572
|
+
FieldMetadata(
|
|
573
|
+
action='store_true',
|
|
739
574
|
),
|
|
575
|
+
description='Skip the actual build, only print the build process',
|
|
576
|
+
default=False,
|
|
740
577
|
)
|
|
741
578
|
keep_going: bool = field(
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
FieldMetadata(
|
|
745
|
-
description='Continue building the next app when the current build fails',
|
|
746
|
-
action='store_true',
|
|
747
|
-
)
|
|
579
|
+
FieldMetadata(
|
|
580
|
+
action='store_true',
|
|
748
581
|
),
|
|
749
|
-
|
|
750
|
-
no_preserve: bool = field(
|
|
582
|
+
description='Continue building the next app when the current build fails',
|
|
751
583
|
default=False,
|
|
752
|
-
metadata=asdict(
|
|
753
|
-
FieldMetadata(
|
|
754
|
-
description='Do not preserve the build directory after a successful build',
|
|
755
|
-
action='store_true',
|
|
756
|
-
)
|
|
757
|
-
),
|
|
758
|
-
)
|
|
759
|
-
collect_size_info: t.Optional[str] = field(
|
|
760
|
-
default=None,
|
|
761
|
-
metadata=asdict(
|
|
762
|
-
FieldMetadata(
|
|
763
|
-
description='Record size json filepath of the built apps to the specified file. '
|
|
764
|
-
'Each line is a json string. Can expand placeholders @p',
|
|
765
|
-
)
|
|
766
|
-
),
|
|
767
584
|
)
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
metadata=asdict(
|
|
772
|
-
FieldMetadata(
|
|
773
|
-
description='Record serialized app model of the built apps to the specified file. '
|
|
774
|
-
'Each line is a json string. Can expand placeholders @p',
|
|
775
|
-
)
|
|
585
|
+
no_preserve: bool = field(
|
|
586
|
+
FieldMetadata(
|
|
587
|
+
action='store_true',
|
|
776
588
|
),
|
|
589
|
+
description='Do not preserve the build directory after a successful build',
|
|
590
|
+
default=False,
|
|
777
591
|
)
|
|
778
|
-
_collect_app_info: t.Optional[str] = field(init=False, repr=False, default=None)
|
|
779
|
-
ignore_warning_str: InitVar[t.Optional[t.List[str]]] = _Field.UNSET
|
|
780
592
|
ignore_warning_strs: t.Optional[t.List[str]] = field(
|
|
593
|
+
FieldMetadata(
|
|
594
|
+
validate_method=[ValidateMethod.TO_LIST],
|
|
595
|
+
deprecates={
|
|
596
|
+
'ignore_warning_str': {'nargs': '+'},
|
|
597
|
+
},
|
|
598
|
+
nargs='+',
|
|
599
|
+
),
|
|
600
|
+
description='space-separated list of patterns. '
|
|
601
|
+
'Ignore the warnings in the build output that match the patterns',
|
|
602
|
+
validation_alias=AliasChoices('ignore_warning_strs', 'ignore_warning_str'),
|
|
781
603
|
default=None,
|
|
782
|
-
metadata=asdict(
|
|
783
|
-
FieldMetadata(
|
|
784
|
-
deprecates={
|
|
785
|
-
'ignore_warning_str': {'nargs': '+'},
|
|
786
|
-
},
|
|
787
|
-
description='space-separated list of patterns. '
|
|
788
|
-
'Ignore the warnings in the build output that match the patterns',
|
|
789
|
-
nargs='+',
|
|
790
|
-
)
|
|
791
|
-
),
|
|
792
604
|
)
|
|
793
|
-
ignore_warning_file: InitVar[t.Optional[str]] = _Field.UNSET
|
|
794
605
|
ignore_warning_files: t.Optional[t.List[str]] = field(
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
deprecates={'ignore_warning_file': {}},
|
|
799
|
-
description='Path to the files containing the patterns to ignore the warnings in the build output',
|
|
800
|
-
nargs='+',
|
|
801
|
-
)
|
|
606
|
+
FieldMetadata(
|
|
607
|
+
deprecates={'ignore_warning_file': {}},
|
|
608
|
+
nargs='+',
|
|
802
609
|
),
|
|
610
|
+
description='Path to the files containing the patterns to ignore the warnings in the build output',
|
|
611
|
+
validation_alias=AliasChoices('ignore_warning_files', 'ignore_warning_file'),
|
|
612
|
+
default=None,
|
|
803
613
|
)
|
|
804
614
|
copy_sdkconfig: bool = field(
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
FieldMetadata(
|
|
808
|
-
description='Copy the sdkconfig file to the build directory',
|
|
809
|
-
action='store_true',
|
|
810
|
-
)
|
|
615
|
+
FieldMetadata(
|
|
616
|
+
action='store_true',
|
|
811
617
|
),
|
|
618
|
+
description='Copy the sdkconfig file to the build directory',
|
|
619
|
+
default=False,
|
|
812
620
|
)
|
|
813
|
-
|
|
621
|
+
|
|
622
|
+
# Attrs that support placeholders
|
|
623
|
+
collect_size_info_filename: t.Optional[str] = field(
|
|
624
|
+
None,
|
|
625
|
+
description='Record size json filepath of the built apps to the specified file. '
|
|
626
|
+
'Each line is a json string. Can expand placeholders @p',
|
|
627
|
+
validation_alias=AliasChoices('collect_size_info_filename', 'collect_size_info'),
|
|
814
628
|
default=None,
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
629
|
+
exclude=True, # computed field is used
|
|
630
|
+
)
|
|
631
|
+
collect_app_info_filename: t.Optional[str] = field(
|
|
632
|
+
None,
|
|
633
|
+
description='Record serialized app model of the built apps to the specified file. '
|
|
634
|
+
'Each line is a json string. Can expand placeholders @p',
|
|
635
|
+
validation_alias=AliasChoices('collect_app_info_filename', 'collect_app_info'),
|
|
636
|
+
default=None,
|
|
637
|
+
exclude=True, # computed field is used
|
|
638
|
+
)
|
|
639
|
+
junitxml_filename: t.Optional[str] = field(
|
|
640
|
+
None,
|
|
641
|
+
description='Path to the junitxml file to record the build results. Can expand placeholder @p',
|
|
642
|
+
validation_alias=AliasChoices('junitxml_filename', 'junitxml'),
|
|
643
|
+
default=None,
|
|
644
|
+
exclude=True, # computed field is used
|
|
820
645
|
)
|
|
821
|
-
_junitxml: t.Optional[str] = field(init=False, repr=False, default=None)
|
|
822
|
-
|
|
823
646
|
# used for expanding placeholders
|
|
824
647
|
PARALLEL_INDEX_PLACEHOLDER: t.ClassVar[str] = '@p' # replace it with the parallel index
|
|
825
648
|
|
|
826
|
-
def
|
|
827
|
-
|
|
828
|
-
manifest_file: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
829
|
-
ignore_app_dependencies_components: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
830
|
-
ignore_app_dependencies_filepatterns: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
831
|
-
exclude_list: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
832
|
-
build_log: t.Optional[str] = _Field.UNSET, # type: ignore
|
|
833
|
-
size_file: t.Optional[str] = _Field.UNSET, # type: ignore
|
|
834
|
-
config: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
835
|
-
config_rules_str: t.Union[t.List[str], str, None] = _Field.UNSET, # type: ignore
|
|
836
|
-
ignore_warning_str: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
837
|
-
ignore_warning_file: t.Optional[str] = _Field.UNSET, # type: ignore
|
|
838
|
-
):
|
|
839
|
-
super().__post_init__(
|
|
840
|
-
manifest_file=manifest_file,
|
|
841
|
-
ignore_app_dependencies_components=ignore_app_dependencies_components,
|
|
842
|
-
ignore_app_dependencies_filepatterns=ignore_app_dependencies_filepatterns,
|
|
843
|
-
exclude_list=exclude_list,
|
|
844
|
-
build_log=build_log,
|
|
845
|
-
size_file=size_file,
|
|
846
|
-
config=config,
|
|
847
|
-
config_rules_str=config_rules_str,
|
|
848
|
-
)
|
|
849
|
-
|
|
850
|
-
self.set_deprecated_field('ignore_warning_strs', 'ignore_warning_str', ignore_warning_str)
|
|
851
|
-
self.set_deprecated_field('ignore_warning_files', 'ignore_warning_file', ignore_warning_file)
|
|
852
|
-
|
|
853
|
-
self.ignore_warning_strs = to_list(self.ignore_warning_strs) or []
|
|
649
|
+
def model_post_init(self, __context: Any) -> None:
|
|
650
|
+
super().model_post_init(__context)
|
|
854
651
|
|
|
855
652
|
ignore_warnings_regexes = []
|
|
856
653
|
if self.ignore_warning_strs:
|
|
@@ -861,97 +658,65 @@ class BuildArguments(FindBuildArguments):
|
|
|
861
658
|
ignore_warnings_regexes.append(re.compile(s.strip()))
|
|
862
659
|
App.IGNORE_WARNS_REGEXES = ignore_warnings_regexes
|
|
863
660
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
)
|
|
870
|
-
|
|
871
|
-
if not isinstance(BuildArguments.collect_app_info, property):
|
|
872
|
-
self._collect_app_info = self.collect_app_info
|
|
873
|
-
BuildArguments.collect_app_info = property( # type: ignore
|
|
874
|
-
BuildArguments._get_collect_app_info,
|
|
875
|
-
BuildArguments._set_collect_app_info,
|
|
876
|
-
)
|
|
877
|
-
|
|
878
|
-
if not isinstance(BuildArguments.junitxml, property):
|
|
879
|
-
self._junitxml = self.junitxml
|
|
880
|
-
BuildArguments.junitxml = property( # type: ignore
|
|
881
|
-
BuildArguments._get_junitxml,
|
|
882
|
-
BuildArguments._set_junitxml,
|
|
883
|
-
)
|
|
884
|
-
|
|
885
|
-
def _get_collect_size_info(self) -> t.Optional[str]:
|
|
886
|
-
return (
|
|
887
|
-
self._collect_size_info.replace(self.PARALLEL_INDEX_PLACEHOLDER, str(self.parallel_index))
|
|
888
|
-
if self._collect_size_info
|
|
889
|
-
else None
|
|
890
|
-
)
|
|
661
|
+
@computed_field # type: ignore
|
|
662
|
+
@property
|
|
663
|
+
def collect_size_info(self) -> t.Optional[str]:
|
|
664
|
+
if self.collect_size_info_filename:
|
|
665
|
+
return self.collect_size_info_filename.replace(self.PARALLEL_INDEX_PLACEHOLDER, str(self.parallel_index))
|
|
891
666
|
|
|
892
|
-
|
|
893
|
-
self._collect_size_info = k
|
|
667
|
+
return None
|
|
894
668
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
)
|
|
669
|
+
@computed_field # type: ignore
|
|
670
|
+
@property
|
|
671
|
+
def collect_app_info(self) -> t.Optional[str]:
|
|
672
|
+
if self.collect_app_info_filename:
|
|
673
|
+
return self.collect_app_info_filename.replace(self.PARALLEL_INDEX_PLACEHOLDER, str(self.parallel_index))
|
|
901
674
|
|
|
902
|
-
|
|
903
|
-
self._collect_app_info = k
|
|
675
|
+
return None
|
|
904
676
|
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
)
|
|
677
|
+
@computed_field # type: ignore
|
|
678
|
+
@property
|
|
679
|
+
def junitxml(self) -> t.Optional[str]:
|
|
680
|
+
if self.junitxml_filename:
|
|
681
|
+
return self.junitxml_filename.replace(self.PARALLEL_INDEX_PLACEHOLDER, str(self.parallel_index))
|
|
911
682
|
|
|
912
|
-
|
|
913
|
-
self._junitxml = k
|
|
683
|
+
return None
|
|
914
684
|
|
|
915
685
|
|
|
916
|
-
@dataclass
|
|
917
686
|
class DumpManifestShaArguments(GlobalArguments):
|
|
918
|
-
"""
|
|
919
|
-
Arguments used in the dump-manifest-sha command
|
|
920
|
-
"""
|
|
921
|
-
|
|
922
687
|
manifest_files: t.Optional[t.List[str]] = field(
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
nargs='+',
|
|
928
|
-
required=True,
|
|
929
|
-
)
|
|
688
|
+
FieldMetadata(
|
|
689
|
+
validate_method=[ValidateMethod.TO_LIST],
|
|
690
|
+
nargs='+',
|
|
691
|
+
required=True,
|
|
930
692
|
),
|
|
693
|
+
description='Path to the manifest files which contains the build test rules of the apps',
|
|
694
|
+
default=None,
|
|
931
695
|
)
|
|
696
|
+
|
|
932
697
|
output: t.Optional[str] = field(
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
description='Record the sha256 hash of the manifest rules to the specified file',
|
|
937
|
-
shorthand='-o',
|
|
938
|
-
required=True,
|
|
939
|
-
)
|
|
698
|
+
FieldMetadata(
|
|
699
|
+
shorthand='-o',
|
|
700
|
+
required=True,
|
|
940
701
|
),
|
|
702
|
+
description='Path to the output file to record the sha256 hash of the manifest rules',
|
|
703
|
+
default=None,
|
|
941
704
|
)
|
|
942
705
|
|
|
943
|
-
def
|
|
944
|
-
super().
|
|
706
|
+
def model_post_init(self, __context: Any) -> None:
|
|
707
|
+
super().model_post_init(__context)
|
|
945
708
|
|
|
946
|
-
# Validation
|
|
947
|
-
self.manifest_files = to_list(self.manifest_files)
|
|
948
709
|
if not self.manifest_files:
|
|
949
710
|
raise InvalidCommand('Manifest files are required to dump the SHA values.')
|
|
950
711
|
if not self.output:
|
|
951
712
|
raise InvalidCommand('Output file is required to dump the SHA values.')
|
|
952
713
|
|
|
953
714
|
|
|
954
|
-
def
|
|
715
|
+
def _snake_case_to_cli_arg_name(s: str) -> str:
|
|
716
|
+
return f'--{s.replace("_", "-")}'
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
def add_args_to_parser(argument_cls: t.Type[BaseArguments], parser: argparse.ArgumentParser) -> None:
|
|
955
720
|
"""
|
|
956
721
|
Add arguments to the parser from the argument class.
|
|
957
722
|
|
|
@@ -960,48 +725,50 @@ def add_arguments_to_parser(argument_cls: t.Type[GlobalArguments], parser: argpa
|
|
|
960
725
|
:param argument_cls: argument class
|
|
961
726
|
:param parser: argparse parser
|
|
962
727
|
"""
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
_names = [_snake_case_to_cli_arg_name(depr_k)]
|
|
978
|
-
if short_name:
|
|
979
|
-
_names.append(short_name)
|
|
980
|
-
parser.add_argument(*_names, **depr_kwargs)
|
|
981
|
-
|
|
982
|
-
# args
|
|
983
|
-
args = [_snake_case_to_cli_arg_name(name)]
|
|
984
|
-
if _meta.shorthand:
|
|
985
|
-
args.append(_meta.shorthand)
|
|
986
|
-
|
|
987
|
-
# kwargs passed to add_argument
|
|
988
|
-
kwargs = drop_none_kwargs(
|
|
989
|
-
{
|
|
990
|
-
'help': desp,
|
|
991
|
-
'action': _meta.action,
|
|
992
|
-
'nargs': _meta.nargs,
|
|
993
|
-
'choices': _meta.choices,
|
|
994
|
-
'type': _meta.type,
|
|
995
|
-
'required': _meta.required,
|
|
996
|
-
}
|
|
997
|
-
)
|
|
998
|
-
# default None is important for argparse
|
|
999
|
-
kwargs['default'] = _meta.default or getattr(f, 'default', None)
|
|
728
|
+
for f_name, f in argument_cls.model_fields.items():
|
|
729
|
+
f_meta = get_meta(f)
|
|
730
|
+
if f_meta and f_meta.deprecates:
|
|
731
|
+
for dep_f_name, dep_f_kwargs in f_meta.deprecates.items():
|
|
732
|
+
_names = [_snake_case_to_cli_arg_name(dep_f_name)]
|
|
733
|
+
_shorthand = dep_f_kwargs.pop('shorthand', None)
|
|
734
|
+
if _shorthand:
|
|
735
|
+
_names.append(_shorthand)
|
|
736
|
+
|
|
737
|
+
parser.add_argument(
|
|
738
|
+
*_names,
|
|
739
|
+
**dep_f_kwargs,
|
|
740
|
+
help=f'[Deprecated] Use {_snake_case_to_cli_arg_name(f_name)} instead',
|
|
741
|
+
)
|
|
1000
742
|
|
|
1001
|
-
|
|
743
|
+
names = [_snake_case_to_cli_arg_name(f_name)]
|
|
744
|
+
if f_meta and f_meta.shorthand:
|
|
745
|
+
names.append(f_meta.shorthand)
|
|
746
|
+
|
|
747
|
+
kwargs: t.Dict[str, t.Any] = {}
|
|
748
|
+
if f_meta:
|
|
749
|
+
if f_meta.type:
|
|
750
|
+
kwargs['type'] = f_meta.type
|
|
751
|
+
if f_meta.required:
|
|
752
|
+
kwargs['required'] = True
|
|
753
|
+
if f_meta.action:
|
|
754
|
+
kwargs['action'] = f_meta.action
|
|
755
|
+
if f_meta.nargs:
|
|
756
|
+
kwargs['nargs'] = f_meta.nargs
|
|
757
|
+
if f_meta.choices:
|
|
758
|
+
kwargs['choices'] = f_meta.choices
|
|
759
|
+
if f_meta.default:
|
|
760
|
+
kwargs['default'] = f_meta.default
|
|
761
|
+
if 'default' not in kwargs:
|
|
762
|
+
kwargs['default'] = f.default
|
|
763
|
+
|
|
764
|
+
parser.add_argument(
|
|
765
|
+
*names,
|
|
766
|
+
**kwargs,
|
|
767
|
+
help=f.description,
|
|
768
|
+
)
|
|
1002
769
|
|
|
1003
770
|
|
|
1004
|
-
def
|
|
771
|
+
def add_args_to_obj_doc_as_params(argument_cls: t.Type[GlobalArguments], obj: t.Any = None) -> None:
|
|
1005
772
|
"""
|
|
1006
773
|
Add arguments to the function as parameters.
|
|
1007
774
|
|
|
@@ -1009,14 +776,24 @@ def add_arguments_to_obj_doc_as_params(argument_cls: t.Type[GlobalArguments], ob
|
|
|
1009
776
|
:param obj: object to add the docstring to
|
|
1010
777
|
"""
|
|
1011
778
|
_obj = obj or argument_cls
|
|
1012
|
-
|
|
1013
|
-
|
|
779
|
+
_doc_str = _obj.__doc__ or ''
|
|
780
|
+
_doc_str += '\n'
|
|
1014
781
|
|
|
1015
|
-
for f in
|
|
782
|
+
for f_name, f in argument_cls.model_fields.items():
|
|
1016
783
|
# typing generic alias is not a class
|
|
1017
|
-
_annotation = f.
|
|
784
|
+
_annotation = f.annotation.__name__ if inspect.isclass(f.annotation) else f.annotation
|
|
785
|
+
_doc_str += f' :param {f_name}: {f.description}\n'
|
|
786
|
+
_doc_str += f' :type {f_name}: {_annotation}\n'
|
|
787
|
+
|
|
788
|
+
_obj.__doc__ = _doc_str
|
|
789
|
+
|
|
1018
790
|
|
|
1019
|
-
|
|
1020
|
-
|
|
791
|
+
def apply_config_file(config_file: t.Optional[str]) -> None:
|
|
792
|
+
def _subclasses(klass: t.Type[T]) -> t.Set[t.Type[T]]:
|
|
793
|
+
return set(klass.__subclasses__()).union([s for c in klass.__subclasses__() for s in _subclasses(c)])
|
|
1021
794
|
|
|
1022
|
-
|
|
795
|
+
if config_file:
|
|
796
|
+
BaseArguments.model_config['toml_file'] = str(config_file)
|
|
797
|
+
# modify all subclasses
|
|
798
|
+
for cls in _subclasses(BaseArguments):
|
|
799
|
+
cls.model_config['toml_file'] = str(config_file)
|