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.
Files changed (78) hide show
  1. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.github/workflows/publish-pypi.yml +3 -3
  2. idf_build_apps-2.6.1/.github/workflows/sync-jira.yml +61 -0
  3. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.github/workflows/test-build-docs.yml +1 -1
  4. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.github/workflows/test-build-idf-apps.yml +1 -1
  5. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.pre-commit-config.yaml +1 -0
  6. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/CHANGELOG.md +6 -0
  7. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/PKG-INFO +2 -1
  8. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/__init__.py +1 -1
  9. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/args.py +25 -12
  10. idf_build_apps-2.6.1/idf_build_apps/constants.py +77 -0
  11. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/main.py +7 -5
  12. idf_build_apps-2.6.1/idf_build_apps/manifest/__init__.py +17 -0
  13. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/manifest/manifest.py +16 -8
  14. idf_build_apps-2.6.1/idf_build_apps/manifest/soc_header.py +6 -0
  15. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/vendors/pydantic_sources.py +3 -1
  16. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/pyproject.toml +5 -1
  17. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/setup.py +3 -2
  18. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/conftest.py +5 -5
  19. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/test_args.py +38 -1
  20. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/test_manifest.py +32 -23
  21. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/test_utils.py +1 -15
  22. idf_build_apps-2.6.0/.github/workflows/issue_comment.yml +0 -20
  23. idf_build_apps-2.6.0/.github/workflows/new_issues.yml +0 -20
  24. idf_build_apps-2.6.0/.github/workflows/new_prs.yml +0 -25
  25. idf_build_apps-2.6.0/idf_build_apps/constants.py +0 -122
  26. idf_build_apps-2.6.0/idf_build_apps/manifest/__init__.py +0 -6
  27. idf_build_apps-2.6.0/idf_build_apps/manifest/if_parser.py +0 -240
  28. idf_build_apps-2.6.0/idf_build_apps/manifest/soc_header.py +0 -141
  29. idf_build_apps-2.6.0/tests/test_soc_caps.py +0 -21
  30. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.editorconfig +0 -0
  31. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.git-blame-ignore-revs +0 -0
  32. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.gitattributes +0 -0
  33. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.github/dependabot.yml +0 -0
  34. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.github/workflows/check-pre-commit.yml +0 -0
  35. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.gitignore +0 -0
  36. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/.readthedocs.yml +0 -0
  37. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/CONTRIBUTING.md +0 -0
  38. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/LICENSE +0 -0
  39. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/README.md +0 -0
  40. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/_apidoc_templates/module.rst_t +0 -0
  41. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/_apidoc_templates/package.rst_t +0 -0
  42. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/_apidoc_templates/toc.rst_t +0 -0
  43. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/_static/espressif-logo.svg +0 -0
  44. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/_static/theme_overrides.css +0 -0
  45. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/_templates/layout.html +0 -0
  46. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/conf_common.py +0 -0
  47. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/Makefile +0 -0
  48. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/conf.py +0 -0
  49. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/explanations/build.rst +0 -0
  50. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/explanations/config_rules.rst +0 -0
  51. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/explanations/dependency_driven_build.rst +0 -0
  52. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/explanations/find.rst +0 -0
  53. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/guides/1.x_to_2.x.md +0 -0
  54. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/index.rst +0 -0
  55. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/others/CHANGELOG.md +0 -0
  56. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/others/CONTRIBUTING.md +0 -0
  57. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/references/cli.rst +0 -0
  58. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/references/config_file.rst +0 -0
  59. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/docs/en/references/manifest.rst +0 -0
  60. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/__main__.py +0 -0
  61. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/app.py +0 -0
  62. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/autocompletions.py +0 -0
  63. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/finder.py +0 -0
  64. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/junit/__init__.py +0 -0
  65. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/junit/report.py +0 -0
  66. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/junit/utils.py +0 -0
  67. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/log.py +0 -0
  68. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/py.typed +0 -0
  69. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/session_args.py +0 -0
  70. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/utils.py +0 -0
  71. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/vendors/__init__.py +0 -0
  72. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/yaml/__init__.py +0 -0
  73. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/idf_build_apps/yaml/parser.py +0 -0
  74. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/license_header.txt +0 -0
  75. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/test_app.py +0 -0
  76. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/test_build.py +0 -0
  77. {idf_build_apps-2.6.0 → idf_build_apps-2.6.1}/tests/test_cmd.py +0 -0
  78. {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
- - 'v*'
6
+ - "v*"
7
7
 
8
8
  jobs:
9
9
  deploy:
10
- runs-on: ubuntu-latest
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: '3.7'
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 }}
@@ -5,7 +5,7 @@ on:
5
5
 
6
6
  jobs:
7
7
  build-docs:
8
- runs-on: ubuntu-latest
8
+ runs-on: ubuntu-22.04
9
9
  steps:
10
10
  - uses: actions/checkout@v4
11
11
  - name: Set up Python
@@ -17,7 +17,7 @@ defaults:
17
17
 
18
18
  jobs:
19
19
  build-python-packages:
20
- runs-on: ubuntu-latest
20
+ runs-on: ubuntu-22.04
21
21
  steps:
22
22
  - uses: actions/checkout@v4
23
23
  - uses: actions/setup-python@v5
@@ -37,6 +37,7 @@ repos:
37
37
  - types-toml
38
38
  - pytest
39
39
  - argcomplete>=3
40
+ - esp-bool-parser>=0.1.2,<1
40
41
  - repo: https://github.com/hfudev/rstfmt
41
42
  rev: v0.1.4
42
43
  hooks:
@@ -2,6 +2,12 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## v2.6.1 (2025-01-13)
6
+
7
+ ### Fix
8
+
9
+ - --config-file not refreshed
10
+
5
11
  ## v2.6.0 (2025-01-02)
6
12
 
7
13
  ### Feat
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: idf-build-apps
3
- Version: 2.6.0
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"
@@ -8,7 +8,7 @@ Tools for building ESP-IDF related apps.
8
8
  # ruff: noqa: E402
9
9
  # avoid circular imports
10
10
 
11
- __version__ = '2.6.0'
11
+ __version__ = '2.6.1'
12
12
 
13
13
  from .session_args import (
14
14
  SessionArgs,
@@ -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
- return (
136
- init_settings,
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 config_file:
882
- BaseArguments.model_config['toml_file'] = str(config_file)
883
- # modify all subclasses
886
+ if reset:
887
+ BaseArguments.CONFIG_FILE_PATH = None
884
888
  for cls in _subclasses(BaseArguments):
885
- cls.model_config['toml_file'] = str(config_file)
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-2024 Espressif Systems (Shanghai) CO LTD
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
- apply_config_file(config_file)
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
- apply_config_file(config_file)
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
- apply_config_file(config_file)
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-2024 Espressif Systems (Shanghai) CO LTD
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 = BOOL_EXPR.parseString(stmt)[0]
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(pickle.dumps(obj, protocol=4)) # protocol 4 by default is set in Python 3.8
164
+ sha.update(repr(obj).encode())
157
165
 
158
166
  return sha.hexdigest()
159
167
 
@@ -0,0 +1,6 @@
1
+ # SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ import esp_bool_parser
5
+
6
+ SOC_HEADERS = esp_bool_parser.SOC_HEADERS
@@ -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
- return provided.resolve()
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.0"
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.0',
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-2024 Espressif Systems (Shanghai) CO LTD
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 IDF_BUILD_APPS_TOML_FN, SUPPORTED_TARGETS
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(IDF_BUILD_APPS_TOML_FN)
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
- == '6fd3175a5068c46bccc411efadf3b98314210e775c25c62833998bff8b0cf1bc1daf738326f138f0d6629caa07338428f2aa122e2b830e6ad43662057c7ea0b1' # noqa: E501
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
- == 'f3408e9bf1d6b9a9e14559e6567917986678a3414229b29f96493aec4dc1bc3e6d0ecc4f79adced0d5c26bc1cd80a4d15fe6aaefa5d1e7033a58290374f4fc7f' # noqa: E501
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-2024 Espressif Systems (Shanghai) CO LTD
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"')