diff --git a/.isort.cfg b/.isort.cfg deleted file mode 100644 index 7d21b117..00000000 --- a/.isort.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[settings] -line_length=88 -known_third_party=OpenSSL, SCons, jsonrpc, twisted, zope diff --git a/HISTORY.rst b/HISTORY.rst index 5687765d..7a93f630 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -8,12 +8,21 @@ PlatformIO Core 5 **A professional collaborative platform for embedded development** +5.1.1 (2021-03-17) +~~~~~~~~~~~~~~~~~~ + +* Fixed a "The command line is too long" issue with a linking process on Windows (`issue #3827 `_) +* Fixed an issue with `device monitor `__ when the "send_on_enter" filter didn't send EOL chars (`issue #3787 `_) +* Fixed an issue with silent mode when unwanted data is printed to stdout (`issue #3837 `_) +* Fixed an issue when code inspection fails with "Bad JSON" (`issue #3790 `_) +* Fixed an issue with overriding user-specified debugging configuration information in VSCode (`issue #3824 `_) + 5.1.0 (2021-01-28) ~~~~~~~~~~~~~~~~~~ * **PlatformIO Home** - - Boosted PlatformIO Home performance thanks to migrating the codebase to the pure Python 3 Asynchronous I/O stack + - Boosted `PlatformIO Home `__ performance thanks to migrating the codebase to the pure Python 3 Asynchronous I/O stack - Added a new ``--session-id`` option to `pio home `__ command that helps to keep PlatformIO Home isolated from other instances and protect from 3rd party access (`issue #3397 `_) * **Build System** @@ -45,7 +54,7 @@ PlatformIO Core 5 - Improved listing of `multicast DNS services `_ - Fixed a "UnicodeDecodeError: 'utf-8' codec can't decode byte" when using J-Link for firmware uploading on Linux (`issue #3804 `_) - Fixed an issue with a compiler driver for ".ccls" language server (`issue #3808 `_) - - Fixed an issue when `pio device monitor --eol `__ and "send_on_enter" filter do not work properly (`issue #3787 `_) + - Fixed an issue when `pio device monitor --eol `__ and "send_on_enter" filter do not work properly (`issue #3787 `_) 5.0.4 (2020-12-30) ~~~~~~~~~~~~~~~~~~ diff --git a/docs b/docs index 25edd66d..3293903c 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 25edd66d5514cc5a0c8d5a01f4752de3e98a03d0 +Subproject commit 3293903cac7c050908b594a838bd5a220e47e2c6 diff --git a/examples b/examples index 8a6e639b..a0631a8b 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 8a6e639b2bcb18dec63bc010f359b49f85084b45 +Subproject commit a0631a8b07f01de96eb5e0431798b41c7ab8f23e diff --git a/platformio/__init__.py b/platformio/__init__.py index 5ed64a4e..56d356cb 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (5, 1, 0) +VERSION = (5, 1, 1) __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" @@ -47,7 +47,7 @@ __pioremote_endpoint__ = "ssl:host=remote.platformio.org:port=4413" __default_requests_timeout__ = (10, None) # (connect, read) __core_packages__ = { - "contrib-piohome": "~3.3.3", + "contrib-piohome": "~3.3.4", "contrib-pysite": "~2.%d%d.0" % (sys.version_info.major, sys.version_info.minor), "tool-unity": "~1.20500.0", "tool-scons": "~2.20501.7" if sys.version_info.major == 2 else "~4.40100.2", diff --git a/platformio/builder/tools/piomaxlen.py b/platformio/builder/tools/piomaxlen.py index d386bd14..0059dcf3 100644 --- a/platformio/builder/tools/piomaxlen.py +++ b/platformio/builder/tools/piomaxlen.py @@ -26,8 +26,8 @@ from platformio.compat import WINDOWS, hashlib_encode_data # There are the next limits depending on a platform: # - Windows = 8192 # - Unix = 131072 -# We need ~256 characters for a temporary file path -MAX_LINE_LENGTH = (8192 if WINDOWS else 131072) - 256 +# We need ~512 characters for compiler and temporary file paths +MAX_LINE_LENGTH = (8192 if WINDOWS else 131072) - 512 WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") diff --git a/platformio/builder/tools/pioplatform.py b/platformio/builder/tools/pioplatform.py index 7dd36a64..dc7f67bf 100644 --- a/platformio/builder/tools/pioplatform.py +++ b/platformio/builder/tools/pioplatform.py @@ -52,6 +52,7 @@ def BoardConfig(env, board=None): except (AssertionError, UnknownBoard) as e: sys.stderr.write("Error: %s\n" % str(e)) env.Exit(1) + return None def GetFrameworkScript(env, framework): diff --git a/platformio/commands/check/tools/cppcheck.py b/platformio/commands/check/tools/cppcheck.py index 46d15d07..c1fe3e3b 100644 --- a/platformio/commands/check/tools/cppcheck.py +++ b/platformio/commands/check/tools/cppcheck.py @@ -96,14 +96,13 @@ class CppcheckCheckTool(CheckToolBase): ) click.echo() self._bad_input = True + self._buffer = "" return None self._buffer = "" return DefectItem(**args) - def configure_command( - self, language, src_files - ): # pylint: disable=arguments-differ + def configure_command(self, language, src_file): # pylint: disable=arguments-differ tool_path = os.path.join(get_core_package_dir("tool-cppcheck"), "cppcheck") cmd = [ @@ -157,8 +156,8 @@ class CppcheckCheckTool(CheckToolBase): "--include=" + inc for inc in self.get_forced_includes(build_flags, self.cpp_includes) ) - cmd.append("--file-list=%s" % self._generate_src_file(src_files)) cmd.append("--includes-file=%s" % self._generate_inc_file()) + cmd.append('"%s"' % src_file) return cmd @@ -227,23 +226,25 @@ class CppcheckCheckTool(CheckToolBase): def check(self, on_defect_callback=None): self._on_defect_callback = on_defect_callback - project_files = self.get_project_target_files(self.options["patterns"]) - languages = ("c", "c++") - if not any([project_files[t] for t in languages]): + project_files = self.get_project_target_files(self.options["patterns"]) + src_files_scope = ("c", "c++") + if not any(project_files[t] for t in src_files_scope): click.echo("Error: Nothing to check.") return True - for language in languages: - if not project_files[language]: - continue - cmd = self.configure_command(language, project_files[language]) - if not cmd: - self._bad_input = True - continue - if self.options.get("verbose"): - click.echo(" ".join(cmd)) - self.execute_check_cmd(cmd) + for scope, files in project_files.items(): + if scope not in src_files_scope: + continue + for src_file in files: + cmd = self.configure_command(scope, src_file) + if not cmd: + self._bad_input = True + continue + if self.options.get("verbose"): + click.echo(" ".join(cmd)) + + self.execute_check_cmd(cmd) self.clean_up() diff --git a/platformio/commands/check/tools/pvsstudio.py b/platformio/commands/check/tools/pvsstudio.py index 88b1a513..d4dde208 100644 --- a/platformio/commands/check/tools/pvsstudio.py +++ b/platformio/commands/check/tools/pvsstudio.py @@ -187,7 +187,13 @@ class PvsStudioCheckTool(CheckToolBase): # pylint: disable=too-many-instance-at flags = self.cc_flags compiler = self.cc_path - cmd = [compiler, src_file, "-E", "-o", self._tmp_preprocessed_file] + cmd = [ + compiler, + '"%s"' % src_file, + "-E", + "-o", + '"%s"' % self._tmp_preprocessed_file, + ] cmd.extend([f for f in flags if f]) cmd.extend(["-D%s" % d for d in self.cpp_defines]) cmd.append('@"%s"' % self._tmp_cmd_file) diff --git a/platformio/commands/debug/helpers.py b/platformio/commands/debug/helpers.py index 7561c338..e2935b5a 100644 --- a/platformio/commands/debug/helpers.py +++ b/platformio/commands/debug/helpers.py @@ -192,7 +192,7 @@ def configure_esp32_load_cmds(debug_options, configuration): debug_options["load_cmds"] != ["load"], "xtensa-esp32" not in configuration.get("cc_path", ""), not flash_images, - not all([isfile(item["path"]) for item in flash_images]), + not all(isfile(item["path"]) for item in flash_images), ] if any(ignore_conds): return debug_options["load_cmds"] diff --git a/platformio/commands/device/filters/send_on_enter.py b/platformio/commands/device/filters/send_on_enter.py index 8300c980..50b730cc 100644 --- a/platformio/commands/device/filters/send_on_enter.py +++ b/platformio/commands/device/filters/send_on_enter.py @@ -32,7 +32,7 @@ class SendOnEnter(DeviceMonitorFilter): def tx(self, text): self._buffer += text if self._buffer.endswith(self._eol): - text = self._buffer[: len(self._eol) * -1] + text = self._buffer self._buffer = "" return text return "" diff --git a/platformio/commands/home/rpc/handlers/account.py b/platformio/commands/home/rpc/handlers/account.py index 337d780a..5336d600 100644 --- a/platformio/commands/home/rpc/handlers/account.py +++ b/platformio/commands/home/rpc/handlers/account.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import jsonrpc +from ajsonrpc.core import JSONRPC20DispatchException from platformio.clients.account import AccountClient @@ -24,6 +24,6 @@ class AccountRPC: client = AccountClient() return getattr(client, method)(*args, **kwargs) except Exception as e: # pylint: disable=bare-except - raise jsonrpc.exceptions.JSONRPCDispatchException( + raise JSONRPC20DispatchException( code=4003, message="PIO Account Call Error", data=str(e) ) diff --git a/platformio/commands/home/rpc/handlers/ide.py b/platformio/commands/home/rpc/handlers/ide.py index ed95b738..bacf8391 100644 --- a/platformio/commands/home/rpc/handlers/ide.py +++ b/platformio/commands/home/rpc/handlers/ide.py @@ -14,7 +14,7 @@ import time -import jsonrpc +from ajsonrpc.core import JSONRPC20DispatchException from platformio.compat import get_running_loop @@ -25,7 +25,7 @@ class IDERPC: def send_command(self, sid, command, params): if not self._queue.get(sid): - raise jsonrpc.exceptions.JSONRPCDispatchException( + raise JSONRPC20DispatchException( code=4005, message="PIO Home IDE agent is not started" ) while self._queue[sid]: @@ -33,11 +33,11 @@ class IDERPC: {"id": time.time(), "method": command, "params": params} ) - def listen_commands(self, sid=0): + async def listen_commands(self, sid=0): if sid not in self._queue: self._queue[sid] = [] self._queue[sid].append(get_running_loop().create_future()) - return self._queue[sid][-1] + return await self._queue[sid][-1] def open_project(self, sid, project_dir): return self.send_command(sid, "open_project", project_dir) diff --git a/platformio/commands/home/rpc/handlers/piocore.py b/platformio/commands/home/rpc/handlers/piocore.py index d74095ab..52a1b126 100644 --- a/platformio/commands/home/rpc/handlers/piocore.py +++ b/platformio/commands/home/rpc/handlers/piocore.py @@ -20,7 +20,7 @@ import sys from io import StringIO import click -import jsonrpc +from ajsonrpc.core import JSONRPC20DispatchException from starlette.concurrency import run_in_threadpool from platformio import __main__, __version__, fs, proc @@ -99,7 +99,7 @@ class PIOCoreRPC: result = await PIOCoreRPC._call_subprocess(args, options) return PIOCoreRPC._process_result(result, to_json) except Exception as e: # pylint: disable=bare-except - raise jsonrpc.exceptions.JSONRPCDispatchException( + raise JSONRPC20DispatchException( code=4003, message="PIO Core Call Error", data=str(e) ) diff --git a/platformio/commands/home/rpc/handlers/project.py b/platformio/commands/home/rpc/handlers/project.py index c8ec6f54..cb8eda5a 100644 --- a/platformio/commands/home/rpc/handlers/project.py +++ b/platformio/commands/home/rpc/handlers/project.py @@ -18,7 +18,7 @@ import os import shutil import time -import jsonrpc +from ajsonrpc.core import JSONRPC20DispatchException from platformio import exception, fs from platformio.commands.home.rpc.handlers.app import AppRPC @@ -257,18 +257,16 @@ class ProjectRPC: return arduino_project_dir is_arduino_project = any( - [ - os.path.isfile( - os.path.join( - arduino_project_dir, - "%s.%s" % (os.path.basename(arduino_project_dir), ext), - ) + os.path.isfile( + os.path.join( + arduino_project_dir, + "%s.%s" % (os.path.basename(arduino_project_dir), ext), ) - for ext in ("ino", "pde") - ] + ) + for ext in ("ino", "pde") ) if not is_arduino_project: - raise jsonrpc.exceptions.JSONRPCDispatchException( + raise JSONRPC20DispatchException( code=4000, message="Not an Arduino project: %s" % arduino_project_dir ) @@ -303,7 +301,7 @@ class ProjectRPC: @staticmethod async def import_pio(project_dir): if not project_dir or not is_platformio_project(project_dir): - raise jsonrpc.exceptions.JSONRPCDispatchException( + raise JSONRPC20DispatchException( code=4001, message="Not an PlatformIO project: %s" % project_dir ) new_project_dir = os.path.join( diff --git a/platformio/commands/home/rpc/server.py b/platformio/commands/home/rpc/server.py index 8ba41da9..6aef10e3 100644 --- a/platformio/commands/home/rpc/server.py +++ b/platformio/commands/home/rpc/server.py @@ -12,14 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import inspect -import json - import click -import jsonrpc +from ajsonrpc.dispatcher import Dispatcher +from ajsonrpc.manager import AsyncJSONRPCResponseManager from starlette.endpoints import WebSocketEndpoint -from platformio.compat import create_task, get_running_loop, is_bytes +from platformio.compat import create_task, get_running_loop from platformio.proc import force_exit @@ -30,13 +28,15 @@ class JSONRPCServerFactoryBase: def __init__(self, shutdown_timeout=0): self.shutdown_timeout = shutdown_timeout - self.dispatcher = jsonrpc.Dispatcher() + self.manager = AsyncJSONRPCResponseManager( + Dispatcher(), is_server_error_verbose=True + ) def __call__(self, *args, **kwargs): raise NotImplementedError - def addHandler(self, handler, namespace): - self.dispatcher.build_method_map(handler, prefix="%s." % namespace) + def addObjectHandler(self, handler, namespace): + self.manager.dispatcher.add_object(handler, prefix="%s." % namespace) def on_client_connect(self): self.connection_nums += 1 @@ -90,29 +90,8 @@ class WebSocketJSONRPCServer(WebSocketEndpoint): self.factory.on_client_disconnect() # pylint: disable=no-member async def _handle_rpc(self, websocket, data): - response = jsonrpc.JSONRPCResponseManager.handle( - data, self.factory.dispatcher # pylint: disable=no-member - ) - if response.result and inspect.isawaitable(response.result): - try: - response.result = await response.result - response.data["result"] = response.result - response.error = None - except Exception as exc: # pylint: disable=broad-except - if not isinstance(exc, jsonrpc.exceptions.JSONRPCDispatchException): - exc = jsonrpc.exceptions.JSONRPCDispatchException( - code=4999, message=str(exc) - ) - response.result = None - response.error = exc.error._data # pylint: disable=protected-access - new_data = response.data.copy() - new_data["error"] = response.error - del new_data["result"] - response.data = new_data - + # pylint: disable=no-member + response = await self.factory.manager.get_response_for_payload(data) if response.error: - click.secho("Error: %s" % response.error, fg="red", err=True) - if "result" in response.data and is_bytes(response.data["result"]): - response.data["result"] = response.data["result"].decode("utf-8") - - await websocket.send_text(json.dumps(response.data)) + click.secho("Error: %s" % response.error.data, fg="red", err=True) + await websocket.send_text(self.factory.manager.serialize(response.body)) diff --git a/platformio/commands/home/run.py b/platformio/commands/home/run.py index 6e93cc2b..4e225720 100644 --- a/platformio/commands/home/run.py +++ b/platformio/commands/home/run.py @@ -65,13 +65,13 @@ def run_server(host, port, no_open, shutdown_timeout, home_url): raise PlatformioException("Invalid path to PIO Home Contrib") ws_rpc_factory = WebSocketJSONRPCServerFactory(shutdown_timeout) - ws_rpc_factory.addHandler(AccountRPC(), namespace="account") - ws_rpc_factory.addHandler(AppRPC(), namespace="app") - ws_rpc_factory.addHandler(IDERPC(), namespace="ide") - ws_rpc_factory.addHandler(MiscRPC(), namespace="misc") - ws_rpc_factory.addHandler(OSRPC(), namespace="os") - ws_rpc_factory.addHandler(PIOCoreRPC(), namespace="core") - ws_rpc_factory.addHandler(ProjectRPC(), namespace="project") + ws_rpc_factory.addObjectHandler(AccountRPC(), namespace="account") + ws_rpc_factory.addObjectHandler(AppRPC(), namespace="app") + ws_rpc_factory.addObjectHandler(IDERPC(), namespace="ide") + ws_rpc_factory.addObjectHandler(MiscRPC(), namespace="misc") + ws_rpc_factory.addObjectHandler(OSRPC(), namespace="os") + ws_rpc_factory.addObjectHandler(PIOCoreRPC(), namespace="core") + ws_rpc_factory.addObjectHandler(ProjectRPC(), namespace="project") path = urlparse(home_url).path routes = [ diff --git a/platformio/commands/test/command.py b/platformio/commands/test/command.py index a4b6634f..07f95226 100644 --- a/platformio/commands/test/command.py +++ b/platformio/commands/test/command.py @@ -25,6 +25,7 @@ from tabulate import tabulate from platformio import app, exception, fs, util from platformio.commands.test.embedded import EmbeddedTestProcessor from platformio.commands.test.native import NativeTestProcessor +from platformio.platform.factory import PlatformFactory from platformio.project.config import ProjectConfig @@ -128,9 +129,9 @@ def cli( # pylint: disable=redefined-builtin not environment and default_envs and envname not in default_envs, testname != "*" and patterns["filter"] - and not any([fnmatch(testname, p) for p in patterns["filter"]]), + and not any(fnmatch(testname, p) for p in patterns["filter"]), testname != "*" - and any([fnmatch(testname, p) for p in patterns["ignore"]]), + and any(fnmatch(testname, p) for p in patterns["ignore"]), ] if any(skip_conditions): results.append({"env": envname, "test": testname}) @@ -140,9 +141,9 @@ def cli( # pylint: disable=redefined-builtin print_processing_header(testname, envname) cls = ( - NativeTestProcessor - if config.get(section, "platform") == "native" - else EmbeddedTestProcessor + EmbeddedTestProcessor + if is_embedded_platform(config.get(section, "platform")) + else NativeTestProcessor ) tp = cls( ctx, @@ -194,6 +195,12 @@ def get_test_names(test_dir): return names +def is_embedded_platform(name): + if not name: + return False + return PlatformFactory.new(name).is_embedded() + + def print_processing_header(test, env): click.echo( "Processing %s in %s environment" diff --git a/platformio/commands/test/embedded.py b/platformio/commands/test/embedded.py index ca658496..02bf675b 100644 --- a/platformio/commands/test/embedded.py +++ b/platformio/commands/test/embedded.py @@ -95,7 +95,7 @@ class EmbeddedTestProcessor(TestProcessorBase): if isinstance(line, bytes): line = line.decode("utf8", "ignore") self.on_run_out(line) - if all([l in line for l in ("Tests", "Failures", "Ignored")]): + if all(l in line for l in ("Tests", "Failures", "Ignored")): break ser.close() return not self._run_failed diff --git a/platformio/ide/tpls/vscode/.vscode/launch.json.tpl b/platformio/ide/tpls/vscode/.vscode/launch.json.tpl index 4acea135..e05c7237 100644 --- a/platformio/ide/tpls/vscode/.vscode/launch.json.tpl +++ b/platformio/ide/tpls/vscode/.vscode/launch.json.tpl @@ -1,50 +1,96 @@ -// AUTOMATICALLY GENERATED FILE. PLEASE DO NOT MODIFY IT MANUALLY - -// PIO Unified Debugger -// -// Documentation: https://docs.platformio.org/page/plus/debugging.html -// Configuration: https://docs.platformio.org/page/projectconf/section_env_debug.html - -% from os.path import dirname, join +% import codecs +% import json +% import os +% +% def _escape(text): +% return text.replace('"', '\"') +% end % % def _escape_path(path): % return path.replace('\\\\', '/').replace('\\', '/').replace('"', '\\"') % end % -{ - "version": "0.2.0", - "configurations": [ - { - "type": "platformio-debug", - "request": "launch", - "name": "PIO Debug", - "executable": "{{ _escape_path(prog_path) }}", - "projectEnvName": "{{ env_name }}", - "toolchainBinDir": "{{ _escape_path(dirname(gdb_path)) }}", -% if svd_path: - "svdPath": "{{ _escape_path(svd_path) }}", +% def get_pio_configurations(): +% predebug = { +% "type": "platformio-debug", +% "request": "launch", +% "name": "PIO Debug (skip Pre-Debug)", +% "executable": _escape_path(prog_path), +% "projectEnvName": env_name, +% "toolchainBinDir": _escape_path(os.path.dirname(gdb_path)), +% "internalConsoleOptions": "openOnSessionStart", +% } +% +% if svd_path: +% predebug["svdPath"] = _escape_path(svd_path) +% end +% debug = predebug.copy() +% debug["name"] = "PIO Debug" +% debug["preLaunchTask"] = { +% "type": "PlatformIO", +% "task": ("Pre-Debug (%s)" % env_name) if len(config.envs()) > 1 else "Pre-Debug", +% } +% return [debug, predebug] % end - "preLaunchTask": { - "type": "PlatformIO", -% if len(config.envs()) > 1: - "task": "Pre-Debug ({{ env_name }})" -% else: - "task": "Pre-Debug" +% +% def _remove_comments(lines): +% data = "" +% for line in lines: +% line = line.strip() +% if not line.startswith("//"): +% data += line +% end +% end +% return data % end - }, - "internalConsoleOptions": "openOnSessionStart" - }, - { - "type": "platformio-debug", - "request": "launch", - "name": "PIO Debug (skip Pre-Debug)", - "executable": "{{ _escape_path(prog_path) }}", - "projectEnvName": "{{ env_name }}", - "toolchainBinDir": "{{ _escape_path(dirname(gdb_path)) }}", -% if svd_path: - "svdPath": "{{ _escape_path(svd_path) }}", +% +% def _contains_external_configurations(launch_config): +% return any( +% c.get("type", "") != "platformio-debug" +% for c in launch_config.get("configurations", []) +% ) % end - "internalConsoleOptions": "openOnSessionStart" - } - ] -} \ No newline at end of file +% +% def _remove_pio_configurations(launch_config): +% if "configurations" not in launch_config: +% return launch_config +% end +% +% external_configurations = [ +% config +% for config in launch_config["configurations"] +% if config.get("type", "") != "platformio-debug" +% ] +% +% launch_config["configurations"] = external_configurations +% return launch_config +% end +% +% def get_launch_configuration(): +% launch_config = {"version": "0.2.0", "configurations": []} +% launch_file = os.path.join(project_dir, ".vscode", "launch.json") +% if os.path.isfile(launch_file): +% with codecs.open(launch_file, "r", encoding="utf8") as fp: +% launch_data = _remove_comments(fp.readlines()) +% try: +% prev_config = json.loads(launch_data) +% if _contains_external_configurations(prev_config): +% launch_config = _remove_pio_configurations(prev_config) +% end +% except: +% pass +% end +% end +% end +% launch_config["configurations"].extend(get_pio_configurations()) +% return launch_config +% end +% +// AUTOMATICALLY GENERATED FILE. PLEASE DO NOT MODIFY IT MANUALLY +// +// PIO Unified Debugger +// +// Documentation: https://docs.platformio.org/page/plus/debugging.html +// Configuration: https://docs.platformio.org/page/projectconf/section_env_debug.html + +{{ json.dumps(get_launch_configuration(), indent=4, ensure_ascii=False) }} diff --git a/platformio/maintenance.py b/platformio/maintenance.py index 0e101339..e22f8407 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -349,8 +349,8 @@ def check_prune_system(): if threshold_mb <= 0: return - unnecessary_mb = calculate_unnecessary_system_data() / 1024 - if unnecessary_mb < threshold_mb: + unnecessary_size = calculate_unnecessary_system_data() + if (unnecessary_size / 1024) < threshold_mb: return terminal_width, _ = click.get_terminal_size() @@ -360,6 +360,6 @@ def check_prune_system(): "We found %s of unnecessary PlatformIO system data (temporary files, " "unnecessary packages, etc.).\nUse `pio system prune --dry-run` to list " "them or `pio system prune` to save disk space." - % fs.humanize_file_size(unnecessary_mb), + % fs.humanize_file_size(unnecessary_size), fg="yellow", ) diff --git a/platformio/package/manager/_registry.py b/platformio/package/manager/_registry.py index 6d243d76..4dfd43b6 100644 --- a/platformio/package/manager/_registry.py +++ b/platformio/package/manager/_registry.py @@ -207,9 +207,9 @@ class PackageManageRegistryMixin(object): time.sleep(1) return (None, None) - def pick_best_registry_version(self, versions, spec=None): + def filter_incompatible_registry_versions(self, versions, spec=None): assert not spec or isinstance(spec, PackageSpec) - best = None + result = [] for version in versions: semver = cast_version_to_semver(version["name"]) if spec and spec.requirements and semver not in spec.requirements: @@ -218,6 +218,13 @@ class PackageManageRegistryMixin(object): self.is_system_compatible(f.get("system")) for f in version["files"] ): continue + result.append(version) + return result + + def pick_best_registry_version(self, versions, spec=None): + best = None + for version in self.filter_incompatible_registry_versions(versions, spec): + semver = cast_version_to_semver(version["name"]) if not best or (semver > cast_version_to_semver(best["name"])): best = version return best diff --git a/platformio/package/manager/core.py b/platformio/package/manager/core.py index 24d494b3..dd3f2663 100644 --- a/platformio/package/manager/core.py +++ b/platformio/package/manager/core.py @@ -137,6 +137,9 @@ def build_contrib_pysite_package(target_dir, with_metadata=True): fs.rmtree(target_dir) os.makedirs(target_dir) + # issue 3865: There is no "rustup" in "Raspbian GNU/Linux 10 (buster)" + os.environ["CRYPTOGRAPHY_DONT_BUILD_RUST"] = "1" + # build dependencies args = [ get_pythonexe_path(), diff --git a/platformio/package/manifest/parser.py b/platformio/package/manifest/parser.py index 4dd4476d..f3d35559 100644 --- a/platformio/package/manifest/parser.py +++ b/platformio/package/manifest/parser.py @@ -568,6 +568,7 @@ class LibraryPropertiesManifestParser(BaseManifestParser): continue found = True item["maintainer"] = True + # pylint: disable=unsupported-membership-test if not item.get("email") and email and "@" in email: item["email"] = email if not found: diff --git a/platformio/package/manifest/schema.py b/platformio/package/manifest/schema.py index a3d940ee..addc4c5f 100644 --- a/platformio/package/manifest/schema.py +++ b/platformio/package/manifest/schema.py @@ -253,5 +253,9 @@ class ManifestSchema(BaseSchema): @staticmethod @memoized(expire="1h") def load_spdx_licenses(): - spdx_data_url = "https://dl.bintray.com/platformio/dl-misc/spdx-licenses-3.json" + version = "3.12" + spdx_data_url = ( + "https://raw.githubusercontent.com/spdx/license-list-data/" + "v%s/json/licenses.json" % version + ) return json.loads(fetch_remote_content(spdx_data_url)) diff --git a/platformio/platform/_run.py b/platformio/platform/_run.py index 457983c4..cb5ec995 100644 --- a/platformio/platform/_run.py +++ b/platformio/platform/_run.py @@ -134,7 +134,9 @@ class PlatformRunMixin(object): args, stdout=proc.BuildAsyncPipe( line_callback=self._on_stdout_line, - data_callback=lambda data: _write_and_flush(sys.stdout, data), + data_callback=lambda data: None + if self.silent + else _write_and_flush(sys.stdout, data), ), stderr=proc.BuildAsyncPipe( line_callback=self._on_stderr_line, diff --git a/platformio/platform/base.py b/platformio/platform/base.py index 81d9b085..3cadbd73 100644 --- a/platformio/platform/base.py +++ b/platformio/platform/base.py @@ -252,6 +252,7 @@ class PlatformBase( # pylint: disable=too-many-instance-attributes,too-many-pub click.secho( "Could not install Python packages -> %s" % e, fg="red", err=True ) + return None def uninstall_python_packages(self): if not self.python_packages: diff --git a/setup.py b/setup.py index ad251a89..2434bcc8 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ if not PY2: home_requirements = [ "aiofiles==0.6.*", - "json-rpc==1.13.*", + "ajsonrpc==1.1.*", "starlette==0.14.*", "uvicorn==0.13.*", "wsproto==1.0.*", diff --git a/tests/commands/test_boards.py b/tests/commands/test_boards.py index 21142dd4..244f0b70 100644 --- a/tests/commands/test_boards.py +++ b/tests/commands/test_boards.py @@ -23,7 +23,7 @@ def test_board_json_output(clirunner, validate_cliresult): validate_cliresult(result) boards = json.loads(result.output) assert isinstance(boards, list) - assert any(["mbed" in b["frameworks"] for b in boards]) + assert any("mbed" in b["frameworks"] for b in boards) def test_board_raw_output(clirunner, validate_cliresult): diff --git a/tests/commands/test_check.py b/tests/commands/test_check.py index c631a613..17f8ed27 100644 --- a/tests/commands/test_check.py +++ b/tests/commands/test_check.py @@ -521,3 +521,16 @@ int main() {} verbose_errors, _, _ = count_defects(result.output) assert verbose_errors == errors == 1 + + +def test_check_handles_spaces_in_paths(clirunner, validate_cliresult, tmpdir_factory): + tmpdir = tmpdir_factory.mktemp("project dir") + config = DEFAULT_CONFIG + "\ncheck_tool = cppcheck, clangtidy, pvs-studio" + tmpdir.join("platformio.ini").write(config) + tmpdir.mkdir("src").join("main.cpp").write( + PVS_STUDIO_FREE_LICENSE_HEADER + TEST_CODE + ) + + default_result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir)]) + + validate_cliresult(default_result) diff --git a/tests/commands/test_init.py b/tests/commands/test_init.py index 09bd8cf9..49db3560 100644 --- a/tests/commands/test_init.py +++ b/tests/commands/test_init.py @@ -70,10 +70,8 @@ def test_init_ide_vscode(clirunner, validate_cliresult, tmpdir): validate_cliresult(result) validate_pioproject(str(tmpdir)) assert all( - [ - tmpdir.join(".vscode").join(f).check() - for f in ("c_cpp_properties.json", "launch.json") - ] + tmpdir.join(".vscode").join(f).check() + for f in ("c_cpp_properties.json", "launch.json") ) assert ( "framework-arduino-avr" @@ -113,7 +111,7 @@ def test_init_ide_eclipse(clirunner, validate_cliresult): result = clirunner.invoke(cmd_init, ["-b", "uno", "--ide", "eclipse"]) validate_cliresult(result) validate_pioproject(getcwd()) - assert all([isfile(f) for f in (".cproject", ".project")]) + assert all(isfile(f) for f in (".cproject", ".project")) def test_init_special_board(clirunner, validate_cliresult): diff --git a/tests/commands/test_lib_complex.py b/tests/commands/test_lib_complex.py index c1314500..5b19c30e 100644 --- a/tests/commands/test_lib_complex.py +++ b/tests/commands/test_lib_complex.py @@ -172,27 +172,23 @@ def test_global_lib_list(clirunner, validate_cliresult): result = clirunner.invoke(cmd_lib, ["-g", "list"]) validate_cliresult(result) assert all( - [ - n in result.output - for n in ( - "Source: https://github.com/Pedroalbuquerque/ESP32WebServer/archive/master.zip", - "Version: 5.10.1", - "Source: git+https://github.com/gioblu/PJON.git#3.0", - "Version: 3.0.0+sha.1fb26fd", - ) - ] + n in result.output + for n in ( + "Source: https://github.com/Pedroalbuquerque/ESP32WebServer/archive/master.zip", + "Version: 5.10.1", + "Source: git+https://github.com/gioblu/PJON.git#3.0", + "Version: 3.0.0+sha.1fb26fd", + ) ) result = clirunner.invoke(cmd_lib, ["-g", "list", "--json-output"]) assert all( - [ - n in result.output - for n in ( - "__pkg_dir", - '"__src_url": "git+https://github.com/gioblu/PJON.git#6.2"', - '"version": "5.10.1"', - ) - ] + n in result.output + for n in ( + "__pkg_dir", + '"__src_url": "git+https://github.com/gioblu/PJON.git#6.2"', + '"version": "5.10.1"', + ) ) items1 = [i["name"] for i in json.loads(result.output)] items2 = [ @@ -316,7 +312,7 @@ def test_global_lib_uninstall(clirunner, validate_cliresult, isolated_pio_core): def test_lib_show(clirunner, validate_cliresult): result = clirunner.invoke(cmd_lib, ["show", "64"]) validate_cliresult(result) - assert all([s in result.output for s in ("ArduinoJson", "Arduino", "Atmel AVR")]) + assert all(s in result.output for s in ("ArduinoJson", "Arduino", "Atmel AVR")) result = clirunner.invoke(cmd_lib, ["show", "OneWire", "--json-output"]) validate_cliresult(result) assert "OneWire" in result.output @@ -333,10 +329,8 @@ def test_lib_stats(clirunner, validate_cliresult): result = clirunner.invoke(cmd_lib, ["stats"]) validate_cliresult(result) assert all( - [ - s in result.output - for s in ("UPDATED", "POPULAR", "https://platformio.org/lib/show") - ] + s in result.output + for s in ("UPDATED", "POPULAR", "https://platformio.org/lib/show") ) result = clirunner.invoke(cmd_lib, ["stats", "--json-output"]) diff --git a/tests/commands/test_platform.py b/tests/commands/test_platform.py index 704543ad..508eae22 100644 --- a/tests/commands/test_platform.py +++ b/tests/commands/test_platform.py @@ -103,7 +103,7 @@ def test_list_json_output(clirunner, validate_cliresult): def test_list_raw_output(clirunner, validate_cliresult): result = clirunner.invoke(cli_platform.platform_list) validate_cliresult(result) - assert all([s in result.output for s in ("atmelavr", "espressif8266")]) + assert all(s in result.output for s in ("atmelavr", "espressif8266")) def test_update_check(clirunner, validate_cliresult, isolated_pio_core): diff --git a/tests/commands/test_test.py b/tests/commands/test_test.py index 4543ad92..08642eaf 100644 --- a/tests/commands/test_test.py +++ b/tests/commands/test_test.py @@ -34,7 +34,7 @@ def test_local_env(): if result["returncode"] != 1: pytest.fail(str(result)) # pylint: disable=unsupported-membership-test - assert all([s in result["err"] for s in ("PASSED", "FAILED")]), result["out"] + assert all(s in result["err"] for s in ("PASSED", "FAILED")), result["out"] def test_multiple_env_build(clirunner, validate_cliresult, tmpdir): diff --git a/tests/commands/test_update.py b/tests/commands/test_update.py index b9ecb5c1..90cb09c7 100644 --- a/tests/commands/test_update.py +++ b/tests/commands/test_update.py @@ -21,7 +21,7 @@ def test_update(clirunner, validate_cliresult, isolated_pio_core): matches = ("Platform Manager", "Library Manager") result = clirunner.invoke(cmd_update, ["--only-check"]) validate_cliresult(result) - assert all([m in result.output for m in matches]) + assert all(m in result.output for m in matches) result = clirunner.invoke(cmd_update) validate_cliresult(result) - assert all([m in result.output for m in matches]) + assert all(m in result.output for m in matches) diff --git a/tox.ini b/tox.ini index 8a1f0b04..c8c18db9 100644 --- a/tox.ini +++ b/tox.ini @@ -15,6 +15,10 @@ [tox] envlist = py36,py37,py38,py39 +[isort] +line_length = 88 +known_third_party=OpenSSL, SCons, jsonrpc, twisted, zope + [testenv] passenv = * usedevelop = True