idf-build-apps 1.0.0.dev1__tar.gz → 1.0.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 (52) hide show
  1. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/.github/workflows/test-build-idf-apps.yml +6 -4
  2. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/CHANGELOG.md +16 -2
  3. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/CONTRIBUTING.md +3 -2
  4. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/PKG-INFO +2 -1
  5. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/docs/find_build.md +8 -9
  6. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/docs/manifest.md +63 -6
  7. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/idf_build_apps/__init__.py +1 -1
  8. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/idf_build_apps/finder.py +7 -3
  9. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/idf_build_apps/main.py +37 -72
  10. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/idf_build_apps/manifest/if_parser.py +5 -0
  11. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/idf_build_apps/utils.py +13 -4
  12. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/pyproject.toml +1 -0
  13. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/setup.py +2 -1
  14. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/tests/test_build.py +17 -0
  15. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/tests/test_finder.py +83 -3
  16. idf_build_apps-1.0.1/tests/test_utils.py +136 -0
  17. idf_build_apps-1.0.0.dev1/tests/test_utils.py +0 -84
  18. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/.editorconfig +0 -0
  19. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/.git-blame-ignore-revs +0 -0
  20. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/.gitattributes +0 -0
  21. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/.github/workflows/check-pre-commit.yml +0 -0
  22. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/.github/workflows/issue_comment.yml +0 -0
  23. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/.github/workflows/new_issues.yml +0 -0
  24. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/.github/workflows/new_prs.yml +0 -0
  25. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/.github/workflows/publish-pypi.yml +0 -0
  26. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/.github/workflows/test-build-docs.yml +0 -0
  27. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/.gitignore +0 -0
  28. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/.pre-commit-config.yaml +0 -0
  29. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/.readthedocs.yml +0 -0
  30. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/LICENSE +0 -0
  31. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/README.md +0 -0
  32. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/docs/CHANGELOG.md +0 -0
  33. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/docs/CONTRIBUTING.md +0 -0
  34. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/docs/Makefile +0 -0
  35. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/docs/_static/espressif-logo.svg +0 -0
  36. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/docs/_static/theme_overrides.css +0 -0
  37. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/docs/_templates/layout.html +0 -0
  38. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/docs/api.rst +0 -0
  39. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/docs/conf.py +0 -0
  40. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/docs/config_file.md +0 -0
  41. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/docs/index.rst +0 -0
  42. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/idf_build_apps/__main__.py +0 -0
  43. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/idf_build_apps/app.py +0 -0
  44. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/idf_build_apps/config.py +0 -0
  45. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/idf_build_apps/constants.py +0 -0
  46. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/idf_build_apps/log.py +0 -0
  47. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/idf_build_apps/manifest/__init__.py +0 -0
  48. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/idf_build_apps/manifest/manifest.py +0 -0
  49. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/idf_build_apps/manifest/soc_header.py +0 -0
  50. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/license_header.txt +0 -0
  51. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/tests/conftest.py +0 -0
  52. {idf_build_apps-1.0.0.dev1 → idf_build_apps-1.0.1}/tests/test_manifest.py +0 -0
@@ -60,22 +60,24 @@ jobs:
60
60
  export PYENV_ROOT="$HOME/.pyenv" && export PATH="$PYENV_ROOT/bin:$PATH" && eval "$(pyenv init --path)"
61
61
  pyenv global ${{ matrix.python-version }}
62
62
  rm $(which python3)
63
+ echo "urllib3<1.25,>=1.21.1" >> $IDF_PATH/requirements.txt
63
64
  bash $IDF_PATH/install.sh
64
65
  . $IDF_PATH/export.sh
65
66
  pip install idf_build_apps-*-py2.py3-none-any.whl
66
67
  python -m idf_build_apps build -vv -t esp32 \
67
68
  -p $IDF_PATH/examples/get-started/hello_world \
68
69
  --size-file size_info.json \
69
- --ignore-warning-str "Python 3 versions older than 3.6 are not supported" \
70
- --ignore-warning-str "Python 2 is no longer supported" \
71
- --ignore-warning-str "Support for Python 2 is deprecated"
70
+ --ignore-warning-str \
71
+ "Python 3 versions older than 3.6 are not supported" \
72
+ "Python 2 is no longer supported" \
73
+ "Support for Python 2 is deprecated"
72
74
 
73
75
  build-apps-on-idf-env:
74
76
  if: ${{ github.ref == 'refs/heads/main' }}
75
77
  needs: build-python-packages
76
78
  strategy:
77
79
  matrix:
78
- idf-branch: [ release-v4.3, release-v4.4, release-v5.0]
80
+ idf-branch: [release-v4.3, release-v4.4, release-v5.0, release-v5.1]
79
81
  runs-on: ubuntu-latest
80
82
  container:
81
83
  image: espressif/idf:${{ matrix.idf-branch }}
@@ -2,11 +2,18 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
- ## [Unreleased - 1.0.0]
5
+ ## [1.0.1] (2023-06-12)
6
+
7
+ ## Fixed
8
+
9
+ - glob patterns are matched recursively
10
+
11
+ ## [1.0.0] (2023-05-25)
6
12
 
7
13
  ## Added
8
14
 
9
15
  - Support keyword `depends_filepatterns` in the manifest file
16
+ - Support expanding environment variables in the manifest files
10
17
 
11
18
  ## BREAKING CHANGES
12
19
 
@@ -23,6 +30,13 @@ All notable changes to this project will be documented in this file.
23
30
  - CLI Options Renamed
24
31
  - `--depends-on-components` renamed to `--modified-components`
25
32
  - `--depends-on-files` renamed to `--modified-files`
33
+ - `--ignore-components-dependencies-file-patterns` renamed to `--ignore-app-dependencies-filepatterns`
34
+ - Removed the deprecated CLI call methods, now these options only support space-separated list
35
+ - `--exclude`
36
+ - `--config`
37
+ - `--manifest-file`
38
+ - `--ignore-warning-str`
39
+ - `--default-build-targets`
26
40
 
27
41
  ## [0.6.1] (2023-05-10)
28
42
 
@@ -122,7 +136,7 @@ This is the last version to support ESP-IDF v4.1 since it's EOL on Feb. 24th, 20
122
136
 
123
137
  ### Fixed
124
138
 
125
- - Ralative path defined in the manifest files depend on the current work path
139
+ - Relative path defined in the manifest files depend on the current work path
126
140
 
127
141
  Added `manifest_rootpath` argument in `find_apps()`. Will use this value instead as the root folder for calculating absolute path
128
142
 
@@ -6,9 +6,10 @@ Please use python 3.7+ for developing, but keep in mind that we need to support
6
6
  |-----------------|---------------------------|
7
7
  | 4.1 | 2.7, 3.4+ |
8
8
  | 4.2 | 2.7, 3.4+ |
9
- | 4.3 | 3.6+ |
10
- | 4.4 | 3.6+ |
9
+ | 4.3 | 2.7, 3.4+ |
10
+ | 4.4 | 2.7, 3.4+ |
11
11
  | 5.0 | 3.7+ |
12
+ | 5.1 | 3.7+ |
12
13
  | master | 3.7+ |
13
14
 
14
15
  ## Setup the Dev Environment
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: idf-build-apps
3
- Version: 1.0.0.dev1
3
+ Version: 1.0.1
4
4
  Summary: Tools for building ESP-IDF related apps.
5
5
  Author-email: Fu Hanxi <fuhanxi@espressif.com>
6
6
  Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
@@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3.9
17
17
  Classifier: Programming Language :: Python :: 3.10
18
18
  Classifier: Programming Language :: Python :: 3.11
19
19
  Requires-Dist: pathlib; python_version < '3.4'
20
+ Requires-Dist: glob2; python_version < '3.5'
20
21
  Requires-Dist: pyparsing
21
22
  Requires-Dist: pyyaml
22
23
  Requires-Dist: packaging
@@ -59,6 +59,7 @@ flowchart TB
59
59
  end
60
60
  ```
61
61
 
62
+ (config-rules)=
62
63
  ### Config Rules
63
64
 
64
65
  Config rule represents the sdkconfig file pattern and the config name. The syntax is simple: `[FILE_PATTERN]=[CONFIG_NAME]`.
@@ -96,10 +97,10 @@ For example, in project `test-1`:
96
97
  - The wildcard matches two files. Build two apps based on each sdkconfig file.
97
98
  - - ``sdkconfig.ci.foo``
98
99
  - ``sdkconfig.ci.bar``
100
+ ```
99
101
 
100
- .. note::
101
-
102
- For each config rule, only one wildcard is supported.
102
+ ```{note}
103
+ For each config rule, only one wildcard is supported.
103
104
  ```
104
105
 
105
106
  ### Placeholders for Work Directory and Build Directory
@@ -114,7 +115,7 @@ By default, `idf-build-apps` would use the project directory as the work directo
114
115
 
115
116
  #### Build Directory
116
117
 
117
- Build directory is the directory where the binary files output would be generated. If it is set to a relative path, the full path would be calculated based on the work directory. If it is a absolute path, it would override the work directory settings.
118
+ Build directory is the directory where the binary files output would be generated. If it is set to a relative path, the full path would be calculated based on the work directory. If it is an absolute path, it would override the work directory settings.
118
119
 
119
120
  By default, `idf-build-apps` would follow what ESP-IDF does, use `build` as the build directory.
120
121
 
@@ -127,6 +128,7 @@ Placeholders are a set of symbols, which could be used when setting work directo
127
128
  - `@n`: Would be replaced by the project name.
128
129
  - `@f`: Would be replaced by the escaped project path (replaced "/" to "_").
129
130
  - `@i`: Would be replaced by the build index. (only available in `build` command)
131
+ - `@p`: Would be replaced by the parallel build index. (default to `1`, only available in `build` command)
130
132
 
131
133
  For example,
132
134
 
@@ -160,11 +162,8 @@ The output would be:
160
162
 
161
163
  Building apps is a process that build all the applications that are collected by the "finding apps" process.
162
164
 
163
- ```{eval-rst}
164
-
165
- .. note::
166
-
167
- Almost all CLI options that ``find`` supported are also supported in ``build`` command. You may call ``idf-build-apps find -h`` or ``idf-build-apps build -h`` for all possible CLI options.
165
+ ```{note}
166
+ Almost all CLI options that ``find`` supported are also supported in ``build`` command. You may call ``idf-build-apps find -h`` or ``idf-build-apps build -h`` for all possible CLI options.
168
167
  ```
169
168
 
170
169
  ### Tips on `build` CLI Options
@@ -23,12 +23,15 @@ One typical manifest file look like this:
23
23
 
24
24
  ### Operands
25
25
 
26
- - Variables start with `SOC_`. The value would be parsed from `IDF_PATH/components/soc/[TARGET]/include/soc/*_caps.h`
27
- - `IDF_TARGET`
28
- - `IDF_VERSION_MAJOR`
29
- - `IDF_VERSION_MINOR`
30
- - `IDF_VERSION_PATCH`
31
- - `INCLUDE_DEFAULT` (The default value of officially supported targets is 1, otherwise is 0)
26
+ - Capitalized Words
27
+ - Variables start with `SOC_`. The value would be parsed from `IDF_PATH/components/soc/[TARGET]/include/soc/*_caps.h`
28
+ - `IDF_TARGET`
29
+ - `IDF_VERSION_MAJOR`
30
+ - `IDF_VERSION_MINOR`
31
+ - `IDF_VERSION_PATCH`
32
+ - `INCLUDE_DEFAULT` (The default value of officially supported targets is 1, otherwise is 0)
33
+ - `CONFIG_NAME` (config name defined in [](project:#config-rules))
34
+ - environment variables, default to `0` if not set
32
35
  - String, must be double-quoted. e.g., `"esp32"`, `"12345"`
33
36
  - Integer, support decimal and hex. e.g., `1`, `0xAB`
34
37
  - List of strings or integers, or both types at the same time. e.g., `["esp32", 1]`
@@ -112,3 +115,57 @@ examples/get-started/blink:
112
115
  - if: INCLUDE_DEFAULT == 1 or IDF_TARGET == "linux"
113
116
  reason: This one supports all supported targets and linux
114
117
  ```
118
+
119
+ ## Check App Dependencies
120
+
121
+ `idf-build-apps` also supports building only related apps by checking app dependencies via modified components and modified files.
122
+
123
+ ### Basic Usage
124
+
125
+ To enable this feature, you need to declare the modified files or components using the CLI option:
126
+
127
+ - `--modified-files`
128
+ - `--modified-components`
129
+
130
+ To declare the dependencies for an app, you could add two more keywords in the corresponding manifest file:
131
+
132
+ - `depends_components`
133
+ - `depends_filepatterns`
134
+
135
+ One app will be built when:
136
+
137
+ - The app itself is modified (`.md` files are excluded)
138
+ - Any of the specified `depends_components` in the corresponding manifest file are modified
139
+ - Files that matches any of the specified `depends_filepatterns` in the corresponding manifest file are modified
140
+ - Any of the `build_components` are modified. `build_components` are defined in the `project_description.json`, which is generated by running `idf.py reconfigure` or `idf.py build`
141
+
142
+ For example, this is an app `example/foo`, which depends on `comp1`, `comp2`, `comp3` and all files under `common_header_files`:
143
+
144
+ ```yaml
145
+ examples/foo:
146
+ depends_components:
147
+ - comp1
148
+ - comp2
149
+ - comp3
150
+ depends_files:
151
+ - "common_header_files/**/*"
152
+ ```
153
+
154
+ This app will be built with the following CLI options:
155
+
156
+ - `--modified-files examples/foo/main/foo.c`
157
+ - `--modified-components comp1`
158
+ - `--modified-components comp2 comp3`
159
+ - `--modified-files common_header_files/foo.h`
160
+
161
+ This app will not be built with the following CLI options:
162
+
163
+ - `--modified-files examples/foo/main/foo.md`
164
+ - `--modified-components bar`
165
+ - `/tmp/foo.c`
166
+
167
+ ### Advanced Usage
168
+
169
+ Sometimes, we have some root dependencies. All apps should be built if these root dependencies are modified.
170
+
171
+ After adding `--ignore-app-dependencies-filepatterns` to the CLI options, if files that matches any of the specified patterns are modified, the check app dependency feature will be disabled.
@@ -7,7 +7,7 @@ Tools for building ESP-IDF related apps.
7
7
 
8
8
  import logging
9
9
 
10
- __version__ = '1.0.0.dev1'
10
+ __version__ = '1.0.1'
11
11
 
12
12
  LOGGER = logging.getLogger('idf_build_apps')
13
13
 
@@ -17,6 +17,7 @@ from .app import (
17
17
  )
18
18
  from .utils import (
19
19
  config_rules_from_str,
20
+ to_absolute_path,
20
21
  to_list,
21
22
  )
22
23
 
@@ -165,15 +166,18 @@ def _find_apps(
165
166
 
166
167
  # The remaining part is for recursive == True
167
168
  apps = []
169
+ # handle the exclude list, since the config file might use linux style, but run in windows
170
+ exclude_list = [to_absolute_path(p) for p in exclude_list]
168
171
  for root, dirs, _ in os.walk(path):
169
172
  LOGGER.debug('Entering %s', root)
170
- if root in exclude_list:
173
+ root_path = to_absolute_path(root)
174
+ if root_path in exclude_list:
171
175
  LOGGER.debug('=> Skipping %s (excluded)', root)
172
176
  del dirs[:]
173
177
  continue
174
178
 
175
- if root.endswith('managed_components'): # idf-component-manager
176
- LOGGER.debug('=> Skipping %s (managed components)', root)
179
+ if root_path.parts[-1] == 'managed_components': # idf-component-manager
180
+ LOGGER.debug('=> Skipping %s (managed components)', root_path)
177
181
  del dirs[:]
178
182
  continue
179
183
 
@@ -2,14 +2,12 @@
2
2
  # SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  import argparse
5
- import io
6
5
  import json
7
6
  import os
8
7
  import re
9
8
  import shutil
10
9
  import sys
11
10
  import textwrap
12
- import warnings
13
11
  from pathlib import (
14
12
  Path,
15
13
  )
@@ -55,22 +53,22 @@ def _check_app_dependency(
55
53
  manifest_rootpath, # type: str
56
54
  modified_components, # type: list[str] | None
57
55
  modified_files, # type: list[str] | None
58
- ignore_component_dependencies_file_patterns, # type: list[str] | None
56
+ ignore_app_dependencies_filepatterns, # type: list[str] | None
59
57
  ): # type: (...) -> bool
60
58
  # not check since modified_components and modified_files are not passed
61
59
  if modified_components is None and modified_files is None:
62
60
  return False
63
61
 
64
- # not check since ignore_component_dependencies_file_patterns is passed and matched
62
+ # not check since ignore_app_dependencies_filepatterns is passed and matched
65
63
  if (
66
- ignore_component_dependencies_file_patterns
64
+ ignore_app_dependencies_filepatterns
67
65
  and modified_files is not None
68
- and files_matches_patterns(modified_files, ignore_component_dependencies_file_patterns, manifest_rootpath)
66
+ and files_matches_patterns(modified_files, ignore_app_dependencies_filepatterns, manifest_rootpath)
69
67
  ):
70
68
  LOGGER.debug(
71
69
  'Skipping check component dependencies for apps since files %s matches patterns: %s',
72
70
  ', '.join(modified_files),
73
- ', '.join(ignore_component_dependencies_file_patterns),
71
+ ', '.join(ignore_app_dependencies_filepatterns),
74
72
  )
75
73
  return False
76
74
 
@@ -95,7 +93,7 @@ def find_apps(
95
93
  default_build_targets=None, # type: list[str] | str | None
96
94
  modified_components=None, # type: list[str] | str | None
97
95
  modified_files=None, # type: list[str] | str | None
98
- ignore_component_dependencies_file_patterns=None, # type: list[str] | str | None
96
+ ignore_app_dependencies_filepatterns=None, # type: list[str] | str | None
99
97
  sdkconfig_defaults=None, # type: str | None
100
98
  ): # type: (...) -> list[App]
101
99
  """
@@ -139,9 +137,9 @@ def find_apps(
139
137
  :type modified_components: list[str] | str | None
140
138
  :param modified_files: modified files
141
139
  :type modified_files: list[str] | str | None
142
- :param ignore_component_dependencies_file_patterns: file patterns that used for ignoring checking the component
140
+ :param ignore_app_dependencies_filepatterns: file patterns that used for ignoring checking the component
143
141
  dependencies
144
- :type ignore_component_dependencies_file_patterns: list[str] | str | None
142
+ :type ignore_app_dependencies_filepatterns: list[str] | str | None
145
143
  :param sdkconfig_defaults: semicolon-separated string, pass to idf.py -DSDKCONFIG_DEFAULTS if specified,
146
144
  also could be set via environment variables "SDKCONFIG_DEFAULTS"
147
145
  :type sdkconfig_defaults: str | None
@@ -166,7 +164,7 @@ def find_apps(
166
164
 
167
165
  modified_components = to_list(modified_components)
168
166
  modified_files = to_list(modified_files)
169
- ignore_component_dependencies_file_patterns = to_list(ignore_component_dependencies_file_patterns)
167
+ ignore_app_dependencies_filepatterns = to_list(ignore_app_dependencies_filepatterns)
170
168
 
171
169
  apps = []
172
170
  if target == 'all':
@@ -195,7 +193,7 @@ def find_apps(
195
193
  manifest_rootpath=manifest_rootpath,
196
194
  modified_components=modified_components,
197
195
  modified_files=modified_files,
198
- ignore_component_dependencies_file_patterns=ignore_component_dependencies_file_patterns,
196
+ ignore_app_dependencies_filepatterns=ignore_app_dependencies_filepatterns,
199
197
  ),
200
198
  modified_components=modified_components,
201
199
  modified_files=modified_files,
@@ -223,7 +221,7 @@ def build_apps(
223
221
  manifest_rootpath=None, # type: str | None
224
222
  modified_components=None, # type: list[str] | str | None
225
223
  modified_files=None, # type: list[str] | str | None
226
- ignore_component_dependencies_file_patterns=None, # type: list[str] | str | None
224
+ ignore_app_dependencies_filepatterns=None, # type: list[str] | str | None
227
225
  ): # type: (...) -> (int, list[App]) | int
228
226
  """
229
227
  Build all the specified apps
@@ -258,9 +256,9 @@ def build_apps(
258
256
  :type modified_components: list[str] | str | None
259
257
  :param modified_files: modified files
260
258
  :type modified_files: list[str] | str | None
261
- :param ignore_component_dependencies_file_patterns: file patterns that used for ignoring checking the component
259
+ :param ignore_app_dependencies_filepatterns: file patterns that used for ignoring checking the component
262
260
  dependencies
263
- :type ignore_component_dependencies_file_patterns: list[str] | str | None
261
+ :type ignore_app_dependencies_filepatterns: list[str] | str | None
264
262
  :return: (exit_code, built_apps) if specified ``modified_components``
265
263
  :rtype: int, list[App]
266
264
  :return: exit_code if not specified ``modified_components``
@@ -269,7 +267,7 @@ def build_apps(
269
267
  apps = to_list(apps) # type: list[App]
270
268
  modified_components = to_list(modified_components)
271
269
  modified_files = to_list(modified_files)
272
- ignore_component_dependencies_file_patterns = to_list(ignore_component_dependencies_file_patterns)
270
+ ignore_app_dependencies_filepatterns = to_list(ignore_app_dependencies_filepatterns)
273
271
 
274
272
  ignore_warnings_regexes = []
275
273
  if ignore_warning_strs:
@@ -300,27 +298,13 @@ def build_apps(
300
298
  app.parallel_count = parallel_count
301
299
 
302
300
  if collect_app_info:
303
- if isinstance(collect_app_info, io.TextIOWrapper):
304
- warnings.warn(
305
- '"collect_app_info" does not support file stream in idf-build-apps 1.0.0, Please use str instead',
306
- DeprecationWarning,
307
- )
308
- app._collect_app_info = collect_app_info.name
309
- else:
310
- app._collect_app_info = collect_app_info
301
+ app._collect_app_info = collect_app_info
311
302
 
312
303
  if app.collect_app_info not in collect_files:
313
304
  collect_files.append(app.collect_app_info)
314
305
 
315
306
  if collect_size_info:
316
- if isinstance(collect_size_info, io.TextIOWrapper):
317
- warnings.warn(
318
- '"collect_size_info" does not support file stream in idf-build-apps 1.0.0, Please use str instead',
319
- DeprecationWarning,
320
- )
321
- app._collect_size_info = collect_size_info.name
322
- else:
323
- app._collect_size_info = collect_size_info
307
+ app._collect_size_info = collect_size_info
324
308
 
325
309
  if app.collect_size_info not in collect_files:
326
310
  collect_files.append(app.collect_size_info)
@@ -352,7 +336,7 @@ def build_apps(
352
336
  modified_components=modified_components,
353
337
  modified_files=modified_files,
354
338
  check_app_dependencies=_check_app_dependency(
355
- manifest_rootpath, modified_components, modified_files, ignore_component_dependencies_file_patterns
339
+ manifest_rootpath, modified_components, modified_files, ignore_app_dependencies_filepatterns
356
340
  ),
357
341
  )
358
342
  except BuildError as e:
@@ -468,15 +452,7 @@ class IdfBuildAppsCliFormatter(argparse.HelpFormatter):
468
452
  else:
469
453
  default_type = type(action.default)
470
454
 
471
- if isinstance(action, argparse._AppendAction): # noqa
472
- _help += (
473
- '. Could be specified for multiple times'
474
- '{} ! DeprecationWarning: will change to space-separated list in idf-build-apps 1.0.0 version'.format(
475
- self.LINE_SEP
476
- )
477
- )
478
- _type = 'list[{}]'.format(default_type.__name__)
479
- elif action.nargs in [argparse.ZERO_OR_MORE, argparse.ONE_OR_MORE]:
455
+ if action.nargs in [argparse.ZERO_OR_MORE, argparse.ONE_OR_MORE]:
480
456
  _type = 'list[{}]'.format(default_type.__name__)
481
457
  else:
482
458
  _type = default_type.__name__
@@ -522,11 +498,7 @@ def get_parser(): # type: () -> argparse.ArgumentParser
522
498
  action='store_true',
523
499
  help='Look for apps in the specified paths recursively',
524
500
  )
525
- common_args.add_argument(
526
- '--exclude',
527
- action='append',
528
- help='Ignore specified directory (if --recursive is given)',
529
- )
501
+ common_args.add_argument('--exclude', nargs='+', help='Ignore specified path (if --recursive is given)')
530
502
  common_args.add_argument(
531
503
  '--work-dir',
532
504
  help='If set, the app is first copied into the specified directory, and then built. '
@@ -548,7 +520,7 @@ def get_parser(): # type: () -> argparse.ArgumentParser
548
520
  )
549
521
  common_args.add_argument(
550
522
  '--config',
551
- action='append',
523
+ nargs='+',
552
524
  help='Adds configurations (sdkconfig file names) to build. '
553
525
  'This can either be FILENAME[=NAME] or FILEPATTERN. FILENAME is the name of the sdkconfig file, '
554
526
  'relative to the project directory, to be used. Optional NAME can be specified, '
@@ -578,7 +550,7 @@ def get_parser(): # type: () -> argparse.ArgumentParser
578
550
  )
579
551
  common_args.add_argument(
580
552
  '--manifest-file',
581
- action='append',
553
+ nargs='+',
582
554
  help='Manifest files which specify the build test rules of the apps',
583
555
  )
584
556
  common_args.add_argument(
@@ -590,10 +562,7 @@ def get_parser(): # type: () -> argparse.ArgumentParser
590
562
  '--default-build-targets',
591
563
  nargs='+',
592
564
  help='space-separated list of supported targets. Targets supported in current ESP-IDF branch '
593
- '(except preview ones) would be used if this option is not set.'
594
- '{} ! DeprecationWarning: comma-separated list support will be removed in idf-build-apps 1.0.0 version'.format(
595
- IdfBuildAppsCliFormatter.LINE_SEP
596
- ),
565
+ '(except preview ones) would be used if this option is not set.',
597
566
  )
598
567
  common_args.add_argument(
599
568
  '--modified-components',
@@ -612,13 +581,12 @@ def get_parser(): # type: () -> argparse.ArgumentParser
612
581
  )
613
582
  common_args.add_argument(
614
583
  '-if',
615
- '--ignore-component-dependencies-file-patterns',
584
+ '--ignore-app-dependencies-filepatterns',
616
585
  nargs='*',
617
586
  default=None,
618
- help='space-separated list which specifies the file patterns used for ignoring the component dependencies. '
619
- 'The `depends_components` and `depends_filepatterns` set in the manifest files will be ignored when any of '
620
- 'the specified file patterns matches any of the modified files. Must be used together with '
621
- '--modified-files',
587
+ help='space-separated list which specifies the file patterns used for ignoring checking the app dependencies. '
588
+ 'The `depends_components` and `depends_filepatterns` set in the manifest files will be ignored when any of the '
589
+ 'specified file patterns matches any of the modified files. Must be used together with --modified-files',
622
590
  )
623
591
 
624
592
  common_args.add_argument(
@@ -675,7 +643,7 @@ def get_parser(): # type: () -> argparse.ArgumentParser
675
643
  )
676
644
  build_parser.add_argument(
677
645
  '--ignore-warning-str',
678
- action='append',
646
+ nargs='+',
679
647
  help='Ignore the warning string that match the specified regex in the build output',
680
648
  )
681
649
  build_parser.add_argument(
@@ -712,20 +680,17 @@ def validate_args(parser, args): # type: (argparse.ArgumentParser, argparse.Nam
712
680
  default_build_targets = []
713
681
  if args.default_build_targets:
714
682
  for target in args.default_build_targets:
715
- t_list = [_t.strip() for _t in target.split(',')] if ',' in target else [target.strip()]
716
- for _t in t_list:
717
- if _t not in ALL_TARGETS:
718
- raise InvalidCommand(
719
- 'Unrecognizable target {} specified with "--default-build-targets". '
720
- 'Current ESP-IDF available targets: {}'.format(_t, ALL_TARGETS)
721
- )
722
-
723
- if _t not in default_build_targets:
724
- default_build_targets.append(_t)
683
+ if target not in ALL_TARGETS:
684
+ raise InvalidCommand(
685
+ 'Unrecognizable target {} specified with "--default-build-targets". '
686
+ 'Current ESP-IDF available targets: {}'.format(target, ALL_TARGETS)
687
+ )
725
688
 
689
+ if target not in default_build_targets:
690
+ default_build_targets.append(target)
726
691
  args.default_build_targets = default_build_targets
727
692
 
728
- if args.ignore_component_dependencies_file_patterns:
693
+ if args.ignore_app_dependencies_filepatterns:
729
694
  if args.modified_files is None:
730
695
  raise InvalidCommand(
731
696
  'Must specify "--ignore-component-dependencies-file-patterns" with "--modified-files", '
@@ -767,7 +732,7 @@ def main():
767
732
  default_build_targets=args.default_build_targets,
768
733
  modified_components=args.modified_components,
769
734
  modified_files=args.modified_files,
770
- ignore_component_dependencies_file_patterns=args.ignore_component_dependencies_file_patterns,
735
+ ignore_app_dependencies_filepatterns=args.ignore_app_dependencies_filepatterns,
771
736
  sdkconfig_defaults=args.sdkconfig_defaults,
772
737
  )
773
738
 
@@ -801,7 +766,7 @@ def main():
801
766
  manifest_rootpath=args.manifest_rootpath,
802
767
  modified_components=args.modified_components,
803
768
  modified_files=args.modified_files,
804
- ignore_component_dependencies_file_patterns=args.ignore_component_dependencies_file_patterns,
769
+ ignore_app_dependencies_filepatterns=args.ignore_app_dependencies_filepatterns,
805
770
  )
806
771
 
807
772
  if args.modified_components is not None:
@@ -1,6 +1,7 @@
1
1
  # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
2
2
  # SPDX-License-Identifier: Apache-2.0
3
3
 
4
+ import os
4
5
  from ast import (
5
6
  literal_eval,
6
7
  )
@@ -86,6 +87,10 @@ class ChipAttr(Stmt):
86
87
  if self.attr in SOC_HEADERS[target]:
87
88
  return SOC_HEADERS[target][self.attr]
88
89
 
90
+ # for non-keyword cap words, check if it is defined in the environment variables
91
+ if self.attr in os.environ:
92
+ return os.environ[self.attr]
93
+
89
94
  return 0 # default return 0 as false
90
95
 
91
96
 
@@ -23,6 +23,12 @@ except ImportError:
23
23
  pass
24
24
 
25
25
 
26
+ if sys.version_info < (3, 5):
27
+ import glob2 as glob
28
+ else:
29
+ import glob
30
+
31
+
26
32
  class ConfigRule:
27
33
  def __init__(self, file_name, config_name): # type: (str, str) -> None
28
34
  """
@@ -213,14 +219,17 @@ def files_matches_patterns(
213
219
  patterns, # type: list[str] | str
214
220
  rootpath=None, # type: str
215
221
  ): # type: (...) -> bool
216
- # can't match a absolute pattern with a relative path
222
+ # can't match an absolute pattern with a relative path
217
223
  # change all to absolute paths
218
224
  files = [to_absolute_path(f, rootpath) for f in to_list(files)]
219
225
  patterns = [to_absolute_path(p, rootpath) for p in to_list(patterns)]
220
226
 
227
+ matched_paths = set()
228
+ for pat in patterns:
229
+ matched_paths.update(glob.glob(str(pat), recursive=True))
230
+
221
231
  for f in files:
222
- for p in patterns:
223
- if f.match(str(p)):
224
- return True
232
+ if str(f) in matched_paths:
233
+ return True
225
234
 
226
235
  return False
@@ -27,6 +27,7 @@ requires-python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
27
27
 
28
28
  dependencies = [
29
29
  "pathlib; python_version < '3.4'",
30
+ "glob2; python_version < '3.5'",
30
31
  "pyparsing",
31
32
  "pyyaml",
32
33
  "packaging",
@@ -15,6 +15,7 @@ install_requires = \
15
15
  extras_require = \
16
16
  {":python_version < '3.11'": ['toml'],
17
17
  ":python_version < '3.4'": ['pathlib'],
18
+ ":python_version < '3.5'": ['glob2'],
18
19
  'doc': ['sphinx',
19
20
  'sphinx-rtd-theme',
20
21
  'sphinx_copybutton',
@@ -26,7 +27,7 @@ entry_points = \
26
27
  {'console_scripts': ['idf-build-apps = idf_build_apps:main.main']}
27
28
 
28
29
  setup(name='idf-build-apps',
29
- version='1.0.0.dev1',
30
+ version='1.0.1',
30
31
  description='Tools for building ESP-IDF related apps.',
31
32
  author=None,
32
33
  author_email='Fu Hanxi <fuhanxi@espressif.com>',
@@ -4,6 +4,9 @@ import shutil
4
4
 
5
5
  import pytest
6
6
 
7
+ from idf_build_apps import (
8
+ find_apps,
9
+ )
7
10
  from idf_build_apps.app import (
8
11
  CMakeApp,
9
12
  )
@@ -74,6 +77,20 @@ class TestBuild:
74
77
 
75
78
  assert built == is_built
76
79
 
80
+ def test_build_without_modified_components_but_ignored_app_dependency_check(self):
81
+ test_dir = str(IDF_PATH / 'examples' / 'get-started' / 'hello_world')
82
+
83
+ apps = find_apps(
84
+ test_dir,
85
+ 'esp32',
86
+ modified_components=[],
87
+ modified_files=['foo.c'],
88
+ ignore_app_dependencies_filepatterns=['foo.c'],
89
+ )
90
+
91
+ for app in apps:
92
+ assert app.build()
93
+
77
94
 
78
95
  @pytest.mark.skipif(not shutil.which('idf.py'), reason='idf.py not found')
79
96
  def test_idf_version_keywords_type():
@@ -3,6 +3,7 @@
3
3
 
4
4
  import logging
5
5
  import os
6
+ import tempfile
6
7
  from pathlib import (
7
8
  Path,
8
9
  )
@@ -185,9 +186,8 @@ get-started:
185
186
  @pytest.mark.parametrize(
186
187
  'modified_components, modified_files, could_find_apps',
187
188
  [
188
- ([], '/foo', True),
189
189
  ([], str(IDF_PATH / 'examples' / 'README.md'), False),
190
- (None, [str(IDF_PATH / 'examples' / 'get-started' / 'hello_world' / 'a.md')], True),
190
+ (None, [str(IDF_PATH / 'examples' / 'get-started' / 'hello_world' / 'a.md')], False),
191
191
  (
192
192
  [],
193
193
  [
@@ -208,7 +208,6 @@ get-started:
208
208
  f'''
209
209
  {test_dir}:
210
210
  depends_filepatterns:
211
- - /foo
212
211
  - examples/get-started/hello_world/**
213
212
  - examples/foo/**
214
213
  ''',
@@ -417,3 +416,84 @@ class TestFindWithSdkconfigFiles:
417
416
  assert apps[0].sdkconfig_files == [
418
417
  str(tmp_path / 'test1' / 'sdkconfig.defaults'),
419
418
  ]
419
+
420
+ def test_env_var(self, tmp_path, monkeypatch):
421
+ create_project('test1', tmp_path)
422
+
423
+ (tmp_path / 'test1' / 'sdkconfig.ci.foo').touch()
424
+ (tmp_path / 'test1' / 'sdkconfig.ci.bar').touch()
425
+ (tmp_path / 'test1' / 'sdkconfig.ci.baz').touch()
426
+
427
+ yaml_file = tmp_path / 'test.yml'
428
+ yaml_file.write_text(
429
+ f'''
430
+ {tmp_path}:
431
+ enable:
432
+ - if: CONFIG_NAME == "foo" and IDF_TARGET == "esp32"
433
+ - if: CONFIG_NAME == "bar" and IDF_TARGET == "esp32s2"
434
+ - if: TEST_ENV_VAR == "1"
435
+ - if: CONFIG_NAME == "baz" and TEST_ENV_VAR == 0
436
+ ''',
437
+ encoding='utf8',
438
+ )
439
+
440
+ # in case you set it...
441
+ monkeypatch.delenv('CONFIG_NAME', raising=False)
442
+ monkeypatch.delenv('TEST_ENV_VAR', raising=False)
443
+
444
+ # CONFIG_NAME should NOT be overridden by env var
445
+ monkeypatch.setenv('CONFIG_NAME', 'bar')
446
+ apps = find_apps(
447
+ str(tmp_path / 'test1'),
448
+ 'esp32',
449
+ config_rules_str=['sdkconfig.ci=default', 'sdkconfig.ci.*='],
450
+ manifest_files=yaml_file,
451
+ )
452
+ assert len(apps) == 2
453
+ assert apps[0].sdkconfig_files == [
454
+ str(tmp_path / 'test1' / 'sdkconfig.ci.baz'),
455
+ ]
456
+ assert apps[1].sdkconfig_files == [
457
+ str(tmp_path / 'test1' / 'sdkconfig.ci.foo'),
458
+ ]
459
+ monkeypatch.delenv('CONFIG_NAME')
460
+
461
+ # env var should be expanded
462
+ monkeypatch.setenv('TEST_ENV_VAR', '1')
463
+ apps = find_apps(
464
+ str(tmp_path / 'test1'),
465
+ 'esp32',
466
+ config_rules_str=['sdkconfig.ci=default', 'sdkconfig.ci.*='],
467
+ manifest_files=yaml_file,
468
+ )
469
+ assert len(apps) == 3
470
+ monkeypatch.delenv('TEST_ENV_VAR')
471
+
472
+
473
+ @pytest.mark.parametrize(
474
+ 'exclude_list, apps_count',
475
+ [
476
+ (['test1'], 3), # not excluded
477
+ (['folder1/test2'], 2),
478
+ (['folder1'], 1),
479
+ (['folder2/test2'], 2),
480
+ ],
481
+ )
482
+ def test_find_apps_with_exclude(tmp_path, exclude_list, apps_count):
483
+ (tmp_path / 'folder1').mkdir()
484
+ (tmp_path / 'folder2').mkdir()
485
+
486
+ create_project('test1', tmp_path / 'folder1')
487
+ create_project('test2', tmp_path / 'folder1')
488
+ create_project('test2', tmp_path / 'folder2')
489
+
490
+ os.chdir(tmp_path)
491
+ apps = find_apps(str(tmp_path), 'esp32', recursive=True, exclude_list=exclude_list)
492
+ assert len(apps) == apps_count
493
+
494
+ # or with absolute_path
495
+ exclude_list = [os.path.abspath(x) for x in exclude_list]
496
+ tmp_path = os.path.abspath(tmp_path)
497
+ os.chdir(tempfile.tempdir)
498
+ apps = find_apps(str(tmp_path), 'esp32', recursive=True, exclude_list=exclude_list)
499
+ assert len(apps) == apps_count
@@ -0,0 +1,136 @@
1
+ # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ import os
4
+ from pathlib import (
5
+ Path,
6
+ )
7
+
8
+ import pytest
9
+
10
+ from idf_build_apps.utils import (
11
+ files_matches_patterns,
12
+ get_parallel_start_stop,
13
+ rmdir,
14
+ to_absolute_path,
15
+ )
16
+
17
+
18
+ @pytest.mark.parametrize(
19
+ 'patterns, expected',
20
+ [
21
+ ('*.txt', ['test/inner', 'test/inner/test.txt', 'test/test.txt']),
22
+ (
23
+ ['*.txt', '*.log'],
24
+ [
25
+ 'test/inner',
26
+ 'test/inner/build.log',
27
+ 'test/inner/test.txt',
28
+ 'test/test.txt',
29
+ ],
30
+ ),
31
+ ],
32
+ )
33
+ def test_rmdir(tmpdir, patterns, expected):
34
+ test_dir = tmpdir.mkdir('test')
35
+ dir1 = test_dir.mkdir('inner')
36
+ test_dir.mkdir('inner2')
37
+
38
+ Path(dir1 / 'test.txt').touch()
39
+ Path(dir1 / 'build.log').touch()
40
+ Path(test_dir / 'test.txt').touch()
41
+
42
+ rmdir(test_dir, exclude_file_patterns=patterns)
43
+
44
+ assert sorted(Path(test_dir).glob('**/*')) == [Path(tmpdir / i) for i in expected]
45
+
46
+
47
+ @pytest.mark.parametrize(
48
+ 'total, parallel_count, parallel_index, start, stop',
49
+ [
50
+ (1, 1, 1, 1, 1),
51
+ (1, 2, 2, 2, 1),
52
+ (1, 10, 1, 1, 1),
53
+ (6, 4, 1, 1, 2),
54
+ (6, 4, 2, 3, 4),
55
+ (6, 4, 3, 5, 6),
56
+ (6, 4, 4, 7, 6),
57
+ (10, 10, 9, 9, 9),
58
+ (33, 2, 1, 1, 17),
59
+ (33, 2, 2, 18, 33),
60
+ ],
61
+ )
62
+ def test_get_parallel_start_stop(total, parallel_count, parallel_index, start, stop):
63
+ assert (start, stop) == get_parallel_start_stop(total, parallel_count, parallel_index)
64
+
65
+
66
+ def test_files_matches_patterns(tmpdir):
67
+ # used for testing absolute paths
68
+ temp_dir = tmpdir.mkdir('temp')
69
+ os.chdir(temp_dir)
70
+
71
+ # create real files
72
+ test_dir = tmpdir.mkdir('test')
73
+ a_dir = test_dir.mkdir('a')
74
+ b_dir = a_dir.mkdir('b')
75
+ c_dir = b_dir.mkdir('c')
76
+ b_py = Path(a_dir / 'b.py')
77
+ c_py = Path(b_dir / 'c.py')
78
+ d_py = Path(c_dir / 'd.py')
79
+ b_py.touch()
80
+ c_py.touch()
81
+ d_py.touch()
82
+
83
+ # ├── temp
84
+ # └── test
85
+ # └── a
86
+ # ├── b
87
+ # │ ├── c
88
+ # │ │ └── d.py
89
+ # │ └── c.py
90
+ # ├── .hidden
91
+ # └── b.py
92
+ #
93
+
94
+ # in correct relative path
95
+ for matched_files, pat, rootpath in [
96
+ ([b_py], '*.py', a_dir),
97
+ ([b_py, c_py, d_py], '**/*.py', a_dir),
98
+ ([c_py], '*.py', b_dir),
99
+ ([c_py, d_py], '**/*.py', b_dir),
100
+ ([d_py], '*.py', c_dir),
101
+ ([d_py], '**/*.py', c_dir),
102
+ ]:
103
+ for f in matched_files:
104
+ assert files_matches_patterns(f, pat, rootpath)
105
+
106
+ # in None root path with relative pattern
107
+ for matched_files, pat in [
108
+ ([b_py], 'a/*.py'),
109
+ ([b_py, c_py, d_py], 'a/**/*.py'),
110
+ ([c_py], 'a/b/*.py'),
111
+ ([c_py, d_py], 'a/b/**/*.py'),
112
+ ([d_py], 'a/b/c/*.py'),
113
+ ([d_py], 'a/b/c/**/*.py'),
114
+ ]:
115
+ for f in matched_files:
116
+ # with correct pwd
117
+ os.chdir(test_dir)
118
+ assert files_matches_patterns(f, pat)
119
+
120
+ # with wrong pwd
121
+ os.chdir(temp_dir)
122
+ assert not files_matches_patterns(f, pat)
123
+
124
+ # use correct absolute path, in wrong pwd
125
+ for matched_files, pat in [
126
+ ([b_py], 'a/*.py'),
127
+ ([b_py, c_py, d_py], 'a/**/*.py'),
128
+ ([c_py], 'a/b/*.py'),
129
+ ([c_py, d_py], 'a/b/**/*.py'),
130
+ ([d_py], 'a/b/c/*.py'),
131
+ ([d_py], 'a/b/c/**/*.py'),
132
+ ]:
133
+ abs_pat = to_absolute_path(pat, test_dir)
134
+ os.chdir(temp_dir)
135
+ for f in matched_files:
136
+ assert files_matches_patterns(f, abs_pat)
@@ -1,84 +0,0 @@
1
- # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
2
- # SPDX-License-Identifier: Apache-2.0
3
-
4
- from pathlib import (
5
- Path,
6
- )
7
-
8
- import pytest
9
-
10
- from idf_build_apps.utils import (
11
- files_matches_patterns,
12
- get_parallel_start_stop,
13
- rmdir,
14
- )
15
-
16
-
17
- @pytest.mark.parametrize(
18
- 'patterns, expected',
19
- [
20
- ('*.txt', ['test/inner', 'test/inner/test.txt', 'test/test.txt']),
21
- (
22
- ['*.txt', '*.log'],
23
- [
24
- 'test/inner',
25
- 'test/inner/build.log',
26
- 'test/inner/test.txt',
27
- 'test/test.txt',
28
- ],
29
- ),
30
- ],
31
- )
32
- def test_rmdir(tmpdir, patterns, expected):
33
- test_dir = tmpdir.mkdir('test')
34
- dir1 = test_dir.mkdir('inner')
35
- test_dir.mkdir('inner2')
36
-
37
- Path(dir1 / 'test.txt').touch()
38
- Path(dir1 / 'build.log').touch()
39
- Path(test_dir / 'test.txt').touch()
40
-
41
- rmdir(test_dir, exclude_file_patterns=patterns)
42
-
43
- assert sorted(Path(test_dir).glob('**/*')) == [Path(tmpdir / i) for i in expected]
44
-
45
-
46
- @pytest.mark.parametrize(
47
- 'total, parallel_count, parallel_index, start, stop',
48
- [
49
- (1, 1, 1, 1, 1),
50
- (1, 2, 2, 2, 1),
51
- (1, 10, 1, 1, 1),
52
- (6, 4, 1, 1, 2),
53
- (6, 4, 2, 3, 4),
54
- (6, 4, 3, 5, 6),
55
- (6, 4, 4, 7, 6),
56
- (10, 10, 9, 9, 9),
57
- (33, 2, 1, 1, 17),
58
- (33, 2, 2, 18, 33),
59
- ],
60
- )
61
- def test_get_parallel_start_stop(total, parallel_count, parallel_index, start, stop):
62
- assert (start, stop) == get_parallel_start_stop(total, parallel_count, parallel_index)
63
-
64
-
65
- @pytest.mark.parametrize(
66
- 'files, patterns, rootpath, result',
67
- [
68
- ('c.py', '*.py', None, True),
69
- ('c.py', '*.py', '/a', True),
70
- ('/a/b/c.py', 'c.py', None, False),
71
- ('/a/b/c.py', 'c.py', '/a/b', True),
72
- ('/a/b/../b/c.py', '*.py', None, False),
73
- ('/a/b/../b/c.py', '*.py', '/a/b', True),
74
- ('/a/b/../b/c.py', '**/*.py', None, False),
75
- ('/a/b/../b/c.py', '**/*.py', '/a', True),
76
- ('c.py', '/a/**/*.py', None, False),
77
- ('c.py', '/a/**/*.py', '/a', False),
78
- ('c.py', '/a/**/*.py', '/a/b', True),
79
- ('/a/b/c.py', '/a/**/*.py', None, True),
80
- ('/a/b/c.py', '/a/**/*.py', 'foo', True),
81
- ],
82
- )
83
- def test_files_matches_patterns(files, patterns, rootpath, result):
84
- assert files_matches_patterns(files, patterns, rootpath) == result