Merge branch 'release/v6.1.17'

This commit is contained in:
Ivan Kravets
2025-02-13 13:08:40 +02:00
39 changed files with 194 additions and 169 deletions

View File

@ -8,7 +8,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest] os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.11", "3.12", "3.13.0-rc.2"] python-version: ["3.11", "3.12", "3.13"]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
@ -27,6 +27,12 @@ jobs:
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install tox pip install tox
- name: Run "codespell" on Linux
if: startsWith(matrix.os, 'ubuntu')
run: |
python -m pip install codespell
make codespell
- name: Core System Info - name: Core System Info
run: | run: |
tox -e py tox -e py

View File

@ -11,7 +11,7 @@ jobs:
with: with:
submodules: "recursive" submodules: "recursive"
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v4 uses: actions/setup-python@v5
with: with:
python-version: "3.11" python-version: "3.11"
- name: Install dependencies - name: Install dependencies
@ -40,7 +40,7 @@ jobs:
- name: Save artifact - name: Save artifact
if: ${{ github.event_name == 'push' }} if: ${{ github.event_name == 'push' }}
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: docs name: docs
path: ./docs.tar.gz path: ./docs.tar.gz
@ -57,7 +57,7 @@ jobs:
if: ${{ github.event_name == 'push' }} if: ${{ github.event_name == 'push' }}
steps: steps:
- name: Download artifact - name: Download artifact
uses: actions/download-artifact@v3 uses: actions/download-artifact@v4
with: with:
name: docs name: docs
- name: Unpack artifact - name: Unpack artifact
@ -65,7 +65,7 @@ jobs:
mkdir ./${{ env.LATEST_DOCS_DIR }} mkdir ./${{ env.LATEST_DOCS_DIR }}
tar -xzf ./docs.tar.gz -C ./${{ env.LATEST_DOCS_DIR }} tar -xzf ./docs.tar.gz -C ./${{ env.LATEST_DOCS_DIR }}
- name: Delete Artifact - name: Delete Artifact
uses: geekyeggo/delete-artifact@v2 uses: geekyeggo/delete-artifact@v5
with: with:
name: docs name: docs
- name: Select Docs type - name: Select Docs type
@ -101,7 +101,7 @@ jobs:
exit 1 exit 1
fi fi
- name: Deploy to Github Pages - name: Deploy to Github Pages
uses: peaceiris/actions-gh-pages@v3 uses: peaceiris/actions-gh-pages@v4
with: with:
personal_token: ${{ secrets.DEPLOY_GH_DOCS_TOKEN }} personal_token: ${{ secrets.DEPLOY_GH_DOCS_TOKEN }}
external_repository: ${{ env.DOCS_REPO }} external_repository: ${{ env.DOCS_REPO }}

View File

@ -34,7 +34,7 @@ jobs:
run: | run: |
# Free space # Free space
sudo apt clean sudo apt clean
docker rmi $(docker image ls -aq) # docker rmi $(docker image ls -aq)
df -h df -h
tox -e testexamples tox -e testexamples

View File

@ -18,6 +18,17 @@ Unlock the true potential of embedded software development with
PlatformIO's collaborative ecosystem, embracing declarative principles, PlatformIO's collaborative ecosystem, embracing declarative principles,
test-driven methodologies, and modern toolchains for unrivaled success. test-driven methodologies, and modern toolchains for unrivaled success.
6.1.17 (2025-02-13)
~~~~~~~~~~~~~~~~~~~
* Introduced the `PLATFORMIO_RUN_JOBS <https://docs.platformio.org/en/latest/envvars.html#envvar-PLATFORMIO_RUN_JOBS>`__ environment variable, allowing manual override of the number of parallel build jobs (`issue #5077 <https://github.com/platformio/platformio-core/issues/5077>`_)
* Added support for ``tar.xz`` tarball dependencies (`pull #4974 <https://github.com/platformio/platformio-core/pull/4974>`_)
* Ensured that dependencies of private libraries are no longer unnecessarily re-installed, optimizing dependency management and reducing redundant operations (`issue #4987 <https://github.com/platformio/platformio-core/issues/4987>`_)
* Resolved an issue where the ``compiledb`` target failed to properly escape compiler executable paths containing spaces (`issue #4998 <https://github.com/platformio/platformio-core/issues/4998>`_)
* Resolved an issue with incorrect path resolution when linking static libraries via the `build_flags <https://docs.platformio.org/en/latest/projectconf/sections/env/options/build/build_flags.html>`__ option (`issue #5004 <https://github.com/platformio/platformio-core/issues/5004>`_)
* Resolved an issue where the ``--project-dir`` flag did not function correctly with the `pio check <https://docs.platformio.org/en/latest/core/userguide/cmd_check.html>`__ and `pio debug <https://docs.platformio.org/en/latest/core/userguide/cmd_debug.html>`__ commands (`issue #5029 <https://github.com/platformio/platformio-core/issues/5029>`_)
* Resolved an issue where the |LDF| occasionally excluded bundled platform libraries from the dependency graph (`pull #4941 <https://github.com/platformio/platformio-core/pull/4941>`_)
6.1.16 (2024-09-26) 6.1.16 (2024-09-26)
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~

View File

@ -10,10 +10,13 @@ format:
black ./platformio black ./platformio
black ./tests black ./tests
codespell:
codespell --skip "./build,./docs/_build" -L "AtLeast,TRE,ans,dout,homestate,ser"
test: test:
pytest --verbose --exitfirst -n 6 --dist=loadscope tests --ignore tests/test_examples.py pytest --verbose --exitfirst -n 6 --dist=loadscope tests --ignore tests/test_examples.py
before-commit: isort format lint before-commit: codespell isort format lint
clean-docs: clean-docs:
rm -rf docs/_build rm -rf docs/_build

2
docs

Submodule docs updated: dd3d549bdb...f44574013b

View File

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
VERSION = (6, 1, 16) VERSION = (6, 1, 17)
__version__ = ".".join([str(s) for s in VERSION]) __version__ = ".".join([str(s) for s in VERSION])
__title__ = "platformio" __title__ = "platformio"

View File

@ -147,13 +147,13 @@ if env.subst("$BUILD_CACHE_DIR"):
if not int(ARGUMENTS.get("PIOVERBOSE", 0)): if not int(ARGUMENTS.get("PIOVERBOSE", 0)):
click.echo("Verbose mode can be enabled via `-v, --verbose` option") click.echo("Verbose mode can be enabled via `-v, --verbose` option")
if not os.path.isdir(env.subst("$BUILD_DIR")):
os.makedirs(env.subst("$BUILD_DIR"))
# Dynamically load dependent tools # Dynamically load dependent tools
if "compiledb" in COMMAND_LINE_TARGETS: if "compiledb" in COMMAND_LINE_TARGETS:
env.Tool("compilation_db") env.Tool("compilation_db")
if not os.path.isdir(env.subst("$BUILD_DIR")):
os.makedirs(env.subst("$BUILD_DIR"))
env.LoadProjectOptions() env.LoadProjectOptions()
env.LoadPioPlatform() env.LoadPioPlatform()

View File

@ -58,6 +58,7 @@ def GetBuildType(env):
def BuildProgram(env): def BuildProgram(env):
env.ProcessCompileDbToolchainOption()
env.ProcessProgramDeps() env.ProcessProgramDeps()
env.ProcessProjectDeps() env.ProcessProjectDeps()
@ -90,6 +91,26 @@ def BuildProgram(env):
return program return program
def ProcessCompileDbToolchainOption(env):
if "compiledb" not in COMMAND_LINE_TARGETS:
return
# Resolve absolute path of toolchain
for cmd in ("CC", "CXX", "AS"):
if cmd not in env:
continue
if os.path.isabs(env[cmd]) or '"' in env[cmd]:
continue
env[cmd] = where_is_program(env.subst("$%s" % cmd), env.subst("${ENV['PATH']}"))
if " " in env[cmd]: # issue #4998: Space in compilator path
env[cmd] = f'"{env[cmd]}"'
if env.get("COMPILATIONDB_INCLUDE_TOOLCHAIN"):
print("Warning! `COMPILATIONDB_INCLUDE_TOOLCHAIN` is scoping")
for scope, includes in env.DumpIntegrationIncludes().items():
if scope in ("toolchain",):
env.Append(CPPPATH=includes)
def ProcessProgramDeps(env): def ProcessProgramDeps(env):
def _append_pio_macros(): def _append_pio_macros():
core_version = pepver_to_semver(__version__) core_version = pepver_to_semver(__version__)
@ -126,27 +147,6 @@ def ProcessProgramDeps(env):
# remove specified flags # remove specified flags
env.ProcessUnFlags(env.get("BUILD_UNFLAGS")) env.ProcessUnFlags(env.get("BUILD_UNFLAGS"))
env.ProcessCompileDbToolchainOption()
def ProcessCompileDbToolchainOption(env):
if "compiledb" in COMMAND_LINE_TARGETS:
# Resolve absolute path of toolchain
for cmd in ("CC", "CXX", "AS"):
if cmd not in env:
continue
if os.path.isabs(env[cmd]):
continue
env[cmd] = where_is_program(
env.subst("$%s" % cmd), env.subst("${ENV['PATH']}")
)
if env.get("COMPILATIONDB_INCLUDE_TOOLCHAIN"):
print("Warning! `COMPILATIONDB_INCLUDE_TOOLCHAIN` is scoping")
for scope, includes in env.DumpIntegrationIncludes().items():
if scope in ("toolchain",):
env.Append(CPPPATH=includes)
def ProcessProjectDeps(env): def ProcessProjectDeps(env):
plb = env.ConfigureProjectLibBuilder() plb = env.ConfigureProjectLibBuilder()
@ -219,6 +219,11 @@ def ParseFlagsExtended(env, flags): # pylint: disable=too-many-branches
if os.path.isdir(p): if os.path.isdir(p):
result[k][i] = os.path.abspath(p) result[k][i] = os.path.abspath(p)
# fix relative LIBs
for i, l in enumerate(result.get("LIBS", [])):
if isinstance(l, FS.File):
result["LIBS"][i] = os.path.abspath(l.get_path())
# fix relative path for "-include" # fix relative path for "-include"
for i, f in enumerate(result.get("CCFLAGS", [])): for i, f in enumerate(result.get("CCFLAGS", [])):
if isinstance(f, tuple) and f[0] == "-include": if isinstance(f, tuple) and f[0] == "-include":

View File

@ -1159,6 +1159,8 @@ def ConfigureProjectLibBuilder(env):
for lb in lib_builders: for lb in lib_builders:
if lb in found_lbs: if lb in found_lbs:
lb.search_deps_recursive(lb.get_search_files()) lb.search_deps_recursive(lb.get_search_files())
# refill found libs after recursive search
found_lbs = [lb for lb in lib_builders if lb.is_dependent]
for lb in lib_builders: for lb in lib_builders:
for deplb in lb.depbuilders[:]: for deplb in lb.depbuilders[:]:
if deplb not in found_lbs: if deplb not in found_lbs:

View File

@ -19,7 +19,6 @@ import json
import os import os
import shutil import shutil
from collections import Counter from collections import Counter
from os.path import dirname, isfile
from time import time from time import time
import click import click
@ -77,7 +76,7 @@ def cli( # pylint: disable=too-many-positional-arguments
app.set_session_var("custom_project_conf", project_conf) app.set_session_var("custom_project_conf", project_conf)
# find project directory on upper level # find project directory on upper level
if isfile(project_dir): if os.path.isfile(project_dir):
project_dir = find_project_dir_above(project_dir) project_dir = find_project_dir_above(project_dir)
results = [] results = []
@ -150,7 +149,7 @@ def cli( # pylint: disable=too-many-positional-arguments
print_processing_header(tool, envname, env_dump) print_processing_header(tool, envname, env_dump)
ct = CheckToolFactory.new( ct = CheckToolFactory.new(
tool, project_dir, config, envname, tool_options tool, os.getcwd(), config, envname, tool_options
) )
result = {"env": envname, "tool": tool, "duration": time()} result = {"env": envname, "tool": tool, "duration": time()}
@ -250,12 +249,12 @@ def collect_component_stats(result):
components[component].update({DefectItem.SEVERITY_LABELS[defect.severity]: 1}) components[component].update({DefectItem.SEVERITY_LABELS[defect.severity]: 1})
for defect in result.get("defects", []): for defect in result.get("defects", []):
component = dirname(defect.file) or defect.file component = os.path.dirname(defect.file) or defect.file
_append_defect(component, defect) _append_defect(component, defect)
if component.lower().startswith(get_project_dir().lower()): if component.lower().startswith(get_project_dir().lower()):
while os.sep in component: while os.sep in component:
component = dirname(component) component = os.path.dirname(component)
_append_defect(component, defect) _append_defect(component, defect)
return components return components

View File

@ -76,5 +76,5 @@ def settings_set(ctx, name, value):
@click.pass_context @click.pass_context
def settings_reset(ctx): def settings_reset(ctx):
app.reset_settings() app.reset_settings()
click.secho("The settings have been reseted!", fg="green") click.secho("The settings have been reset!", fg="green")
ctx.invoke(settings_get) ctx.invoke(settings_get)

View File

@ -86,7 +86,7 @@ def cli( # pylint: disable=too-many-positional-arguments
if not interface: if not interface:
return helpers.predebug_project( return helpers.predebug_project(
ctx, project_dir, project_config, env_name, False, verbose ctx, os.getcwd(), project_config, env_name, False, verbose
) )
configure_args = ( configure_args = (
@ -106,7 +106,7 @@ def cli( # pylint: disable=too-many-positional-arguments
else: else:
debug_config = _configure(*configure_args) debug_config = _configure(*configure_args)
_run(project_dir, debug_config, client_extra_args) _run(os.getcwd(), debug_config, client_extra_args)
return None return None

View File

@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import platform
from platformio.compat import is_proxy_set from platformio.compat import is_proxy_set
@ -30,8 +28,7 @@ def get_core_dependencies():
def get_pip_dependencies(): def get_pip_dependencies():
core = [ core = [
'bottle == 0.12.*; python_version < "3.7"', "bottle == 0.13.*",
'bottle == 0.13.*; python_version >= "3.7"',
"click >=8.0.4, <9", "click >=8.0.4, <9",
"colorama", "colorama",
"marshmallow == 3.*", "marshmallow == 3.*",
@ -45,19 +42,16 @@ def get_pip_dependencies():
home = [ home = [
# PIO Home requirements # PIO Home requirements
"ajsonrpc == 1.2.*", "ajsonrpc == 1.2.*",
"starlette >=0.19, <0.40", "starlette >=0.19, <0.46",
'uvicorn == 0.16.0; python_version < "3.7"', "uvicorn >=0.16, <0.35",
'uvicorn >=0.16, <0.31; python_version >= "3.7"',
"wsproto == 1.*", "wsproto == 1.*",
] ]
extra = [] extra = []
# issue #4702; Broken "requests/charset_normalizer" on macOS ARM # issue #4702; Broken "requests/charset_normalizer" on macOS ARM
if platform.system() == "Darwin" and "arm" in platform.machine().lower(): extra.append(
extra.append( 'chardet >= 3.0.2,<6; platform_system == "Darwin" and "arm" in platform_machine'
'chardet >= 3.0.2,<6; platform_system == "Darwin" and "arm" in platform_machine' )
)
# issue 4614: urllib3 v2.0 only supports OpenSSL 1.1.1+ # issue 4614: urllib3 v2.0 only supports OpenSSL 1.1.1+
try: try:

View File

@ -54,7 +54,7 @@ def package_exec_cmd(obj, package, call, args):
os.environ["PIO_PYTHON_EXE"] = get_pythonexe_path() os.environ["PIO_PYTHON_EXE"] = get_pythonexe_path()
# inject current python interpreter on Windows # inject current python interpreter on Windows
if args[0].endswith(".py"): if args and args[0].endswith(".py"):
args = [os.environ["PIO_PYTHON_EXE"]] + list(args) args = [os.environ["PIO_PYTHON_EXE"]] + list(args)
if not os.path.exists(args[1]): if not os.path.exists(args[1]):
args[1] = where_is_program(args[1]) args[1] = where_is_program(args[1])

View File

@ -297,7 +297,11 @@ def _install_project_private_library_deps(private_pkg, private_lm, env_lm, optio
if not spec.external and not spec.owner: if not spec.external and not spec.owner:
continue continue
pkg = private_lm.get_package(spec) pkg = private_lm.get_package(spec)
if not pkg and not env_lm.get_package(spec): if (
not pkg
and not private_lm.get_package(spec)
and not env_lm.get_package(spec)
):
pkg = env_lm.install( pkg = env_lm.install(
spec, spec,
skip_dependencies=True, skip_dependencies=True,

View File

@ -111,7 +111,7 @@ def uninstall_project_env_dependencies(project_env, options=None):
uninstalled_conds.append( uninstalled_conds.append(
_uninstall_project_env_custom_tools(project_env, options) _uninstall_project_env_custom_tools(project_env, options)
) )
# custom ibraries # custom libraries
if options.get("libraries"): if options.get("libraries"):
uninstalled_conds.append( uninstalled_conds.append(
_uninstall_project_env_custom_libraries(project_env, options) _uninstall_project_env_custom_libraries(project_env, options)

View File

@ -110,7 +110,7 @@ def update_project_env_dependencies(project_env, options=None):
# custom tools # custom tools
if options.get("tools"): if options.get("tools"):
updated_conds.append(_update_project_env_custom_tools(project_env, options)) updated_conds.append(_update_project_env_custom_tools(project_env, options))
# custom ibraries # custom libraries
if options.get("libraries"): if options.get("libraries"):
updated_conds.append(_update_project_env_custom_libraries(project_env, options)) updated_conds.append(_update_project_env_custom_libraries(project_env, options))
# declared dependencies # declared dependencies

View File

@ -34,7 +34,7 @@ class FileDownloader:
url, url,
stream=True, stream=True,
) )
if self._http_response.status_code != 200: if self._http_response.status_code not in (200, 203):
raise PackageException( raise PackageException(
"Got the unrecognized status code '{0}' when downloaded {1}".format( "Got the unrecognized status code '{0}' when downloaded {1}".format(
self._http_response.status_code, url self._http_response.status_code, url

View File

@ -276,7 +276,7 @@ class ManifestSchema(BaseSchema):
@staticmethod @staticmethod
@memoized(expire="1h") @memoized(expire="1h")
def load_spdx_licenses(): def load_spdx_licenses():
version = "3.24.0" version = "3.26.0"
spdx_data_url = ( spdx_data_url = (
"https://raw.githubusercontent.com/spdx/license-list-data/" "https://raw.githubusercontent.com/spdx/license-list-data/"
f"v{version}/json/licenses.json" f"v{version}/json/licenses.json"

View File

@ -396,7 +396,7 @@ class PackageSpec: # pylint: disable=too-many-instance-attributes
parts.path.endswith(".git"), parts.path.endswith(".git"),
# Handle GitHub URL (https://github.com/user/package) # Handle GitHub URL (https://github.com/user/package)
parts.netloc in ("github.com", "gitlab.com", "bitbucket.com") parts.netloc in ("github.com", "gitlab.com", "bitbucket.com")
and not parts.path.endswith((".zip", ".tar.gz")), and not parts.path.endswith((".zip", ".tar.gz", ".tar.xz")),
] ]
hg_conditions = [ hg_conditions = [
# Handle Developer Mbed URL # Handle Developer Mbed URL

View File

@ -152,6 +152,7 @@ class FileUnpacker:
magic_map = { magic_map = {
b"\x1f\x8b\x08": TARArchiver, b"\x1f\x8b\x08": TARArchiver,
b"\x42\x5a\x68": TARArchiver, b"\x42\x5a\x68": TARArchiver,
b"\xfd\x37\x7a\x58\x5a\x00": TARArchiver,
b"\x50\x4b\x03\x04": ZIPArchiver, b"\x50\x4b\x03\x04": ZIPArchiver,
} }
magic_len = max(len(k) for k in magic_map) magic_len = max(len(k) for k in magic_map)

View File

@ -44,7 +44,7 @@ def cast_version_to_semver(value, force=True, raise_exception=False):
def pepver_to_semver(pepver): def pepver_to_semver(pepver):
return cast_version_to_semver( return cast_version_to_semver(
re.sub(r"(\.\d+)\.?(dev|a|b|rc|post)", r"\1-\2.", pepver, 1) re.sub(r"(\.\d+)\.?(dev|a|b|rc|post)", r"\1-\2.", pepver, count=1)
) )

View File

@ -33,7 +33,7 @@ class PlatformFactory:
@staticmethod @staticmethod
def load_platform_module(name, path): def load_platform_module(name, path):
# backward compatibiility with the legacy dev-platforms # backward compatibility with the legacy dev-platforms
sys.modules["platformio.managers.platform"] = base sys.modules["platformio.managers.platform"] = base
try: try:
return load_python_module("platformio.platform.%s" % name, path) return load_python_module("platformio.platform.%s" % name, path)

View File

@ -201,9 +201,7 @@ new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program. find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'. In C, the convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation: Read more about using header files in official GCC documentation:
@ -222,12 +220,12 @@ def init_lib_readme(lib_dir):
fp.write( fp.write(
""" """
This directory is intended for project specific (private) libraries. This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file. PlatformIO will compile them to static libraries and link into the executable file.
The source code of each library should be placed in an own separate directory The source code of each library should be placed in a separate directory
("lib/your_library_name/[here are source files]"). ("lib/your_library_name/[Code]").
For example, see a structure of the following two libraries `Foo` and `Bar`: For example, see the structure of the following example libraries `Foo` and `Bar`:
|--lib |--lib
| | | |
@ -237,7 +235,7 @@ For example, see a structure of the following two libraries `Foo` and `Bar`:
| | |--src | | |--src
| | |- Bar.c | | |- Bar.c
| | |- Bar.h | | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html | | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| | | |
| |--Foo | |--Foo
| | |- Foo.c | | |- Foo.c
@ -249,7 +247,7 @@ For example, see a structure of the following two libraries `Foo` and `Bar`:
|--src |--src
|- main.c |- main.c
and a contents of `src/main.c`: Example contents of `src/main.c` using Foo and Bar:
``` ```
#include <Foo.h> #include <Foo.h>
#include <Bar.h> #include <Bar.h>
@ -261,8 +259,8 @@ int main (void)
``` ```
PlatformIO Library Dependency Finder will find automatically dependent The PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files. libraries by scanning project source files.
More information about PlatformIO Library Dependency Finder More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html - https://docs.platformio.org/page/librarymanager/ldf.html

View File

@ -347,7 +347,7 @@ class ProjectConfigBase:
if section is None: if section is None:
if option in self.BUILTIN_VARS: if option in self.BUILTIN_VARS:
return self.BUILTIN_VARS[option]() return self.BUILTIN_VARS[option]()
# SCons varaibles # SCons variables
return f"${{{option}}}" return f"${{{option}}}"
# handle system environment variables # handle system environment variables

View File

@ -158,7 +158,7 @@ def load_build_metadata(project_dir, env_or_envs, cache=False, build_type=None):
return result or None return result or None
# Backward compatibiility with dev-platforms # Backward compatibility with dev-platforms
load_project_ide_data = load_build_metadata load_project_ide_data = load_build_metadata

View File

@ -17,7 +17,7 @@
# common.symbolFiles=<Symbol Files loaded by debugger> # common.symbolFiles=<Symbol Files loaded by debugger>
# (This value is overwritten by a launcher specific symbolFiles value if the latter exists) # (This value is overwritten by a launcher specific symbolFiles value if the latter exists)
# #
# In runDir, symbolFiles and env fields you can use these macroses: # In runDir, symbolFiles and env fields you can use these macros:
# ${PROJECT_DIR} - project directory absolute path # ${PROJECT_DIR} - project directory absolute path
# ${OUTPUT_PATH} - linker output path (relative to project directory path) # ${OUTPUT_PATH} - linker output path (relative to project directory path)
# ${OUTPUT_BASENAME}- linker output filename # ${OUTPUT_BASENAME}- linker output filename

View File

@ -33,9 +33,11 @@ from platformio.test.runners.base import CTX_META_TEST_IS_RUNNING
# pylint: disable=too-many-arguments,too-many-locals,too-many-branches # pylint: disable=too-many-arguments,too-many-locals,too-many-branches
try: try:
DEFAULT_JOB_NUMS = cpu_count() SYSTEM_CPU_COUNT = cpu_count()
except NotImplementedError: except NotImplementedError:
DEFAULT_JOB_NUMS = 1 SYSTEM_CPU_COUNT = 1
DEFAULT_JOB_NUMS = int(os.getenv("PLATFORMIO_RUN_JOBS", SYSTEM_CPU_COUNT))
@click.command("run", short_help="Run project targets (build, upload, clean, etc.)") @click.command("run", short_help="Run project targets (build, upload, clean, etc.)")

View File

@ -65,16 +65,16 @@ class memoized:
class throttle: class throttle:
def __init__(self, threshhold): def __init__(self, threshold):
self.threshhold = threshhold # milliseconds self.threshold = threshold # milliseconds
self.last = 0 self.last = 0
def __call__(self, func): def __call__(self, func):
@functools.wraps(func) @functools.wraps(func)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
diff = int(round((time.time() - self.last) * 1000)) diff = int(round((time.time() - self.last) * 1000))
if diff < self.threshhold: if diff < self.threshold:
time.sleep((self.threshhold - diff) * 0.001) time.sleep((self.threshold - diff) * 0.001)
self.last = time.time() self.last = time.time()
return func(*args, **kwargs) return func(*args, **kwargs)

View File

@ -31,7 +31,7 @@ PROJECT_CONFIG_TPL = """
[env] [env]
platform = platformio/atmelavr@^3.4.0 platform = platformio/atmelavr@^3.4.0
lib_deps = lib_deps =
milesburton/DallasTemperature@^3.9.1 milesburton/DallasTemperature@^4.0.4
https://github.com/esphome/ESPAsyncWebServer/archive/refs/tags/v2.1.0.zip https://github.com/esphome/ESPAsyncWebServer/archive/refs/tags/v2.1.0.zip
[env:baremetal] [env:baremetal]
@ -215,7 +215,7 @@ def test_project(
PackageSpec("toolchain-atmelavr@1.70300.191015"), PackageSpec("toolchain-atmelavr@1.70300.191015"),
] ]
assert config.get("env:devkit", "lib_deps") == [ assert config.get("env:devkit", "lib_deps") == [
"milesburton/DallasTemperature@^3.9.1", "milesburton/DallasTemperature@^4.0.4",
"https://github.com/esphome/ESPAsyncWebServer/archive/refs/tags/v2.1.0.zip", "https://github.com/esphome/ESPAsyncWebServer/archive/refs/tags/v2.1.0.zip",
] ]
@ -241,7 +241,7 @@ def test_private_lib_deps(
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"bblanchon/ArduinoJson": "^5", "bblanchon/ArduinoJson": "^5",
"milesburton/DallasTemperature": "^3.9.1" "milesburton/DallasTemperature": "^4.0.4"
} }
} }
""" """
@ -340,7 +340,7 @@ def test_remove_project_unused_libdeps(
), ),
] ]
# manually remove from cofiguration file # manually remove from configuration file
config.set("env:baremetal", "lib_deps", ["bblanchon/ArduinoJson@^5"]) config.set("env:baremetal", "lib_deps", ["bblanchon/ArduinoJson@^5"])
config.save() config.save()
result = clirunner.invoke( result = clirunner.invoke(
@ -446,7 +446,7 @@ def test_custom_project_libraries(
) )
assert pkgs_to_specs(lm.get_installed()) == [ assert pkgs_to_specs(lm.get_installed()) == [
PackageSpec("ArduinoJson@5.13.4"), PackageSpec("ArduinoJson@5.13.4"),
PackageSpec("Nanopb@0.4.9"), PackageSpec("Nanopb@0.4.91"),
] ]
assert config.get("env:devkit", "lib_deps") == [ assert config.get("env:devkit", "lib_deps") == [
"bblanchon/ArduinoJson@^5", "bblanchon/ArduinoJson@^5",

View File

@ -56,7 +56,7 @@ def test_project(clirunner, validate_cliresult, isolated_pio_core, tmp_path):
re.MULTILINE, re.MULTILINE,
) )
assert re.search( assert re.search(
r"^DallasTemperature\s+3\.\d\.1\s+3\.\d+\.\d+\s+3\.\d+\.\d+\s+Library\s+devkit", r"^DallasTemperature\s+3\.\d\.1\s+3\.\d+\.\d+\s+4\.\d+\.\d+\s+Library\s+devkit",
result.output, result.output,
re.MULTILINE, re.MULTILINE,
) )

View File

@ -58,12 +58,14 @@ def test_global_packages(
validate_cliresult(result) validate_cliresult(result)
assert pkgs_to_names(LibraryPackageManager().get_installed()) == [ assert pkgs_to_names(LibraryPackageManager().get_installed()) == [
"ArduinoJson", "ArduinoJson",
"Async TCP",
"AsyncMqttClient", "AsyncMqttClient",
"AsyncTCP", "AsyncTCP",
"AsyncTCP_RP2040W",
"Bounce2", "Bounce2",
"ESP Async WebServer", "ESP Async WebServer",
"ESPAsyncTCP", "ESPAsyncTCP",
"ESPAsyncTCP", "ESPAsyncTCP-esphome",
"Homie", "Homie",
] ]
# uninstall all deps # uninstall all deps
@ -96,12 +98,14 @@ def test_global_packages(
validate_cliresult(result) validate_cliresult(result)
assert pkgs_to_names(LibraryPackageManager().get_installed()) == [ assert pkgs_to_names(LibraryPackageManager().get_installed()) == [
"ArduinoJson", "ArduinoJson",
"Async TCP",
"AsyncMqttClient", "AsyncMqttClient",
"AsyncTCP", "AsyncTCP",
"AsyncTCP_RP2040W",
"Bounce2", "Bounce2",
"ESP Async WebServer", "ESP Async WebServer",
"ESPAsyncTCP", "ESPAsyncTCP",
"ESPAsyncTCP", "ESPAsyncTCP-esphome",
] ]
# remove specific dependency # remove specific dependency
result = clirunner.invoke( result = clirunner.invoke(
@ -116,6 +120,7 @@ def test_global_packages(
assert pkgs_to_names(LibraryPackageManager().get_installed()) == [ assert pkgs_to_names(LibraryPackageManager().get_installed()) == [
"ArduinoJson", "ArduinoJson",
"AsyncMqttClient", "AsyncMqttClient",
"AsyncTCP",
"Bounce2", "Bounce2",
"ESPAsyncTCP", "ESPAsyncTCP",
] ]

View File

@ -34,7 +34,7 @@ PROJECT_OUTDATED_CONFIG_TPL = """
platform = platformio/atmelavr@^2 platform = platformio/atmelavr@^2
framework = arduino framework = arduino
board = attiny88 board = attiny88
lib_deps = milesburton/DallasTemperature@^3.8.0 lib_deps = milesburton/DallasTemperature@^3.9.1
""" """
PROJECT_UPDATED_CONFIG_TPL = """ PROJECT_UPDATED_CONFIG_TPL = """
@ -42,7 +42,7 @@ PROJECT_UPDATED_CONFIG_TPL = """
platform = platformio/atmelavr@<4 platform = platformio/atmelavr@<4
framework = arduino framework = arduino
board = attiny88 board = attiny88
lib_deps = milesburton/DallasTemperature@^3.8.0 lib_deps = milesburton/DallasTemperature@^3.9.1
""" """
@ -179,7 +179,7 @@ def test_project(
PackageSpec("toolchain-atmelavr@1.50400.190710"), PackageSpec("toolchain-atmelavr@1.50400.190710"),
] ]
assert config.get("env:devkit", "lib_deps") == [ assert config.get("env:devkit", "lib_deps") == [
"milesburton/DallasTemperature@^3.8.0" "milesburton/DallasTemperature@^3.9.1"
] ]
# update packages # update packages
@ -195,10 +195,7 @@ def test_project(
assert pkgs[0].metadata.name == "atmelavr" assert pkgs[0].metadata.name == "atmelavr"
assert pkgs[0].metadata.version.major == 3 assert pkgs[0].metadata.version.major == 3
assert pkgs_to_specs(lm.get_installed()) == [ assert pkgs_to_specs(lm.get_installed()) == [
PackageSpec( PackageSpec("DallasTemperature@3.11.0"),
"DallasTemperature@%s"
% get_pkg_latest_version("milesburton/DallasTemperature")
),
PackageSpec( PackageSpec(
"OneWire@%s" % get_pkg_latest_version("paulstoffregen/OneWire") "OneWire@%s" % get_pkg_latest_version("paulstoffregen/OneWire")
), ),
@ -210,7 +207,7 @@ def test_project(
PackageSpec("toolchain-atmelavr@1.50400.190710"), PackageSpec("toolchain-atmelavr@1.50400.190710"),
] ]
assert config.get("env:devkit", "lib_deps") == [ assert config.get("env:devkit", "lib_deps") == [
"milesburton/DallasTemperature@^3.8.0" "milesburton/DallasTemperature@^3.9.1"
] ]
# update again # update again
@ -230,7 +227,7 @@ def test_custom_project_libraries(
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project_dir.mkdir() project_dir.mkdir()
(project_dir / "platformio.ini").write_text(PROJECT_OUTDATED_CONFIG_TPL) (project_dir / "platformio.ini").write_text(PROJECT_OUTDATED_CONFIG_TPL)
spec = "milesburton/DallasTemperature@^3.8.0" spec = "milesburton/DallasTemperature@^3.9.1"
result = clirunner.invoke( result = clirunner.invoke(
package_install_cmd, package_install_cmd,
["-d", str(project_dir), "-e", "devkit", "-l", spec], ["-d", str(project_dir), "-e", "devkit", "-l", spec],
@ -251,15 +248,15 @@ def test_custom_project_libraries(
# update package # update package
result = clirunner.invoke( result = clirunner.invoke(
package_update_cmd, package_update_cmd,
["-e", "devkit", "-l", "milesburton/DallasTemperature@^3.8.0"], ["-e", "devkit", "-l", "milesburton/DallasTemperature@^3.9.1"],
) )
assert ProjectConfig().get("env:devkit", "lib_deps") == [ assert ProjectConfig().get("env:devkit", "lib_deps") == [
"milesburton/DallasTemperature@^3.8.0" "milesburton/DallasTemperature@^3.9.1"
] ]
# try again # try again
result = clirunner.invoke( result = clirunner.invoke(
package_update_cmd, package_update_cmd,
["-e", "devkit", "-l", "milesburton/DallasTemperature@^3.8.0"], ["-e", "devkit", "-l", "milesburton/DallasTemperature@^3.9.1"],
) )
validate_cliresult(result) validate_cliresult(result)
assert "Already up-to-date." in result.output assert "Already up-to-date." in result.output
@ -276,16 +273,13 @@ def test_custom_project_libraries(
os.path.join(config.get("platformio", "libdeps_dir"), "devkit") os.path.join(config.get("platformio", "libdeps_dir"), "devkit")
) )
assert pkgs_to_specs(lm.get_installed()) == [ assert pkgs_to_specs(lm.get_installed()) == [
PackageSpec( PackageSpec("DallasTemperature@3.11.0"),
"DallasTemperature@%s"
% get_pkg_latest_version("milesburton/DallasTemperature")
),
PackageSpec( PackageSpec(
"OneWire@%s" % get_pkg_latest_version("paulstoffregen/OneWire") "OneWire@%s" % get_pkg_latest_version("paulstoffregen/OneWire")
), ),
] ]
assert config.get("env:devkit", "lib_deps") == [ assert config.get("env:devkit", "lib_deps") == [
"milesburton/DallasTemperature@^3.8.0" "milesburton/DallasTemperature@^3.9.1"
] ]
# unknown libraries # unknown libraries

View File

@ -235,7 +235,7 @@ def test_global_lib_update_check(clirunner, validate_cliresult):
validate_cliresult(result) validate_cliresult(result)
output = json.loads(result.output) output = json.loads(result.output)
assert set( assert set(
["Adafruit PN532", "AsyncMqttClient", "ESPAsyncTCP", "NeoPixelBus"] ["Adafruit PN532", "AsyncMqttClient", "AsyncTCP", "ESPAsyncTCP", "NeoPixelBus"]
) == set(lib["name"] for lib in output) ) == set(lib["name"] for lib in output)

View File

@ -246,67 +246,67 @@ int main(int argc, char *argv[]) {
) )
@pytest.mark.skipif( # @pytest.mark.skipif(
sys.platform != "darwin", reason="runs only on macOS (issue with SimAVR)" # sys.platform != "darwin", reason="runs only on macOS (issue with SimAVR)"
) # )
def test_custom_testing_command(clirunner, validate_cliresult, tmp_path: Path): # def test_custom_testing_command(clirunner, validate_cliresult, tmp_path: Path):
project_dir = tmp_path / "project" # project_dir = tmp_path / "project"
project_dir.mkdir() # project_dir.mkdir()
(project_dir / "platformio.ini").write_text( # (project_dir / "platformio.ini").write_text(
""" # """
[env:uno] # [env:uno]
platform = atmelavr # platform = atmelavr
framework = arduino # framework = arduino
board = uno # board = uno
platform_packages = # platform_packages =
platformio/tool-simavr @ ^1 # platformio/tool-simavr @ ^1
test_speed = 9600 # test_speed = 9600
test_testing_command = # test_testing_command =
${platformio.packages_dir}/tool-simavr/bin/simavr # ${platformio.packages_dir}/tool-simavr/bin/simavr
-m # -m
atmega328p # atmega328p
-f # -f
16000000L # 16000000L
${platformio.build_dir}/${this.__env__}/firmware.elf # ${platformio.build_dir}/${this.__env__}/firmware.elf
""" # """
) # )
test_dir = project_dir / "test" / "test_dummy" # test_dir = project_dir / "test" / "test_dummy"
test_dir.mkdir(parents=True) # test_dir.mkdir(parents=True)
(test_dir / "test_main.cpp").write_text( # (test_dir / "test_main.cpp").write_text(
""" # """
#include <Arduino.h> # #include <Arduino.h>
#include <unity.h> # #include <unity.h>
void setUp(void) { # void setUp(void) {
// set stuff up here # // set stuff up here
} # }
void tearDown(void) { # void tearDown(void) {
// clean stuff up here # // clean stuff up here
} # }
void dummy_test(void) { # void dummy_test(void) {
TEST_ASSERT_EQUAL(1, 1); # TEST_ASSERT_EQUAL(1, 1);
} # }
void setup() { # void setup() {
UNITY_BEGIN(); # UNITY_BEGIN();
RUN_TEST(dummy_test); # RUN_TEST(dummy_test);
UNITY_END(); # UNITY_END();
} # }
void loop() { # void loop() {
delay(1000); # delay(1000);
} # }
""" # """
) # )
result = clirunner.invoke( # result = clirunner.invoke(
pio_test_cmd, # pio_test_cmd,
["-d", str(project_dir), "--without-uploading"], # ["-d", str(project_dir), "--without-uploading"],
) # )
validate_cliresult(result) # validate_cliresult(result)
assert "dummy_test" in result.output # assert "dummy_test" in result.output
def test_unity_setup_teardown(clirunner, validate_cliresult, tmpdir): def test_unity_setup_teardown(clirunner, validate_cliresult, tmpdir):

View File

@ -335,7 +335,7 @@ def test_symlink(tmp_path: Path):
# uninstall # uninstall
lm.uninstall("External") lm.uninstall("External")
assert ["Installed"] == [pkg.metadata.name for pkg in lm.get_installed()] assert ["Installed"] == [pkg.metadata.name for pkg in lm.get_installed()]
# ensure original package was not rmeoved # ensure original package was not removed
assert external_pkg_dir.is_dir() assert external_pkg_dir.is_dir()
# install again, remove from a disk # install again, remove from a disk

View File

@ -27,11 +27,12 @@ passenv = *
usedevelop = True usedevelop = True
deps = deps =
black black
codespell
isort isort
jsondiff
pylint pylint
pytest pytest
pytest-xdist pytest-xdist
jsondiff
commands = commands =
{envpython} --version {envpython} --version
pio system info pio system info
@ -54,8 +55,8 @@ commands =
[testenv:docs] [testenv:docs]
deps = deps =
sphinx sphinx-rtd-theme==3.0.2
sphinx-rtd-theme==2.0.0 sphinxcontrib-googleanalytics
sphinx-notfound-page sphinx-notfound-page
sphinx-copybutton sphinx-copybutton
restructuredtext-lint restructuredtext-lint