idf-build-apps 2.6.0__tar.gz → 2.6.1__tar.gz
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-2.6.0 → idf_build_apps-2.6.1}/.github/workflows/publish-pypi.yml +3 -3
- idf_build_apps-2.6.1/.github/workflows/sync-jira.yml +61 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.github/workflows/test-build-docs.yml +1 -1
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.github/workflows/test-build-idf-apps.yml +1 -1
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.pre-commit-config.yaml +1 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/CHANGELOG.md +6 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/PKG-INFO +2 -1
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/__init__.py +1 -1
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/args.py +25 -12
- idf_build_apps-2.6.1/idf_build_apps/constants.py +77 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/main.py +7 -5
- idf_build_apps-2.6.1/idf_build_apps/manifest/__init__.py +17 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/manifest/manifest.py +16 -8
- idf_build_apps-2.6.1/idf_build_apps/manifest/soc_header.py +6 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/vendors/pydantic_sources.py +3 -1
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/pyproject.toml +5 -1
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/setup.py +3 -2
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/conftest.py +5 -5
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/test_args.py +38 -1
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/test_manifest.py +32 -23
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/test_utils.py +1 -15
- idf_build_apps-2.6.0/.github/workflows/issue_comment.yml +0 -20
- idf_build_apps-2.6.0/.github/workflows/new_issues.yml +0 -20
- idf_build_apps-2.6.0/.github/workflows/new_prs.yml +0 -25
- idf_build_apps-2.6.0/idf_build_apps/constants.py +0 -122
- idf_build_apps-2.6.0/idf_build_apps/manifest/__init__.py +0 -6
- idf_build_apps-2.6.0/idf_build_apps/manifest/if_parser.py +0 -240
- idf_build_apps-2.6.0/idf_build_apps/manifest/soc_header.py +0 -141
- idf_build_apps-2.6.0/tests/test_soc_caps.py +0 -21
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.editorconfig +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.git-blame-ignore-revs +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.gitattributes +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.github/dependabot.yml +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.github/workflows/check-pre-commit.yml +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.gitignore +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.readthedocs.yml +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/CONTRIBUTING.md +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/LICENSE +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/README.md +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/_apidoc_templates/module.rst_t +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/_apidoc_templates/package.rst_t +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/_apidoc_templates/toc.rst_t +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/_static/espressif-logo.svg +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/_static/theme_overrides.css +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/_templates/layout.html +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/conf_common.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/Makefile +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/conf.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/explanations/build.rst +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/explanations/config_rules.rst +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/explanations/dependency_driven_build.rst +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/explanations/find.rst +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/guides/1.x_to_2.x.md +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/index.rst +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/others/CHANGELOG.md +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/others/CONTRIBUTING.md +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/references/cli.rst +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/references/config_file.rst +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/references/manifest.rst +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/__main__.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/app.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/autocompletions.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/finder.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/junit/__init__.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/junit/report.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/junit/utils.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/log.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/py.typed +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/session_args.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/utils.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/vendors/__init__.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/yaml/__init__.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/yaml/parser.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/license_header.txt +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/test_app.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/test_build.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/test_cmd.py +0 -0
- {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/test_finder.py +0 -0
|
@@ -3,16 +3,16 @@ name: Publish PyPI
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
5
|
tags:
|
|
6
|
-
-
|
|
6
|
+
- "v*"
|
|
7
7
|
|
|
8
8
|
jobs:
|
|
9
9
|
deploy:
|
|
10
|
-
runs-on: ubuntu-
|
|
10
|
+
runs-on: ubuntu-22.04
|
|
11
11
|
steps:
|
|
12
12
|
- uses: actions/checkout@v4
|
|
13
13
|
- uses: actions/setup-python@v5
|
|
14
14
|
with:
|
|
15
|
-
python-version:
|
|
15
|
+
python-version: "3.7"
|
|
16
16
|
- name: Publish packages
|
|
17
17
|
env:
|
|
18
18
|
FLIT_USERNAME: __token__
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# FILE: .github/workflows/sync-jira.yml
|
|
2
|
+
---
|
|
3
|
+
# This GitHub Actions workflow synchronizes GitHub issues, comments, and pull requests with Jira.
|
|
4
|
+
# It triggers on new issues, issue comments, and on a scheduled basis.
|
|
5
|
+
# The workflow uses a custom action to perform the synchronization with Jira (espressif/sync-jira-actions).
|
|
6
|
+
|
|
7
|
+
name: 🔷 Sync to Jira
|
|
8
|
+
|
|
9
|
+
run-name: >
|
|
10
|
+
Sync to Jira -
|
|
11
|
+
${{ github.event_name == 'issue_comment' && 'Issue Comment' ||
|
|
12
|
+
github.event_name == 'schedule' && 'New Pull Requests' ||
|
|
13
|
+
github.event_name == 'issues' && 'New Issue' ||
|
|
14
|
+
github.event_name == 'workflow_dispatch' && 'Manual Sync' }}
|
|
15
|
+
|
|
16
|
+
on:
|
|
17
|
+
issues: { types: [opened] }
|
|
18
|
+
issue_comment: { types: [created, edited, deleted] }
|
|
19
|
+
schedule: [cron: "0 * * * *"]
|
|
20
|
+
workflow_dispatch:
|
|
21
|
+
inputs:
|
|
22
|
+
action:
|
|
23
|
+
{
|
|
24
|
+
description: "Action to be performed",
|
|
25
|
+
required: true,
|
|
26
|
+
default: "mirror-issues",
|
|
27
|
+
}
|
|
28
|
+
issue-numbers:
|
|
29
|
+
{
|
|
30
|
+
description: "Issue numbers to sync (comma-separated)",
|
|
31
|
+
required: true,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
jobs:
|
|
35
|
+
sync-to-jira:
|
|
36
|
+
name: >
|
|
37
|
+
Sync to Jira -
|
|
38
|
+
${{ github.event_name == 'issue_comment' && 'Issue Comment' ||
|
|
39
|
+
github.event_name == 'schedule' && 'New Pull Requests' ||
|
|
40
|
+
github.event_name == 'issues' && 'New Issue' ||
|
|
41
|
+
github.event_name == 'workflow_dispatch' && 'Manual Sync' }}
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
permissions:
|
|
44
|
+
contents: read
|
|
45
|
+
issues: write
|
|
46
|
+
pull-requests: write
|
|
47
|
+
steps:
|
|
48
|
+
- name: Check out
|
|
49
|
+
uses: actions/checkout@v4
|
|
50
|
+
|
|
51
|
+
- name: Run synchronization to Jira
|
|
52
|
+
uses: espressif/sync-jira-actions@v1
|
|
53
|
+
with:
|
|
54
|
+
cron_job: ${{ github.event_name == 'schedule' && 'true' || '' }}
|
|
55
|
+
env:
|
|
56
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
57
|
+
JIRA_PASS: ${{ secrets.JIRA_PASS }}
|
|
58
|
+
JIRA_PROJECT: RDT
|
|
59
|
+
JIRA_COMPONENT: idf-build-apps
|
|
60
|
+
JIRA_URL: ${{ secrets.JIRA_URL }}
|
|
61
|
+
JIRA_USER: ${{ secrets.JIRA_USER }}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: idf-build-apps
|
|
3
|
-
Version: 2.6.
|
|
3
|
+
Version: 2.6.1
|
|
4
4
|
Summary: Tools for building ESP-IDF related apps.
|
|
5
5
|
Author-email: Fu Hanxi <fuhanxi@espressif.com>
|
|
6
6
|
Requires-Python: >=3.7
|
|
@@ -21,6 +21,7 @@ Requires-Dist: pydantic~=2.0
|
|
|
21
21
|
Requires-Dist: pydantic_settings
|
|
22
22
|
Requires-Dist: argcomplete>=3
|
|
23
23
|
Requires-Dist: typing-extensions; python_version < '3.11'
|
|
24
|
+
Requires-Dist: esp-bool-parser>=0.1.2,<1
|
|
24
25
|
Requires-Dist: sphinx ; extra == "doc"
|
|
25
26
|
Requires-Dist: sphinx-rtd-theme ; extra == "doc"
|
|
26
27
|
Requires-Dist: sphinx_copybutton ; extra == "doc"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
|
1
|
+
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import argparse
|
|
@@ -115,8 +115,9 @@ def get_meta(f: FieldInfo) -> t.Optional[FieldMetadata]:
|
|
|
115
115
|
class BaseArguments(BaseSettings):
|
|
116
116
|
"""Base settings class for all settings classes"""
|
|
117
117
|
|
|
118
|
+
CONFIG_FILE_PATH: t.ClassVar[t.Optional[Path]] = None
|
|
119
|
+
|
|
118
120
|
model_config = SettingsConfigDict(
|
|
119
|
-
toml_file=IDF_BUILD_APPS_TOML_FN,
|
|
120
121
|
# these below two are supported in pydantic 2.6
|
|
121
122
|
pyproject_toml_table_header=('tool', 'idf-build-apps'),
|
|
122
123
|
pyproject_toml_depth=sys.maxsize,
|
|
@@ -132,11 +133,15 @@ class BaseArguments(BaseSettings):
|
|
|
132
133
|
dotenv_settings: PydanticBaseSettingsSource, # noqa: ARG003
|
|
133
134
|
file_secret_settings: PydanticBaseSettingsSource, # noqa: ARG003
|
|
134
135
|
) -> t.Tuple[PydanticBaseSettingsSource, ...]:
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
TomlConfigSettingsSource(settings_cls),
|
|
138
|
-
PyprojectTomlConfigSettingsSource(settings_cls),
|
|
139
|
-
|
|
136
|
+
sources: t.Tuple[PydanticBaseSettingsSource, ...] = (init_settings,)
|
|
137
|
+
if cls.CONFIG_FILE_PATH is None:
|
|
138
|
+
sources += (TomlConfigSettingsSource(settings_cls, toml_file=Path(IDF_BUILD_APPS_TOML_FN)),)
|
|
139
|
+
sources += (PyprojectTomlConfigSettingsSource(settings_cls, toml_file=Path('pyproject.toml')),)
|
|
140
|
+
else:
|
|
141
|
+
sources += (TomlConfigSettingsSource(settings_cls, toml_file=Path(cls.CONFIG_FILE_PATH)),)
|
|
142
|
+
sources += (PyprojectTomlConfigSettingsSource(settings_cls, toml_file=Path(cls.CONFIG_FILE_PATH)),)
|
|
143
|
+
|
|
144
|
+
return sources
|
|
140
145
|
|
|
141
146
|
@field_validator('*', mode='before')
|
|
142
147
|
@classmethod
|
|
@@ -874,12 +879,20 @@ def add_args_to_obj_doc_as_params(argument_cls: t.Type[GlobalArguments], obj: t.
|
|
|
874
879
|
_obj.__doc__ = _doc_str
|
|
875
880
|
|
|
876
881
|
|
|
877
|
-
def apply_config_file(config_file: t.Optional[str]) -> None:
|
|
882
|
+
def apply_config_file(config_file: t.Optional[str] = None, reset: bool = False) -> None:
|
|
878
883
|
def _subclasses(klass: t.Type[T]) -> t.Set[t.Type[T]]:
|
|
879
884
|
return set(klass.__subclasses__()).union([s for c in klass.__subclasses__() for s in _subclasses(c)])
|
|
880
885
|
|
|
881
|
-
if
|
|
882
|
-
BaseArguments.
|
|
883
|
-
# modify all subclasses
|
|
886
|
+
if reset:
|
|
887
|
+
BaseArguments.CONFIG_FILE_PATH = None
|
|
884
888
|
for cls in _subclasses(BaseArguments):
|
|
885
|
-
cls.
|
|
889
|
+
cls.CONFIG_FILE_PATH = None
|
|
890
|
+
|
|
891
|
+
if config_file:
|
|
892
|
+
if os.path.isfile(config_file):
|
|
893
|
+
p = Path(config_file)
|
|
894
|
+
BaseArguments.CONFIG_FILE_PATH = p
|
|
895
|
+
for cls in _subclasses(BaseArguments):
|
|
896
|
+
cls.CONFIG_FILE_PATH = p
|
|
897
|
+
else:
|
|
898
|
+
LOGGER.warning(f'Config file {config_file} does not exist. Ignoring...')
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import enum
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
import esp_bool_parser
|
|
8
|
+
|
|
9
|
+
IDF_PATH = esp_bool_parser.IDF_PATH
|
|
10
|
+
IDF_PY = os.path.join(IDF_PATH, 'tools', 'idf.py')
|
|
11
|
+
IDF_SIZE_PY = os.path.join(IDF_PATH, 'tools', 'idf_size.py')
|
|
12
|
+
|
|
13
|
+
PROJECT_DESCRIPTION_JSON = 'project_description.json'
|
|
14
|
+
DEFAULT_SDKCONFIG = 'sdkconfig.defaults'
|
|
15
|
+
|
|
16
|
+
SUPPORTED_TARGETS = esp_bool_parser.SUPPORTED_TARGETS
|
|
17
|
+
PREVIEW_TARGETS = esp_bool_parser.PREVIEW_TARGETS
|
|
18
|
+
ALL_TARGETS = esp_bool_parser.ALL_TARGETS
|
|
19
|
+
IDF_VERSION_MAJOR = esp_bool_parser.IDF_VERSION_MAJOR
|
|
20
|
+
IDF_VERSION_MINOR = esp_bool_parser.IDF_VERSION_MINOR
|
|
21
|
+
IDF_VERSION_PATCH = esp_bool_parser.IDF_VERSION_PATCH
|
|
22
|
+
IDF_VERSION = esp_bool_parser.IDF_VERSION
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class BuildStatus(str, enum.Enum):
|
|
26
|
+
UNKNOWN = 'unknown'
|
|
27
|
+
DISABLED = 'disabled'
|
|
28
|
+
SKIPPED = 'skipped'
|
|
29
|
+
SHOULD_BE_BUILT = 'should be built'
|
|
30
|
+
FAILED = 'build failed'
|
|
31
|
+
SUCCESS = 'build success'
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class BuildStage(str, enum.Enum):
|
|
35
|
+
DRY_RUN = 'Dry Run'
|
|
36
|
+
PRE_BUILD = 'Pre Build'
|
|
37
|
+
BUILD = 'Build'
|
|
38
|
+
POST_BUILD = 'Post Build'
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def max_length(cls) -> int:
|
|
42
|
+
return max(len(v.value) for v in cls.__members__.values())
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
completion_instructions = """
|
|
46
|
+
With the `--activate` option, detect your shell type and add the appropriate commands to your shell's config file
|
|
47
|
+
so that it runs on startup. You will likely have to restart.
|
|
48
|
+
or re-login for the autocompletion to start working.
|
|
49
|
+
|
|
50
|
+
You can also specify your shell using the `--shell` option.
|
|
51
|
+
|
|
52
|
+
If you do not want automatic modification of your shell configuration file
|
|
53
|
+
You can manually add the commands provided below to activate autocompletion.
|
|
54
|
+
or run them in your current terminal session for one-time activation.
|
|
55
|
+
|
|
56
|
+
Once again, you will likely have to restart
|
|
57
|
+
or re-login for the autocompletion to start working.
|
|
58
|
+
|
|
59
|
+
bash:
|
|
60
|
+
eval "$(register-python-argcomplete idf-build-apps)"
|
|
61
|
+
|
|
62
|
+
zsh:
|
|
63
|
+
To activate completions in zsh, first make sure compinit is marked for
|
|
64
|
+
autoload and run autoload:
|
|
65
|
+
|
|
66
|
+
autoload -U compinit
|
|
67
|
+
compinit
|
|
68
|
+
|
|
69
|
+
Afterwards you can enable completions for idf-build-apps:
|
|
70
|
+
|
|
71
|
+
eval "$(register-python-argcomplete idf-build-apps)"
|
|
72
|
+
|
|
73
|
+
fish:
|
|
74
|
+
# Not required to be in the config file, only run once
|
|
75
|
+
register-python-argcomplete --shell fish idf-build-apps >~/.config/fish/completions/idf-build-apps.fish
|
|
76
|
+
"""
|
|
77
|
+
IDF_BUILD_APPS_TOML_FN = '.idf_build_apps.toml'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# PYTHON_ARGCOMPLETE_OK
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: 2022-
|
|
3
|
+
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
|
4
4
|
# SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
|
|
6
6
|
import argparse
|
|
@@ -68,7 +68,8 @@ def find_apps(
|
|
|
68
68
|
|
|
69
69
|
:return: list of found apps
|
|
70
70
|
"""
|
|
71
|
-
|
|
71
|
+
if config_file:
|
|
72
|
+
apply_config_file(config_file)
|
|
72
73
|
|
|
73
74
|
# compatible with old usage
|
|
74
75
|
## `preserve`
|
|
@@ -132,7 +133,8 @@ def build_apps(
|
|
|
132
133
|
|
|
133
134
|
:return: exit code
|
|
134
135
|
"""
|
|
135
|
-
|
|
136
|
+
if config_file:
|
|
137
|
+
apply_config_file(config_file)
|
|
136
138
|
|
|
137
139
|
# compatible with old usage
|
|
138
140
|
## `check_app_dependencies`
|
|
@@ -385,8 +387,8 @@ def main():
|
|
|
385
387
|
kwargs = vars(args)
|
|
386
388
|
action = kwargs.pop('action')
|
|
387
389
|
config_file = kwargs.pop('config_file')
|
|
388
|
-
|
|
389
|
-
|
|
390
|
+
if config_file:
|
|
391
|
+
apply_config_file(config_file)
|
|
390
392
|
|
|
391
393
|
if action == 'dump-manifest-sha':
|
|
392
394
|
arguments = DumpManifestShaArguments(**drop_none_kwargs(kwargs))
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Manifest file
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from esp_bool_parser import register_addition_attribute
|
|
9
|
+
|
|
10
|
+
from .manifest import FolderRule
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def folder_rule_attr(target, **kwargs):
|
|
14
|
+
return 1 if target in FolderRule.DEFAULT_BUILD_TARGETS else 0
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
register_addition_attribute('INCLUDE_DEFAULT', folder_rule_attr)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2022-
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import logging
|
|
4
4
|
import os
|
|
5
|
-
import pickle
|
|
6
5
|
import typing as t
|
|
7
6
|
from hashlib import sha512
|
|
8
7
|
|
|
8
|
+
from esp_bool_parser import BoolStmt, parse_bool_expr
|
|
9
9
|
from pyparsing import (
|
|
10
10
|
ParseException,
|
|
11
11
|
)
|
|
@@ -23,10 +23,6 @@ from ..utils import (
|
|
|
23
23
|
from ..yaml import (
|
|
24
24
|
parse,
|
|
25
25
|
)
|
|
26
|
-
from .if_parser import (
|
|
27
|
-
BOOL_EXPR,
|
|
28
|
-
BoolStmt,
|
|
29
|
-
)
|
|
30
26
|
|
|
31
27
|
LOGGER = logging.getLogger(__name__)
|
|
32
28
|
|
|
@@ -34,7 +30,8 @@ LOGGER = logging.getLogger(__name__)
|
|
|
34
30
|
class IfClause:
|
|
35
31
|
def __init__(self, stmt: str, temporary: bool = False, reason: t.Optional[str] = None) -> None:
|
|
36
32
|
try:
|
|
37
|
-
self.stmt: BoolStmt =
|
|
33
|
+
self.stmt: BoolStmt = parse_bool_expr(stmt)
|
|
34
|
+
self._stmt: str = stmt
|
|
38
35
|
except (ParseException, InvalidIfClause) as ex:
|
|
39
36
|
raise InvalidIfClause(f'Invalid if clause: {stmt}. {ex}')
|
|
40
37
|
|
|
@@ -51,6 +48,9 @@ class IfClause:
|
|
|
51
48
|
f' reason: lack of ci runners'
|
|
52
49
|
)
|
|
53
50
|
|
|
51
|
+
def __repr__(self):
|
|
52
|
+
return f'IfClause(stmt={self._stmt!r}, temporary={self.temporary!r}, reason={self.reason!r})'
|
|
53
|
+
|
|
54
54
|
def get_value(self, target: str, config_name: str) -> t.Any:
|
|
55
55
|
return self.stmt.get_value(target, config_name)
|
|
56
56
|
|
|
@@ -69,6 +69,14 @@ class SwitchClause:
|
|
|
69
69
|
return content
|
|
70
70
|
return self.default_clause
|
|
71
71
|
|
|
72
|
+
def __repr__(self) -> str:
|
|
73
|
+
return (
|
|
74
|
+
f'SwitchClause('
|
|
75
|
+
f'if_clauses={self.if_clauses!r}, '
|
|
76
|
+
f'contents={self.contents!r}, '
|
|
77
|
+
f'default_clause={self.default_clause!r})'
|
|
78
|
+
)
|
|
79
|
+
|
|
72
80
|
|
|
73
81
|
class FolderRule:
|
|
74
82
|
DEFAULT_BUILD_TARGETS = SUPPORTED_TARGETS
|
|
@@ -153,7 +161,7 @@ class FolderRule:
|
|
|
153
161
|
self.depends_components,
|
|
154
162
|
self.depends_filepatterns,
|
|
155
163
|
]:
|
|
156
|
-
sha.update(
|
|
164
|
+
sha.update(repr(obj).encode())
|
|
157
165
|
|
|
158
166
|
return sha.hexdigest()
|
|
159
167
|
|
|
@@ -93,7 +93,9 @@ class TomlConfigSettingsSource(InitSettingsSource, ConfigFileSourceMixin):
|
|
|
93
93
|
:param depth: Number of directories up the tree to check of a pyproject.toml.
|
|
94
94
|
"""
|
|
95
95
|
if provided and Path(provided).is_file():
|
|
96
|
-
|
|
96
|
+
fp = provided.resolve()
|
|
97
|
+
print(f'Loading config file: {fp}')
|
|
98
|
+
return fp
|
|
97
99
|
|
|
98
100
|
rv = Path.cwd()
|
|
99
101
|
count = -1
|
|
@@ -31,6 +31,7 @@ dependencies = [
|
|
|
31
31
|
"pydantic_settings",
|
|
32
32
|
"argcomplete>=3",
|
|
33
33
|
"typing-extensions; python_version < '3.11'",
|
|
34
|
+
"esp-bool-parser>=0.1.2,<1"
|
|
34
35
|
]
|
|
35
36
|
|
|
36
37
|
[project.optional-dependencies]
|
|
@@ -61,7 +62,7 @@ idf-build-apps = "idf_build_apps:main.main"
|
|
|
61
62
|
|
|
62
63
|
[tool.commitizen]
|
|
63
64
|
name = "cz_conventional_commits"
|
|
64
|
-
version = "2.6.
|
|
65
|
+
version = "2.6.1"
|
|
65
66
|
tag_format = "v$version"
|
|
66
67
|
version_files = [
|
|
67
68
|
"idf_build_apps/__init__.py",
|
|
@@ -156,5 +157,8 @@ typing-modules = [
|
|
|
156
157
|
quote-style = "single"
|
|
157
158
|
docstring-code-format = true
|
|
158
159
|
|
|
160
|
+
[tool.ruff.lint.flake8-unused-arguments]
|
|
161
|
+
ignore-variadic-names = true
|
|
162
|
+
|
|
159
163
|
[tool.mypy]
|
|
160
164
|
python_version = "3.8"
|
|
@@ -19,7 +19,8 @@ install_requires = \
|
|
|
19
19
|
'packaging',
|
|
20
20
|
'pydantic~=2.0',
|
|
21
21
|
'pydantic_settings',
|
|
22
|
-
'argcomplete>=3'
|
|
22
|
+
'argcomplete>=3',
|
|
23
|
+
'esp-bool-parser>=0.1.2,<1']
|
|
23
24
|
|
|
24
25
|
extras_require = \
|
|
25
26
|
{":python_version < '3.11'": ['toml', 'typing-extensions'],
|
|
@@ -36,7 +37,7 @@ entry_points = \
|
|
|
36
37
|
{'console_scripts': ['idf-build-apps = idf_build_apps:main.main']}
|
|
37
38
|
|
|
38
39
|
setup(name='idf-build-apps',
|
|
39
|
-
version='2.6.
|
|
40
|
+
version='2.6.1',
|
|
40
41
|
description='Tools for building ESP-IDF related apps.',
|
|
41
42
|
author=None,
|
|
42
43
|
author_email='Fu Hanxi <fuhanxi@espressif.com>',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2022-
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import os
|
|
4
4
|
|
|
@@ -10,7 +10,7 @@ from idf_build_apps import (
|
|
|
10
10
|
setup_logging,
|
|
11
11
|
)
|
|
12
12
|
from idf_build_apps.args import apply_config_file
|
|
13
|
-
from idf_build_apps.constants import
|
|
13
|
+
from idf_build_apps.constants import SUPPORTED_TARGETS
|
|
14
14
|
from idf_build_apps.manifest.manifest import FolderRule
|
|
15
15
|
|
|
16
16
|
|
|
@@ -19,7 +19,7 @@ def clean_cls_attr(tmp_path):
|
|
|
19
19
|
App.MANIFEST = None
|
|
20
20
|
FolderRule.DEFAULT_BUILD_TARGETS = SUPPORTED_TARGETS
|
|
21
21
|
idf_build_apps.SESSION_ARGS.clean()
|
|
22
|
-
apply_config_file(
|
|
22
|
+
apply_config_file(reset=True)
|
|
23
23
|
os.chdir(tmp_path)
|
|
24
24
|
|
|
25
25
|
|
|
@@ -63,7 +63,7 @@ def sha_of_enable_only_esp32():
|
|
|
63
63
|
# !!! ONLY CHANGE IT WHEN NECESSARY !!!
|
|
64
64
|
assert (
|
|
65
65
|
sha
|
|
66
|
-
== '
|
|
66
|
+
== 'bfc1c61176cfb76169eab6c4f00dbcc4d7886fee4b93ede5fac2c005dd85db640464e9b03986d3da3bfaa4d109b053862c07dc4d5a407e58f773a8f710ec60cb' # noqa: E501
|
|
67
67
|
)
|
|
68
68
|
|
|
69
69
|
return sha
|
|
@@ -76,7 +76,7 @@ def sha_of_enable_esp32_or_esp32s2():
|
|
|
76
76
|
# !!! ONLY CHANGE IT WHEN NECESSARY !!!
|
|
77
77
|
assert (
|
|
78
78
|
sha
|
|
79
|
-
== '
|
|
79
|
+
== '9ab121a0d39bcb590465837091e82dfd798cd1ff9579e92c23e8bebaee127b46751108f0de3953993cb7993903e45d78851fc465d774a606b0ab1251fbe4b9f5' # noqa: E501
|
|
80
80
|
)
|
|
81
81
|
|
|
82
82
|
return sha
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
|
1
|
+
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import os
|
|
4
|
+
from tempfile import NamedTemporaryFile
|
|
4
5
|
from xml.etree import ElementTree
|
|
5
6
|
|
|
6
7
|
import pytest
|
|
@@ -323,3 +324,39 @@ dry_run = false
|
|
|
323
324
|
assert test_suite.attrib['skipped'] == '2'
|
|
324
325
|
assert test_suite.findall('testcase')[0].attrib['name'] == 'foo/build_esp32'
|
|
325
326
|
assert test_suite.findall('testcase')[1].attrib['name'] == 'foo/build_esp32s2'
|
|
327
|
+
|
|
328
|
+
def test_config_file_by_cli(self, tmp_path, monkeypatch):
|
|
329
|
+
create_project('foo', tmp_path)
|
|
330
|
+
create_project('bar', tmp_path)
|
|
331
|
+
|
|
332
|
+
with open(IDF_BUILD_APPS_TOML_FN, 'w') as fw:
|
|
333
|
+
fw.write('paths = ["foo"]')
|
|
334
|
+
|
|
335
|
+
with NamedTemporaryFile(mode='w', suffix='.toml') as ft:
|
|
336
|
+
ft.write('paths = ["bar"]')
|
|
337
|
+
ft.flush()
|
|
338
|
+
|
|
339
|
+
with monkeypatch.context() as m:
|
|
340
|
+
m.setattr(
|
|
341
|
+
'sys.argv',
|
|
342
|
+
[
|
|
343
|
+
'idf-build-apps',
|
|
344
|
+
'build',
|
|
345
|
+
'-t',
|
|
346
|
+
'esp32',
|
|
347
|
+
'--config-file',
|
|
348
|
+
ft.name,
|
|
349
|
+
'--junitxml',
|
|
350
|
+
'test.xml',
|
|
351
|
+
'--dry-run',
|
|
352
|
+
],
|
|
353
|
+
)
|
|
354
|
+
main()
|
|
355
|
+
|
|
356
|
+
with open('test.xml') as f:
|
|
357
|
+
xml = ElementTree.fromstring(f.read())
|
|
358
|
+
test_suite = xml.findall('testsuite')[0]
|
|
359
|
+
assert test_suite.attrib['failures'] == '0'
|
|
360
|
+
assert test_suite.attrib['errors'] == '0'
|
|
361
|
+
assert test_suite.attrib['skipped'] == '1'
|
|
362
|
+
assert test_suite.findall('testcase')[0].attrib['name'] == 'bar/build'
|
|
@@ -1,21 +1,15 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2022-
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import os
|
|
4
4
|
|
|
5
5
|
import pytest
|
|
6
6
|
import yaml
|
|
7
|
-
from packaging.version import (
|
|
8
|
-
Version,
|
|
9
|
-
)
|
|
10
7
|
|
|
11
8
|
import idf_build_apps
|
|
12
9
|
from idf_build_apps import setup_logging
|
|
13
10
|
from idf_build_apps.constants import (
|
|
14
11
|
SUPPORTED_TARGETS,
|
|
15
12
|
)
|
|
16
|
-
from idf_build_apps.manifest.if_parser import (
|
|
17
|
-
BOOL_STMT,
|
|
18
|
-
)
|
|
19
13
|
from idf_build_apps.manifest.manifest import (
|
|
20
14
|
IfClause,
|
|
21
15
|
Manifest,
|
|
@@ -70,6 +64,37 @@ test2:
|
|
|
70
64
|
assert manifest.enable_build_targets('test23') == sorted(SUPPORTED_TARGETS)
|
|
71
65
|
|
|
72
66
|
|
|
67
|
+
def test_repr(tmp_path):
|
|
68
|
+
yaml_file = tmp_path / 'test.yml'
|
|
69
|
+
|
|
70
|
+
yaml_file.write_text(
|
|
71
|
+
"""
|
|
72
|
+
test1:
|
|
73
|
+
enable:
|
|
74
|
+
- if: IDF_TARGET == "esp32c3"
|
|
75
|
+
reason: "None"
|
|
76
|
+
depends_components:
|
|
77
|
+
- if: IDF_VERSION == "1.2.3" or IDF_VERSION_MAJOR == 4
|
|
78
|
+
content: [ "VVV" ]
|
|
79
|
+
- if: CONFIG_NAME == "AAA"
|
|
80
|
+
content: [ "AAA" ]
|
|
81
|
+
- default: ["some_1", "some_2", "some_3"]
|
|
82
|
+
|
|
83
|
+
""",
|
|
84
|
+
encoding='utf8',
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
manifest = Manifest.from_file(yaml_file)
|
|
88
|
+
manifest_rule = manifest.rules[0]
|
|
89
|
+
assert (
|
|
90
|
+
repr(manifest_rule.enable) == """[IfClause(stmt='IDF_TARGET == "esp32c3"', temporary=False, reason='None')]"""
|
|
91
|
+
)
|
|
92
|
+
assert (
|
|
93
|
+
repr(manifest_rule.depends_components)
|
|
94
|
+
== """SwitchClause(if_clauses=[IfClause(stmt='IDF_VERSION == "1.2.3" or IDF_VERSION_MAJOR == 4', temporary=False, reason=None), IfClause(stmt='CONFIG_NAME == "AAA"', temporary=False, reason=None)], contents=[['VVV'], ['AAA']], default_clause=['some_1', 'some_2', 'some_3'])""" # noqa
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
73
98
|
def test_manifest_switch_clause(tmp_path):
|
|
74
99
|
yaml_file = tmp_path / 'test.yml'
|
|
75
100
|
from idf_build_apps.constants import (
|
|
@@ -511,14 +536,6 @@ baz:
|
|
|
511
536
|
|
|
512
537
|
|
|
513
538
|
class TestIfParser:
|
|
514
|
-
def test_idf_version(self, monkeypatch):
|
|
515
|
-
monkeypatch.setattr(idf_build_apps.manifest.if_parser, 'IDF_VERSION', Version('5.9.0'))
|
|
516
|
-
statement = 'IDF_VERSION > "5.10.0"'
|
|
517
|
-
assert BOOL_STMT.parseString(statement)[0].get_value('esp32', 'foo') is False
|
|
518
|
-
|
|
519
|
-
statement = 'IDF_VERSION in ["5.9.0"]'
|
|
520
|
-
assert BOOL_STMT.parseString(statement)[0].get_value('esp32', 'foo') is True
|
|
521
|
-
|
|
522
539
|
def test_invalid_if_statement(self):
|
|
523
540
|
statement = '1'
|
|
524
541
|
with pytest.raises(InvalidIfClause, match='Invalid if clause: 1'):
|
|
@@ -527,11 +544,3 @@ class TestIfParser:
|
|
|
527
544
|
def test_temporary_must_with_reason(self):
|
|
528
545
|
with pytest.raises(InvalidIfClause, match='"reason" must be set when "temporary: true"'):
|
|
529
546
|
IfClause(stmt='IDF_TARGET == "esp32"', temporary=True)
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
def test_consecutive_or_and_stml_manifest():
|
|
533
|
-
with pytest.raises(InvalidIfClause, match='Chaining "and"/"or" is not allowed'):
|
|
534
|
-
IfClause(stmt='IDF_TARGET == "esp32" or IDF_TARGET == "esp32c3" or IDF_TARGET == "esp32s3"')
|
|
535
|
-
|
|
536
|
-
with pytest.raises(InvalidIfClause, match='Chaining "and"/"or" is not allowed'):
|
|
537
|
-
IfClause(stmt='IDF_TARGET == "esp32" or IDF_TARGET == "esp32c3" and IDF_TARGET == "esp32s3"')
|