idf-build-apps 2.5.0rc0__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/app.py +0 -4
- idf_build_apps/args.py +454 -620
- idf_build_apps/constants.py +1 -0
- idf_build_apps/finder.py +2 -2
- idf_build_apps/main.py +49 -16
- 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.0rc0.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.0rc0.dist-info/RECORD +0 -26
- {idf_build_apps-2.5.0rc0.dist-info → idf_build_apps-2.5.0rc2.dist-info}/LICENSE +0 -0
- {idf_build_apps-2.5.0rc0.dist-info → idf_build_apps-2.5.0rc2.dist-info}/WHEEL +0 -0
- {idf_build_apps-2.5.0rc0.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
|
|
154
104
|
|
|
155
|
-
|
|
156
|
-
for name, value in config_dict.items():
|
|
157
|
-
if hasattr(self, name):
|
|
158
|
-
setattr(self, name, value)
|
|
105
|
+
return None
|
|
159
106
|
|
|
160
|
-
if name in self._depr_name_to_new_name_dict:
|
|
161
|
-
self.set_deprecated_field(self._depr_name_to_new_name_dict[name], name, value)
|
|
162
107
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
return
|
|
108
|
+
class BaseArguments(BaseSettings):
|
|
109
|
+
"""Base settings class for all settings classes"""
|
|
166
110
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
+
)
|
|
116
|
+
|
|
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__()
|
|
289
|
-
|
|
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
|
-
)
|
|
262
|
+
def model_post_init(self, __context: Any) -> None:
|
|
263
|
+
super().model_post_init(__context)
|
|
311
264
|
|
|
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
|
-
)
|
|
481
|
+
def model_post_init(self, __context: Any) -> None:
|
|
482
|
+
super().model_post_init(__context)
|
|
598
483
|
|
|
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)
|
|
608
|
-
|
|
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,207 +540,183 @@ 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
|
),
|
|
582
|
+
description='Continue building the next app when the current build fails',
|
|
583
|
+
default=False,
|
|
749
584
|
)
|
|
750
585
|
no_preserve: bool = field(
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
FieldMetadata(
|
|
754
|
-
description='Do not preserve the build directory after a successful build',
|
|
755
|
-
action='store_true',
|
|
756
|
-
)
|
|
586
|
+
FieldMetadata(
|
|
587
|
+
action='store_true',
|
|
757
588
|
),
|
|
589
|
+
description='Do not preserve the build directory after a successful build',
|
|
590
|
+
default=False,
|
|
758
591
|
)
|
|
759
|
-
|
|
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'),
|
|
760
603
|
default=None,
|
|
761
|
-
metadata=asdict(
|
|
762
|
-
FieldMetadata(
|
|
763
|
-
description='[INTERNAL CI USE] 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
604
|
)
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
description='[INTERNAL CI USE] record serialized app model of the built apps to the specified file. '
|
|
773
|
-
'Each line is a json string. Can expand placeholders @p',
|
|
774
|
-
)
|
|
605
|
+
ignore_warning_files: t.Optional[t.List[str]] = field(
|
|
606
|
+
FieldMetadata(
|
|
607
|
+
deprecates={'ignore_warning_file': {}},
|
|
608
|
+
nargs='+',
|
|
775
609
|
),
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
ignore_warning_strings: t.Optional[t.List[str]] = field(
|
|
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'),
|
|
779
612
|
default=None,
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
},
|
|
785
|
-
description='space-separated list of patterns. '
|
|
786
|
-
'Ignore the warnings in the build output that match the patterns',
|
|
787
|
-
nargs='+',
|
|
788
|
-
)
|
|
613
|
+
)
|
|
614
|
+
copy_sdkconfig: bool = field(
|
|
615
|
+
FieldMetadata(
|
|
616
|
+
action='store_true',
|
|
789
617
|
),
|
|
618
|
+
description='Copy the sdkconfig file to the build directory',
|
|
619
|
+
default=False,
|
|
790
620
|
)
|
|
791
|
-
|
|
792
|
-
|
|
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'),
|
|
793
628
|
default=None,
|
|
794
|
-
|
|
795
|
-
FieldMetadata(
|
|
796
|
-
deprecates={'ignore_warning_file': {}},
|
|
797
|
-
description='Path to the files containing the patterns to ignore the warnings in the build output',
|
|
798
|
-
nargs='+',
|
|
799
|
-
)
|
|
800
|
-
),
|
|
629
|
+
exclude=True, # computed field is used
|
|
801
630
|
)
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
),
|
|
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
|
|
810
638
|
)
|
|
811
|
-
|
|
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'),
|
|
812
643
|
default=None,
|
|
813
|
-
|
|
814
|
-
FieldMetadata(
|
|
815
|
-
description='Path to the junitxml file to record the build results. Can expand placeholder @p',
|
|
816
|
-
)
|
|
817
|
-
),
|
|
644
|
+
exclude=True, # computed field is used
|
|
818
645
|
)
|
|
646
|
+
# used for expanding placeholders
|
|
647
|
+
PARALLEL_INDEX_PLACEHOLDER: t.ClassVar[str] = '@p' # replace it with the parallel index
|
|
819
648
|
|
|
820
|
-
def
|
|
821
|
-
|
|
822
|
-
manifest_file: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
823
|
-
ignore_app_dependencies_components: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
824
|
-
ignore_app_dependencies_filepatterns: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
825
|
-
exclude_list: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
826
|
-
build_log: t.Optional[str] = _Field.UNSET, # type: ignore
|
|
827
|
-
size_file: t.Optional[str] = _Field.UNSET, # type: ignore
|
|
828
|
-
config: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
829
|
-
config_rules_str: t.Union[t.List[str], str, None] = _Field.UNSET, # type: ignore
|
|
830
|
-
ignore_warning_str: t.Optional[t.List[str]] = _Field.UNSET, # type: ignore
|
|
831
|
-
ignore_warning_file: t.Optional[str] = _Field.UNSET, # type: ignore
|
|
832
|
-
):
|
|
833
|
-
super().__post_init__(
|
|
834
|
-
manifest_file=manifest_file,
|
|
835
|
-
ignore_app_dependencies_components=ignore_app_dependencies_components,
|
|
836
|
-
ignore_app_dependencies_filepatterns=ignore_app_dependencies_filepatterns,
|
|
837
|
-
exclude_list=exclude_list,
|
|
838
|
-
build_log=build_log,
|
|
839
|
-
size_file=size_file,
|
|
840
|
-
config=config,
|
|
841
|
-
config_rules_str=config_rules_str,
|
|
842
|
-
)
|
|
843
|
-
|
|
844
|
-
self.set_deprecated_field('ignore_warning_strings', 'ignore_warning_str', ignore_warning_str)
|
|
845
|
-
self.set_deprecated_field('ignore_warning_files', 'ignore_warning_file', ignore_warning_file)
|
|
846
|
-
|
|
847
|
-
self.ignore_warning_strings = to_list(self.ignore_warning_strings) or []
|
|
649
|
+
def model_post_init(self, __context: Any) -> None:
|
|
650
|
+
super().model_post_init(__context)
|
|
848
651
|
|
|
849
652
|
ignore_warnings_regexes = []
|
|
850
|
-
if self.
|
|
851
|
-
for s in self.
|
|
653
|
+
if self.ignore_warning_strs:
|
|
654
|
+
for s in self.ignore_warning_strs:
|
|
852
655
|
ignore_warnings_regexes.append(re.compile(s))
|
|
853
656
|
if self.ignore_warning_files:
|
|
854
657
|
for s in self.ignore_warning_files:
|
|
855
658
|
ignore_warnings_regexes.append(re.compile(s.strip()))
|
|
856
659
|
App.IGNORE_WARNS_REGEXES = ignore_warnings_regexes
|
|
857
660
|
|
|
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))
|
|
666
|
+
|
|
667
|
+
return None
|
|
858
668
|
|
|
859
|
-
@
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
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))
|
|
864
674
|
|
|
675
|
+
return None
|
|
676
|
+
|
|
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))
|
|
682
|
+
|
|
683
|
+
return None
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
class DumpManifestShaArguments(GlobalArguments):
|
|
865
687
|
manifest_files: t.Optional[t.List[str]] = field(
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
nargs='+',
|
|
871
|
-
required=True,
|
|
872
|
-
)
|
|
688
|
+
FieldMetadata(
|
|
689
|
+
validate_method=[ValidateMethod.TO_LIST],
|
|
690
|
+
nargs='+',
|
|
691
|
+
required=True,
|
|
873
692
|
),
|
|
693
|
+
description='Path to the manifest files which contains the build test rules of the apps',
|
|
694
|
+
default=None,
|
|
874
695
|
)
|
|
696
|
+
|
|
875
697
|
output: t.Optional[str] = field(
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
description='Record the sha256 hash of the manifest rules to the specified file',
|
|
880
|
-
shorthand='-o',
|
|
881
|
-
required=True,
|
|
882
|
-
)
|
|
698
|
+
FieldMetadata(
|
|
699
|
+
shorthand='-o',
|
|
700
|
+
required=True,
|
|
883
701
|
),
|
|
702
|
+
description='Path to the output file to record the sha256 hash of the manifest rules',
|
|
703
|
+
default=None,
|
|
884
704
|
)
|
|
885
705
|
|
|
886
|
-
def
|
|
887
|
-
super().
|
|
706
|
+
def model_post_init(self, __context: Any) -> None:
|
|
707
|
+
super().model_post_init(__context)
|
|
888
708
|
|
|
889
|
-
# Validation
|
|
890
|
-
self.manifest_files = to_list(self.manifest_files)
|
|
891
709
|
if not self.manifest_files:
|
|
892
710
|
raise InvalidCommand('Manifest files are required to dump the SHA values.')
|
|
893
711
|
if not self.output:
|
|
894
712
|
raise InvalidCommand('Output file is required to dump the SHA values.')
|
|
895
713
|
|
|
896
714
|
|
|
897
|
-
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:
|
|
898
720
|
"""
|
|
899
721
|
Add arguments to the parser from the argument class.
|
|
900
722
|
|
|
@@ -903,48 +725,50 @@ def add_arguments_to_parser(argument_cls: t.Type[GlobalArguments], parser: argpa
|
|
|
903
725
|
:param argument_cls: argument class
|
|
904
726
|
:param parser: argparse parser
|
|
905
727
|
"""
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
_names = [_snake_case_to_cli_arg_name(depr_k)]
|
|
921
|
-
if short_name:
|
|
922
|
-
_names.append(short_name)
|
|
923
|
-
parser.add_argument(*_names, **depr_kwargs)
|
|
924
|
-
|
|
925
|
-
# args
|
|
926
|
-
args = [_snake_case_to_cli_arg_name(name)]
|
|
927
|
-
if _meta.shorthand:
|
|
928
|
-
args.append(_meta.shorthand)
|
|
929
|
-
|
|
930
|
-
# kwargs passed to add_argument
|
|
931
|
-
kwargs = drop_none_kwargs(
|
|
932
|
-
{
|
|
933
|
-
'help': desp,
|
|
934
|
-
'action': _meta.action,
|
|
935
|
-
'nargs': _meta.nargs,
|
|
936
|
-
'choices': _meta.choices,
|
|
937
|
-
'type': _meta.type,
|
|
938
|
-
'required': _meta.required,
|
|
939
|
-
}
|
|
940
|
-
)
|
|
941
|
-
# default None is important for argparse
|
|
942
|
-
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
|
+
)
|
|
943
742
|
|
|
944
|
-
|
|
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
|
+
)
|
|
945
769
|
|
|
946
770
|
|
|
947
|
-
def
|
|
771
|
+
def add_args_to_obj_doc_as_params(argument_cls: t.Type[GlobalArguments], obj: t.Any = None) -> None:
|
|
948
772
|
"""
|
|
949
773
|
Add arguments to the function as parameters.
|
|
950
774
|
|
|
@@ -952,14 +776,24 @@ def add_arguments_to_obj_doc_as_params(argument_cls: t.Type[GlobalArguments], ob
|
|
|
952
776
|
:param obj: object to add the docstring to
|
|
953
777
|
"""
|
|
954
778
|
_obj = obj or argument_cls
|
|
955
|
-
|
|
956
|
-
|
|
779
|
+
_doc_str = _obj.__doc__ or ''
|
|
780
|
+
_doc_str += '\n'
|
|
957
781
|
|
|
958
|
-
for f in
|
|
782
|
+
for f_name, f in argument_cls.model_fields.items():
|
|
959
783
|
# typing generic alias is not a class
|
|
960
|
-
_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
|
+
|
|
961
790
|
|
|
962
|
-
|
|
963
|
-
|
|
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)])
|
|
964
794
|
|
|
965
|
-
|
|
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)
|