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