forked from platformio/platformio-core
Merge branch 'develop' into feature/v7
# Conflicts: # docs # platformio/builder/tools/piobuild.py # platformio/debug/config/base.py # platformio/project/helpers.py
This commit is contained in:
@@ -20,8 +20,12 @@ test-driven methodologies, and modern toolchains for unrivaled success.
|
|||||||
6.1.14 (2024-??-??)
|
6.1.14 (2024-??-??)
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* Introduced the ``--json-output`` option to the `pio test <https://docs.platformio.org/en/latest/core/userguide/cmd_test.html>`__ command, enabling users to generate test results in the JSON format
|
||||||
* Broadened version support for the ``pyelftools`` dependency, enabling compatibility with lower versions and facilitating integration with a wider range of third-party tools (`issue #4834 <https://github.com/platformio/platformio-core/issues/4834>`_)
|
* Broadened version support for the ``pyelftools`` dependency, enabling compatibility with lower versions and facilitating integration with a wider range of third-party tools (`issue #4834 <https://github.com/platformio/platformio-core/issues/4834>`_)
|
||||||
|
* Addressed an issue where passing a relative path (``--project-dir``) to the `pio project init <https://docs.platformio.org/en/latest/core/userguide/project/cmd_init.html>`__ command resulted in an error (`issue #4847 <https://github.com/platformio/platformio-core/issues/4847>`_)
|
||||||
* Resolved an issue related to the relative package path in the `pio pkg publish <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_publish.html>`__ command
|
* Resolved an issue related to the relative package path in the `pio pkg publish <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_publish.html>`__ command
|
||||||
|
* Resolved an issue where the |LDF| selected an incorrect library version (`issue #4860 <https://github.com/platformio/platformio-core/issues/4860>`_)
|
||||||
|
* Resolved an issue with the ``hexlify`` filter in the `device monitor <https://docs.platformio.org/en/latest/core/userguide/device/cmd_monitor.html>`__ command, ensuring proper representation of characters with Unicode code points higher than 127 (`issue #4732 <https://github.com/platformio/platformio-core/issues/4732>`_)
|
||||||
|
|
||||||
6.1.13 (2024-01-12)
|
6.1.13 (2024-01-12)
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
@@ -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, "14a1")
|
VERSION = (6, 1, "14b1")
|
||||||
__version__ = ".".join([str(s) for s in VERSION])
|
__version__ = ".".join([str(s) for s in VERSION])
|
||||||
|
|
||||||
__title__ = "platformio"
|
__title__ = "platformio"
|
||||||
|
@@ -36,6 +36,8 @@ ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", MODE:="0666", ENV{ID_MM_DEVIC
|
|||||||
|
|
||||||
# QinHeng Electronics HL-340 USB-Serial adapter
|
# QinHeng Electronics HL-340 USB-Serial adapter
|
||||||
ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
|
ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
|
||||||
|
# QinHeng Electronics CH343 USB-Serial adapter
|
||||||
|
ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d3", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
|
||||||
# QinHeng Electronics CH9102 USB-Serial adapter
|
# QinHeng Electronics CH9102 USB-Serial adapter
|
||||||
ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
|
ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
|
||||||
|
|
||||||
@@ -85,6 +87,8 @@ ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="[01]*", MODE:="0666", ENV{ID_MM_DEVI
|
|||||||
# AIR32F103
|
# AIR32F103
|
||||||
ATTRS{idVendor}=="0d28", ATTRS{idProduct}=="0204", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
|
ATTRS{idVendor}=="0d28", ATTRS{idProduct}=="0204", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
|
||||||
|
|
||||||
|
# STM32 virtual COM port
|
||||||
|
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Debuggers
|
# Debuggers
|
||||||
|
@@ -45,7 +45,16 @@ def scons_patched_match_splitext(path, suffixes=None):
|
|||||||
|
|
||||||
|
|
||||||
def GetBuildType(env):
|
def GetBuildType(env):
|
||||||
return env["BUILD_TYPE"]
|
modes = []
|
||||||
|
if (
|
||||||
|
set(["__debug", "sizedata"]) # sizedata = for memory inspection
|
||||||
|
& set(COMMAND_LINE_TARGETS)
|
||||||
|
or env.GetProjectOption("build_type") == "debug"
|
||||||
|
):
|
||||||
|
modes.append("debug")
|
||||||
|
if "__test" in COMMAND_LINE_TARGETS or env.GetProjectOption("build_type") == "test":
|
||||||
|
modes.append("test")
|
||||||
|
return ", ".join(modes or ["release"])
|
||||||
|
|
||||||
|
|
||||||
def BuildProgram(env):
|
def BuildProgram(env):
|
||||||
@@ -65,7 +74,7 @@ def BuildProgram(env):
|
|||||||
env.Prepend(_LIBFLAGS="-Wl,--start-group ")
|
env.Prepend(_LIBFLAGS="-Wl,--start-group ")
|
||||||
env.Append(_LIBFLAGS=" -Wl,--end-group")
|
env.Append(_LIBFLAGS=" -Wl,--end-group")
|
||||||
|
|
||||||
program = env.Program(env.subst("$PROGPATH"), env.get("PIOBUILDFILES", []))
|
program = env.Program(env.subst("$PROGPATH"), env["PIOBUILDFILES"])
|
||||||
env.Replace(PIOMAINPROG=program)
|
env.Replace(PIOMAINPROG=program)
|
||||||
|
|
||||||
AlwaysBuild(
|
AlwaysBuild(
|
||||||
@@ -153,9 +162,6 @@ def ProcessProjectDeps(env):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if env.IsIntegrationDump():
|
|
||||||
return
|
|
||||||
|
|
||||||
if "test" in env["BUILD_TYPE"]:
|
if "test" in env["BUILD_TYPE"]:
|
||||||
build_files_before_nums = len(env.get("PIOBUILDFILES", []))
|
build_files_before_nums = len(env.get("PIOBUILDFILES", []))
|
||||||
plb.env.BuildSources(
|
plb.env.BuildSources(
|
||||||
|
@@ -309,10 +309,10 @@ class LibBuilderBase:
|
|||||||
if not self.dependencies or self._deps_are_processed:
|
if not self.dependencies or self._deps_are_processed:
|
||||||
return
|
return
|
||||||
self._deps_are_processed = True
|
self._deps_are_processed = True
|
||||||
for item in self.dependencies:
|
for dependency in self.dependencies:
|
||||||
found = False
|
found = False
|
||||||
for lb in self.env.GetLibBuilders():
|
for lb in self.env.GetLibBuilders():
|
||||||
if item["name"] != lb.name:
|
if not lb.is_dependency_compatible(dependency):
|
||||||
continue
|
continue
|
||||||
found = True
|
found = True
|
||||||
if lb not in self.depbuilders:
|
if lb not in self.depbuilders:
|
||||||
@@ -322,9 +322,20 @@ class LibBuilderBase:
|
|||||||
if not found and self.verbose:
|
if not found and self.verbose:
|
||||||
sys.stderr.write(
|
sys.stderr.write(
|
||||||
"Warning: Ignored `%s` dependency for `%s` "
|
"Warning: Ignored `%s` dependency for `%s` "
|
||||||
"library\n" % (item["name"], self.name)
|
"library\n" % (dependency["name"], self.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def is_dependency_compatible(self, dependency):
|
||||||
|
pkg = PackageItem(self.path)
|
||||||
|
qualifiers = {"name": self.name, "version": self.version}
|
||||||
|
if pkg.metadata:
|
||||||
|
qualifiers = {"name": pkg.metadata.name, "version": pkg.metadata.version}
|
||||||
|
if pkg.metadata.spec and pkg.metadata.spec.owner:
|
||||||
|
qualifiers["owner"] = pkg.metadata.spec.owner
|
||||||
|
return PackageCompatibility.from_dependency(
|
||||||
|
{k: v for k, v in dependency.items() if k in ("owner", "name", "version")}
|
||||||
|
).is_compatible(PackageCompatibility(**qualifiers))
|
||||||
|
|
||||||
def get_search_files(self):
|
def get_search_files(self):
|
||||||
return [
|
return [
|
||||||
os.path.join(self.src_dir, item)
|
os.path.join(self.src_dir, item)
|
||||||
|
@@ -23,10 +23,10 @@ from SCons.Subst import quote_spaces # pylint: disable=import-error
|
|||||||
from platformio.compat import IS_WINDOWS, hashlib_encode_data
|
from platformio.compat import IS_WINDOWS, hashlib_encode_data
|
||||||
|
|
||||||
# There are the next limits depending on a platform:
|
# There are the next limits depending on a platform:
|
||||||
# - Windows = 8192
|
# - Windows = 8191
|
||||||
# - Unix = 131072
|
# - Unix = 131072
|
||||||
# We need ~512 characters for compiler and temporary file paths
|
# We need ~512 characters for compiler and temporary file paths
|
||||||
MAX_LINE_LENGTH = (8192 if IS_WINDOWS else 131072) - 512
|
MAX_LINE_LENGTH = (8191 if IS_WINDOWS else 131072) - 512
|
||||||
|
|
||||||
WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)")
|
WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)")
|
||||||
|
|
||||||
|
@@ -31,7 +31,7 @@ class DebugConfigBase: # pylint: disable=too-many-instance-attributes
|
|||||||
self.project_config = project_config
|
self.project_config = project_config
|
||||||
self.env_name = env_name
|
self.env_name = env_name
|
||||||
self.env_options = project_config.items(env=env_name, as_dict=True)
|
self.env_options = project_config.items(env=env_name, as_dict=True)
|
||||||
self.build_metadata = self._load_debug_build_metadata()
|
self.build_data = self._load_build_data()
|
||||||
|
|
||||||
self.tool_name = None
|
self.tool_name = None
|
||||||
self.board_config = {}
|
self.board_config = {}
|
||||||
@@ -64,11 +64,11 @@ class DebugConfigBase: # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def program_path(self):
|
def program_path(self):
|
||||||
return self.build_metadata["prog_path"]
|
return self.build_data["prog_path"]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def client_executable_path(self):
|
def client_executable_path(self):
|
||||||
return self.build_metadata["gdb_path"]
|
return self.build_data["gdb_path"]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def load_cmds(self):
|
def load_cmds(self):
|
||||||
@@ -147,13 +147,9 @@ class DebugConfigBase: # pylint: disable=too-many-instance-attributes
|
|||||||
"debug_server_ready_pattern", (self.server or {}).get("ready_pattern")
|
"debug_server_ready_pattern", (self.server or {}).get("ready_pattern")
|
||||||
)
|
)
|
||||||
|
|
||||||
def _load_debug_build_metadata(self):
|
def _load_build_data(self):
|
||||||
data = load_build_metadata(
|
data = load_build_metadata(
|
||||||
None,
|
os.getcwd(), self.env_name, cache=True, build_type="debug"
|
||||||
self.env_name,
|
|
||||||
cache=True,
|
|
||||||
debug=True,
|
|
||||||
test=self.env_options.get("debug_test", False),
|
|
||||||
)
|
)
|
||||||
if not data:
|
if not data:
|
||||||
raise DebugInvalidOptionsError("Could not load a build configuration")
|
raise DebugInvalidOptionsError("Could not load a build configuration")
|
||||||
|
@@ -58,7 +58,7 @@ from platformio.project.options import ProjectOptions
|
|||||||
"--encoding",
|
"--encoding",
|
||||||
help=(
|
help=(
|
||||||
"Set the encoding for the serial port "
|
"Set the encoding for the serial port "
|
||||||
"(e.g. hexlify, Latin1, UTF-8) [default=%s]"
|
"(e.g. hexlify, Latin-1, UTF-8) [default=%s]"
|
||||||
% ProjectOptions["env.monitor_encoding"].default
|
% ProjectOptions["env.monitor_encoding"].default
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@@ -25,11 +25,12 @@ from platformio.project.config import ProjectConfig
|
|||||||
class DeviceMonitorFilterBase(miniterm.Transform):
|
class DeviceMonitorFilterBase(miniterm.Transform):
|
||||||
def __init__(self, options=None):
|
def __init__(self, options=None):
|
||||||
"""Called by PlatformIO to pass context"""
|
"""Called by PlatformIO to pass context"""
|
||||||
miniterm.Transform.__init__(self)
|
super().__init__()
|
||||||
|
|
||||||
self.options = options or {}
|
self.options = options or {}
|
||||||
self.project_dir = self.options.get("project_dir")
|
self.project_dir = self.options.get("project_dir")
|
||||||
self.environment = self.options.get("environment")
|
self.environment = self.options.get("environment")
|
||||||
|
self._running_terminal = None
|
||||||
|
|
||||||
self.config = ProjectConfig.get_instance()
|
self.config = ProjectConfig.get_instance()
|
||||||
if not self.environment:
|
if not self.environment:
|
||||||
@@ -47,6 +48,12 @@ class DeviceMonitorFilterBase(miniterm.Transform):
|
|||||||
def NAME(self):
|
def NAME(self):
|
||||||
raise NotImplementedError("Please declare NAME attribute for the filter class")
|
raise NotImplementedError("Please declare NAME attribute for the filter class")
|
||||||
|
|
||||||
|
def set_running_terminal(self, terminal):
|
||||||
|
self._running_terminal = terminal
|
||||||
|
|
||||||
|
def get_running_terminal(self):
|
||||||
|
return self._running_terminal
|
||||||
|
|
||||||
|
|
||||||
def register_filters(platform=None, options=None):
|
def register_filters(platform=None, options=None):
|
||||||
# project filters
|
# project filters
|
||||||
|
@@ -24,12 +24,18 @@ class Hexlify(DeviceMonitorFilterBase):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self._counter = 0
|
self._counter = 0
|
||||||
|
|
||||||
|
def set_running_terminal(self, terminal):
|
||||||
|
# force to Latin-1, issue #4732
|
||||||
|
if terminal.input_encoding == "UTF-8":
|
||||||
|
terminal.set_rx_encoding("Latin-1")
|
||||||
|
super().set_running_terminal(terminal)
|
||||||
|
|
||||||
def rx(self, text):
|
def rx(self, text):
|
||||||
result = ""
|
result = ""
|
||||||
for b in serial.iterbytes(text):
|
for c in serial.iterbytes(text):
|
||||||
if (self._counter % 16) == 0:
|
if (self._counter % 16) == 0:
|
||||||
result += "\n{:04X} | ".format(self._counter)
|
result += "\n{:04X} | ".format(self._counter)
|
||||||
asciicode = ord(b)
|
asciicode = ord(c)
|
||||||
if asciicode <= 255:
|
if asciicode <= 255:
|
||||||
result += "{:02X} ".format(asciicode)
|
result += "{:02X} ".format(asciicode)
|
||||||
else:
|
else:
|
||||||
|
@@ -110,6 +110,12 @@ def new_terminal(options):
|
|||||||
term.raw = options["raw"]
|
term.raw = options["raw"]
|
||||||
term.set_rx_encoding(options["encoding"])
|
term.set_rx_encoding(options["encoding"])
|
||||||
term.set_tx_encoding(options["encoding"])
|
term.set_tx_encoding(options["encoding"])
|
||||||
|
for ts in (term.tx_transformations, term.rx_transformations):
|
||||||
|
for t in ts:
|
||||||
|
try:
|
||||||
|
t.set_running_terminal(term)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
return term
|
return term
|
||||||
|
|
||||||
|
|
||||||
|
@@ -99,7 +99,11 @@ class PackageManagerInstallMixin:
|
|||||||
pkg = self.install_from_registry(
|
pkg = self.install_from_registry(
|
||||||
spec,
|
spec,
|
||||||
search_qualifiers=(
|
search_qualifiers=(
|
||||||
compatibility.to_search_qualifiers() if compatibility else None
|
compatibility.to_search_qualifiers(
|
||||||
|
["platforms", "frameworks", "authors"]
|
||||||
|
)
|
||||||
|
if compatibility
|
||||||
|
else None
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -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.22"
|
version = "3.23"
|
||||||
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"
|
||||||
|
@@ -65,7 +65,14 @@ class PackageType:
|
|||||||
|
|
||||||
|
|
||||||
class PackageCompatibility:
|
class PackageCompatibility:
|
||||||
KNOWN_QUALIFIERS = ("platforms", "frameworks", "authors")
|
KNOWN_QUALIFIERS = (
|
||||||
|
"owner",
|
||||||
|
"name",
|
||||||
|
"version",
|
||||||
|
"platforms",
|
||||||
|
"frameworks",
|
||||||
|
"authors",
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dependency(cls, dependency):
|
def from_dependency(cls, dependency):
|
||||||
@@ -89,19 +96,45 @@ class PackageCompatibility:
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "PackageCompatibility <%s>" % self.qualifiers
|
return "PackageCompatibility <%s>" % self.qualifiers
|
||||||
|
|
||||||
def to_search_qualifiers(self):
|
def to_search_qualifiers(self, fields=None):
|
||||||
return self.qualifiers
|
result = {}
|
||||||
|
for name, value in self.qualifiers.items():
|
||||||
|
if not fields or name in fields:
|
||||||
|
result[name] = value
|
||||||
|
return result
|
||||||
|
|
||||||
def is_compatible(self, other):
|
def is_compatible(self, other):
|
||||||
assert isinstance(other, PackageCompatibility)
|
assert isinstance(other, PackageCompatibility)
|
||||||
for key, value in self.qualifiers.items():
|
for key, current_value in self.qualifiers.items():
|
||||||
other_value = other.qualifiers.get(key)
|
other_value = other.qualifiers.get(key)
|
||||||
if not value or not other_value:
|
if not current_value or not other_value:
|
||||||
continue
|
continue
|
||||||
if not items_in_list(value, other_value):
|
if any(isinstance(v, list) for v in (current_value, other_value)):
|
||||||
|
if not items_in_list(current_value, other_value):
|
||||||
|
return False
|
||||||
|
continue
|
||||||
|
if key == "version":
|
||||||
|
if not self._compare_versions(current_value, other_value):
|
||||||
|
return False
|
||||||
|
continue
|
||||||
|
if current_value != other_value:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _compare_versions(self, current, other):
|
||||||
|
if current == other:
|
||||||
|
return True
|
||||||
|
try:
|
||||||
|
version = (
|
||||||
|
other
|
||||||
|
if isinstance(other, semantic_version.Version)
|
||||||
|
else cast_version_to_semver(other)
|
||||||
|
)
|
||||||
|
return version in semantic_version.SimpleSpec(current)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class PackageOutdatedResult:
|
class PackageOutdatedResult:
|
||||||
UPDATE_INCREMENT_MAJOR = "major"
|
UPDATE_INCREMENT_MAJOR = "major"
|
||||||
|
@@ -35,7 +35,7 @@ def get_pip_dependencies():
|
|||||||
home = [
|
home = [
|
||||||
# PIO Home requirements
|
# PIO Home requirements
|
||||||
"ajsonrpc == 1.2.*",
|
"ajsonrpc == 1.2.*",
|
||||||
"starlette >=0.19, <0.36",
|
"starlette >=0.19, <0.38",
|
||||||
"uvicorn %s" % ("== 0.16.0" if PY36 else ">=0.16, <0.28"),
|
"uvicorn %s" % ("== 0.16.0" if PY36 else ">=0.16, <0.28"),
|
||||||
"wsproto == 1.*",
|
"wsproto == 1.*",
|
||||||
]
|
]
|
||||||
|
@@ -79,6 +79,7 @@ def project_init_cmd(
|
|||||||
env_prefix,
|
env_prefix,
|
||||||
silent,
|
silent,
|
||||||
):
|
):
|
||||||
|
project_dir = os.path.abspath(project_dir)
|
||||||
is_new_project = not is_platformio_project(project_dir)
|
is_new_project = not is_platformio_project(project_dir)
|
||||||
if is_new_project:
|
if is_new_project:
|
||||||
if not silent:
|
if not silent:
|
||||||
@@ -223,7 +224,7 @@ def init_lib_readme(lib_dir):
|
|||||||
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 executable file.
|
||||||
|
|
||||||
The source code of each library should be placed in a an own separate directory
|
The source code of each library should be placed in an own separate directory
|
||||||
("lib/your_library_name/[here are source files]").
|
("lib/your_library_name/[here are source files]").
|
||||||
|
|
||||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||||
|
@@ -12,7 +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 hashlib
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -29,12 +28,6 @@ def get_project_dir():
|
|||||||
return os.getcwd()
|
return os.getcwd()
|
||||||
|
|
||||||
|
|
||||||
def get_project_id(project_dir=None):
|
|
||||||
return hashlib.sha1(
|
|
||||||
hashlib_encode_data(project_dir or get_project_dir())
|
|
||||||
).hexdigest()
|
|
||||||
|
|
||||||
|
|
||||||
def is_platformio_project(project_dir=None):
|
def is_platformio_project(project_dir=None):
|
||||||
if not project_dir:
|
if not project_dir:
|
||||||
project_dir = get_project_dir()
|
project_dir = get_project_dir()
|
||||||
@@ -138,36 +131,27 @@ def compute_project_checksum(config):
|
|||||||
return checksum.hexdigest()
|
return checksum.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def get_build_type(config, env, run_targets=None):
|
def load_build_metadata(project_dir, env_or_envs, cache=False, build_type=None):
|
||||||
types = []
|
|
||||||
run_targets = run_targets or []
|
|
||||||
declared_build_type = config.get(f"env:{env}", "build_type")
|
|
||||||
if (
|
|
||||||
set(["__debug", "__memusage"]) & set(run_targets)
|
|
||||||
or declared_build_type == "debug"
|
|
||||||
):
|
|
||||||
types.append("debug")
|
|
||||||
if "__test" in run_targets or declared_build_type == "test":
|
|
||||||
types.append("test")
|
|
||||||
return "+".join(types or ["release"])
|
|
||||||
|
|
||||||
|
|
||||||
def load_build_metadata(project_dir, env_or_envs, cache=False, debug=False, test=False):
|
|
||||||
assert env_or_envs
|
assert env_or_envs
|
||||||
envs = env_or_envs
|
env_names = env_or_envs
|
||||||
if not isinstance(envs, list):
|
if not isinstance(env_names, list):
|
||||||
envs = [envs]
|
env_names = [env_names]
|
||||||
run_targets = []
|
|
||||||
if debug:
|
|
||||||
run_targets.append("__debug")
|
|
||||||
if test:
|
|
||||||
run_targets.append("__test")
|
|
||||||
|
|
||||||
with fs.cd(project_dir or os.getcwd()):
|
with fs.cd(project_dir):
|
||||||
result = _get_cached_build_metadata(envs, run_targets) if cache else {}
|
result = _get_cached_build_metadata(env_names) if cache else {}
|
||||||
missed_envs = set(envs) - set(result.keys())
|
# incompatible build-type data
|
||||||
if missed_envs:
|
for env_name in list(result.keys()):
|
||||||
result.update(_load_build_metadata(missed_envs, run_targets))
|
if build_type is None:
|
||||||
|
build_type = ProjectConfig.get_instance().get(
|
||||||
|
f"env:{env_name}", "build_type"
|
||||||
|
)
|
||||||
|
if result[env_name].get("build_type", "") != build_type:
|
||||||
|
del result[env_name]
|
||||||
|
missed_env_names = set(env_names) - set(result.keys())
|
||||||
|
if missed_env_names:
|
||||||
|
result.update(
|
||||||
|
_load_build_metadata(project_dir, missed_env_names, build_type)
|
||||||
|
)
|
||||||
|
|
||||||
if not isinstance(env_or_envs, list) and env_or_envs in result:
|
if not isinstance(env_or_envs, list) and env_or_envs in result:
|
||||||
return result[env_or_envs]
|
return result[env_or_envs]
|
||||||
@@ -178,28 +162,18 @@ def load_build_metadata(project_dir, env_or_envs, cache=False, debug=False, test
|
|||||||
load_project_ide_data = load_build_metadata
|
load_project_ide_data = load_build_metadata
|
||||||
|
|
||||||
|
|
||||||
def _get_cached_build_metadata(envs, run_targets=None):
|
def _load_build_metadata(project_dir, env_names, build_type=None):
|
||||||
config = ProjectConfig.get_instance(os.path.join(os.getcwd(), "platformio.ini"))
|
|
||||||
build_dir = config.get("platformio", "build_dir")
|
|
||||||
result = {}
|
|
||||||
for env in envs:
|
|
||||||
build_type = get_build_type(config, env, run_targets)
|
|
||||||
json_path = os.path.join(build_dir, env, build_type, "metadata.json")
|
|
||||||
if os.path.isfile(json_path):
|
|
||||||
result[env] = fs.load_json(json_path)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def _load_build_metadata(envs, run_targets=None):
|
|
||||||
# pylint: disable=import-outside-toplevel
|
# pylint: disable=import-outside-toplevel
|
||||||
from platformio import app
|
from platformio import app
|
||||||
from platformio.run.cli import cli as cmd_run
|
from platformio.run.cli import cli as cmd_run
|
||||||
|
|
||||||
args = ["--target", "__metadata"]
|
args = ["--project-dir", project_dir, "--target", "__idedata"]
|
||||||
for target in run_targets or []:
|
if build_type == "debug":
|
||||||
args.extend(["--target", target])
|
args.extend(["--target", "__debug"])
|
||||||
for env in envs:
|
# if build_type == "test":
|
||||||
args.extend(["-e", env])
|
# args.extend(["--target", "__test"])
|
||||||
|
for name in env_names:
|
||||||
|
args.extend(["-e", name])
|
||||||
app.set_session_var("pause_telemetry", True)
|
app.set_session_var("pause_telemetry", True)
|
||||||
result = CliRunner().invoke(cmd_run, args)
|
result = CliRunner().invoke(cmd_run, args)
|
||||||
app.set_session_var("pause_telemetry", False)
|
app.set_session_var("pause_telemetry", False)
|
||||||
@@ -207,6 +181,18 @@ def _load_build_metadata(envs, run_targets=None):
|
|||||||
result.exception, exception.ReturnErrorCode
|
result.exception, exception.ReturnErrorCode
|
||||||
):
|
):
|
||||||
raise result.exception
|
raise result.exception
|
||||||
if "Metadata has been saved to the following location" not in result.output:
|
if '"includes":' not in result.output:
|
||||||
raise exception.UserSideException(result.output)
|
raise exception.UserSideException(result.output)
|
||||||
return _get_cached_build_metadata(envs, run_targets)
|
return _get_cached_build_metadata(env_names)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_cached_build_metadata(env_names):
|
||||||
|
build_dir = ProjectConfig.get_instance().get("platformio", "build_dir")
|
||||||
|
result = {}
|
||||||
|
for env_name in env_names:
|
||||||
|
if not os.path.isfile(os.path.join(build_dir, env_name, "idedata.json")):
|
||||||
|
continue
|
||||||
|
result[env_name] = fs.load_json(
|
||||||
|
os.path.join(build_dir, env_name, "idedata.json")
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
@@ -560,7 +560,7 @@ ProjectOptions = OrderedDict(
|
|||||||
ConfigEnvOption(
|
ConfigEnvOption(
|
||||||
group="monitor",
|
group="monitor",
|
||||||
name="monitor_encoding",
|
name="monitor_encoding",
|
||||||
description="Custom encoding (e.g. hexlify, Latin1, UTF-8)",
|
description="Custom encoding (e.g. hexlify, Latin-1, UTF-8)",
|
||||||
default="UTF-8",
|
default="UTF-8",
|
||||||
),
|
),
|
||||||
# Library
|
# Library
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
@@ -79,6 +80,7 @@ from platformio.test.runners.factory import TestRunnerFactory
|
|||||||
help="A program argument (multiple are allowed)",
|
help="A program argument (multiple are allowed)",
|
||||||
)
|
)
|
||||||
@click.option("--list-tests", is_flag=True)
|
@click.option("--list-tests", is_flag=True)
|
||||||
|
@click.option("--json-output", is_flag=True)
|
||||||
@click.option("--json-output-path", type=click.Path())
|
@click.option("--json-output-path", type=click.Path())
|
||||||
@click.option("--junit-output-path", type=click.Path())
|
@click.option("--junit-output-path", type=click.Path())
|
||||||
@click.option(
|
@click.option(
|
||||||
@@ -105,6 +107,7 @@ def cli( # pylint: disable=too-many-arguments,too-many-locals,redefined-builtin
|
|||||||
monitor_dtr,
|
monitor_dtr,
|
||||||
program_args,
|
program_args,
|
||||||
list_tests,
|
list_tests,
|
||||||
|
json_output,
|
||||||
json_output_path,
|
json_output_path,
|
||||||
junit_output_path,
|
junit_output_path,
|
||||||
verbose,
|
verbose,
|
||||||
@@ -156,6 +159,7 @@ def cli( # pylint: disable=too-many-arguments,too-many-locals,redefined-builtin
|
|||||||
stdout_report.generate(verbose=verbose or list_tests)
|
stdout_report.generate(verbose=verbose or list_tests)
|
||||||
|
|
||||||
for output_format, output_path in [
|
for output_format, output_path in [
|
||||||
|
("json", subprocess.STDOUT if json_output else None),
|
||||||
("json", json_output_path),
|
("json", json_output_path),
|
||||||
("junit", junit_output_path),
|
("junit", junit_output_path),
|
||||||
]:
|
]:
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
@@ -24,6 +25,9 @@ from platformio.test.result import TestStatus
|
|||||||
|
|
||||||
class JsonTestReport(TestReportBase):
|
class JsonTestReport(TestReportBase):
|
||||||
def generate(self, output_path, verbose=False):
|
def generate(self, output_path, verbose=False):
|
||||||
|
if output_path == subprocess.STDOUT:
|
||||||
|
return click.echo("\n\n" + json.dumps(self.to_json()))
|
||||||
|
|
||||||
if os.path.isdir(output_path):
|
if os.path.isdir(output_path):
|
||||||
output_path = os.path.join(
|
output_path = os.path.join(
|
||||||
output_path,
|
output_path,
|
||||||
@@ -40,6 +44,8 @@ class JsonTestReport(TestReportBase):
|
|||||||
if verbose:
|
if verbose:
|
||||||
click.secho(f"Saved JSON report to the {output_path}", fg="green")
|
click.secho(f"Saved JSON report to the {output_path}", fg="green")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
result = dict(
|
result = dict(
|
||||||
version="1.0",
|
version="1.0",
|
||||||
|
@@ -184,10 +184,6 @@ void unityOutputComplete(void) { unittest_uart_end(); }
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Delete when Unity > 2.5.2 is released"""
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def get_unity_framework_config(self):
|
def get_unity_framework_config(self):
|
||||||
if not self.platform.is_embedded():
|
if not self.platform.is_embedded():
|
||||||
return self.UNITY_FRAMEWORK_CONFIG["native"]
|
return self.UNITY_FRAMEWORK_CONFIG["native"]
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from platformio import fs
|
||||||
from platformio.commands.boards import cli as cmd_boards
|
from platformio.commands.boards import cli as cmd_boards
|
||||||
from platformio.project.commands.init import project_init_cmd
|
from platformio.project.commands.init import project_init_cmd
|
||||||
from platformio.project.config import ProjectConfig
|
from platformio.project.config import ProjectConfig
|
||||||
@@ -36,25 +37,26 @@ def test_init_default(clirunner, validate_cliresult):
|
|||||||
validate_pioproject(os.getcwd())
|
validate_pioproject(os.getcwd())
|
||||||
|
|
||||||
|
|
||||||
def test_init_ext_folder(clirunner, validate_cliresult):
|
|
||||||
with clirunner.isolated_filesystem():
|
|
||||||
ext_folder_name = "ext_folder"
|
|
||||||
os.makedirs(ext_folder_name)
|
|
||||||
result = clirunner.invoke(project_init_cmd, ["-d", ext_folder_name])
|
|
||||||
validate_cliresult(result)
|
|
||||||
validate_pioproject(os.path.join(os.getcwd(), ext_folder_name))
|
|
||||||
|
|
||||||
|
|
||||||
def test_init_duplicated_boards(clirunner, validate_cliresult, tmpdir):
|
def test_init_duplicated_boards(clirunner, validate_cliresult, tmpdir):
|
||||||
with tmpdir.as_cwd():
|
project_dir = str(tmpdir.join("ext_folder"))
|
||||||
for _ in range(2):
|
os.makedirs(project_dir)
|
||||||
|
|
||||||
|
with fs.cd(os.path.dirname(project_dir)):
|
||||||
result = clirunner.invoke(
|
result = clirunner.invoke(
|
||||||
project_init_cmd,
|
project_init_cmd,
|
||||||
["-b", "uno", "-b", "uno", "--no-install-dependencies"],
|
[
|
||||||
|
"-d",
|
||||||
|
os.path.basename(project_dir),
|
||||||
|
"-b",
|
||||||
|
"uno",
|
||||||
|
"-b",
|
||||||
|
"uno",
|
||||||
|
"--no-install-dependencies",
|
||||||
|
],
|
||||||
)
|
)
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
validate_pioproject(str(tmpdir))
|
validate_pioproject(project_dir)
|
||||||
config = ProjectConfig(os.path.join(os.getcwd(), "platformio.ini"))
|
config = ProjectConfig(os.path.join(project_dir, "platformio.ini"))
|
||||||
config.validate()
|
config.validate()
|
||||||
assert set(config.sections()) == set(["env:uno"])
|
assert set(config.sections()) == set(["env:uno"])
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user