Merge branch 'release/v5.1.1'

This commit is contained in:
Ivan Kravets
2021-03-17 18:17:46 +02:00
36 changed files with 249 additions and 178 deletions

View File

@ -1,3 +0,0 @@
[settings]
line_length=88
known_third_party=OpenSSL, SCons, jsonrpc, twisted, zope

View File

@ -8,12 +8,21 @@ PlatformIO Core 5
**A professional collaborative platform for embedded development** **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 <https://github.com/platformio/platformio-core/issues/3827>`_)
* Fixed an issue with `device monitor <https://docs.platformio.org/page/core/userguide/device/cmd_monitor.html>`__ when the "send_on_enter" filter didn't send EOL chars (`issue #3787 <https://github.com/platformio/platformio-core/issues/3787>`_)
* Fixed an issue with silent mode when unwanted data is printed to stdout (`issue #3837 <https://github.com/platformio/platformio-core/issues/3837>`_)
* Fixed an issue when code inspection fails with "Bad JSON" (`issue #3790 <https://github.com/platformio/platformio-core/issues/3790>`_)
* Fixed an issue with overriding user-specified debugging configuration information in VSCode (`issue #3824 <https://github.com/platformio/platformio-core/issues/3824>`_)
5.1.0 (2021-01-28) 5.1.0 (2021-01-28)
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
* **PlatformIO Home** * **PlatformIO Home**
- Boosted PlatformIO Home performance thanks to migrating the codebase to the pure Python 3 Asynchronous I/O stack - Boosted `PlatformIO Home <https://docs.platformio.org/page/home/index.html>`__ performance thanks to migrating the codebase to the pure Python 3 Asynchronous I/O stack
- Added a new ``--session-id`` option to `pio home <https://docs.platformio.org/page/core/userguide/cmd_home.html>`__ command that helps to keep PlatformIO Home isolated from other instances and protect from 3rd party access (`issue #3397 <https://github.com/platformio/platformio-core/issues/3397>`_) - Added a new ``--session-id`` option to `pio home <https://docs.platformio.org/page/core/userguide/cmd_home.html>`__ command that helps to keep PlatformIO Home isolated from other instances and protect from 3rd party access (`issue #3397 <https://github.com/platformio/platformio-core/issues/3397>`_)
* **Build System** * **Build System**
@ -45,7 +54,7 @@ PlatformIO Core 5
- Improved listing of `multicast DNS services <https://docs.platformio.org/page/core/userguide/device/cmd_list.html>`_ - Improved listing of `multicast DNS services <https://docs.platformio.org/page/core/userguide/device/cmd_list.html>`_
- Fixed a "UnicodeDecodeError: 'utf-8' codec can't decode byte" when using J-Link for firmware uploading on Linux (`issue #3804 <https://github.com/platformio/platformio-core/issues/3804>`_) - Fixed a "UnicodeDecodeError: 'utf-8' codec can't decode byte" when using J-Link for firmware uploading on Linux (`issue #3804 <https://github.com/platformio/platformio-core/issues/3804>`_)
- Fixed an issue with a compiler driver for ".ccls" language server (`issue #3808 <https://github.com/platformio/platformio-core/issues/3808>`_) - Fixed an issue with a compiler driver for ".ccls" language server (`issue #3808 <https://github.com/platformio/platformio-core/issues/3808>`_)
- Fixed an issue when `pio device monitor --eol <https://docs.platformio.org/en/latest/core/userguide/device/cmd_monitor.html#cmdoption-pio-device-monitor-eol>`__ and "send_on_enter" filter do not work properly (`issue #3787 <https://github.com/platformio/platformio-core/issues/3787>`_) - Fixed an issue when `pio device monitor --eol <https://docs.platformio.org/page/core/userguide/device/cmd_monitor.html#cmdoption-pio-device-monitor-eol>`__ and "send_on_enter" filter do not work properly (`issue #3787 <https://github.com/platformio/platformio-core/issues/3787>`_)
5.0.4 (2020-12-30) 5.0.4 (2020-12-30)
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~

2
docs

Submodule docs updated: 25edd66d55...3293903cac

View File

@ -14,7 +14,7 @@
import sys import sys
VERSION = (5, 1, 0) VERSION = (5, 1, 1)
__version__ = ".".join([str(s) for s in VERSION]) __version__ = ".".join([str(s) for s in VERSION])
__title__ = "platformio" __title__ = "platformio"
@ -47,7 +47,7 @@ __pioremote_endpoint__ = "ssl:host=remote.platformio.org:port=4413"
__default_requests_timeout__ = (10, None) # (connect, read) __default_requests_timeout__ = (10, None) # (connect, read)
__core_packages__ = { __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), "contrib-pysite": "~2.%d%d.0" % (sys.version_info.major, sys.version_info.minor),
"tool-unity": "~1.20500.0", "tool-unity": "~1.20500.0",
"tool-scons": "~2.20501.7" if sys.version_info.major == 2 else "~4.40100.2", "tool-scons": "~2.20501.7" if sys.version_info.major == 2 else "~4.40100.2",

View File

@ -26,8 +26,8 @@ from platformio.compat import 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 = 8192
# - Unix = 131072 # - Unix = 131072
# We need ~256 characters for a temporary file path # We need ~512 characters for compiler and temporary file paths
MAX_LINE_LENGTH = (8192 if WINDOWS else 131072) - 256 MAX_LINE_LENGTH = (8192 if WINDOWS else 131072) - 512
WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)")

View File

@ -52,6 +52,7 @@ def BoardConfig(env, board=None):
except (AssertionError, UnknownBoard) as e: except (AssertionError, UnknownBoard) as e:
sys.stderr.write("Error: %s\n" % str(e)) sys.stderr.write("Error: %s\n" % str(e))
env.Exit(1) env.Exit(1)
return None
def GetFrameworkScript(env, framework): def GetFrameworkScript(env, framework):

View File

@ -96,14 +96,13 @@ class CppcheckCheckTool(CheckToolBase):
) )
click.echo() click.echo()
self._bad_input = True self._bad_input = True
self._buffer = ""
return None return None
self._buffer = "" self._buffer = ""
return DefectItem(**args) return DefectItem(**args)
def configure_command( def configure_command(self, language, src_file): # pylint: disable=arguments-differ
self, language, src_files
): # pylint: disable=arguments-differ
tool_path = os.path.join(get_core_package_dir("tool-cppcheck"), "cppcheck") tool_path = os.path.join(get_core_package_dir("tool-cppcheck"), "cppcheck")
cmd = [ cmd = [
@ -157,8 +156,8 @@ class CppcheckCheckTool(CheckToolBase):
"--include=" + inc "--include=" + inc
for inc in self.get_forced_includes(build_flags, self.cpp_includes) 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("--includes-file=%s" % self._generate_inc_file())
cmd.append('"%s"' % src_file)
return cmd return cmd
@ -227,23 +226,25 @@ class CppcheckCheckTool(CheckToolBase):
def check(self, on_defect_callback=None): def check(self, on_defect_callback=None):
self._on_defect_callback = on_defect_callback self._on_defect_callback = on_defect_callback
project_files = self.get_project_target_files(self.options["patterns"])
languages = ("c", "c++") project_files = self.get_project_target_files(self.options["patterns"])
if not any([project_files[t] for t in languages]): src_files_scope = ("c", "c++")
if not any(project_files[t] for t in src_files_scope):
click.echo("Error: Nothing to check.") click.echo("Error: Nothing to check.")
return True 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() self.clean_up()

View File

@ -187,7 +187,13 @@ class PvsStudioCheckTool(CheckToolBase): # pylint: disable=too-many-instance-at
flags = self.cc_flags flags = self.cc_flags
compiler = self.cc_path 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([f for f in flags if f])
cmd.extend(["-D%s" % d for d in self.cpp_defines]) cmd.extend(["-D%s" % d for d in self.cpp_defines])
cmd.append('@"%s"' % self._tmp_cmd_file) cmd.append('@"%s"' % self._tmp_cmd_file)

View File

@ -192,7 +192,7 @@ def configure_esp32_load_cmds(debug_options, configuration):
debug_options["load_cmds"] != ["load"], debug_options["load_cmds"] != ["load"],
"xtensa-esp32" not in configuration.get("cc_path", ""), "xtensa-esp32" not in configuration.get("cc_path", ""),
not flash_images, 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): if any(ignore_conds):
return debug_options["load_cmds"] return debug_options["load_cmds"]

View File

@ -32,7 +32,7 @@ class SendOnEnter(DeviceMonitorFilter):
def tx(self, text): def tx(self, text):
self._buffer += text self._buffer += text
if self._buffer.endswith(self._eol): if self._buffer.endswith(self._eol):
text = self._buffer[: len(self._eol) * -1] text = self._buffer
self._buffer = "" self._buffer = ""
return text return text
return "" return ""

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.
import jsonrpc from ajsonrpc.core import JSONRPC20DispatchException
from platformio.clients.account import AccountClient from platformio.clients.account import AccountClient
@ -24,6 +24,6 @@ class AccountRPC:
client = AccountClient() client = AccountClient()
return getattr(client, method)(*args, **kwargs) return getattr(client, method)(*args, **kwargs)
except Exception as e: # pylint: disable=bare-except except Exception as e: # pylint: disable=bare-except
raise jsonrpc.exceptions.JSONRPCDispatchException( raise JSONRPC20DispatchException(
code=4003, message="PIO Account Call Error", data=str(e) code=4003, message="PIO Account Call Error", data=str(e)
) )

View File

@ -14,7 +14,7 @@
import time import time
import jsonrpc from ajsonrpc.core import JSONRPC20DispatchException
from platformio.compat import get_running_loop from platformio.compat import get_running_loop
@ -25,7 +25,7 @@ class IDERPC:
def send_command(self, sid, command, params): def send_command(self, sid, command, params):
if not self._queue.get(sid): if not self._queue.get(sid):
raise jsonrpc.exceptions.JSONRPCDispatchException( raise JSONRPC20DispatchException(
code=4005, message="PIO Home IDE agent is not started" code=4005, message="PIO Home IDE agent is not started"
) )
while self._queue[sid]: while self._queue[sid]:
@ -33,11 +33,11 @@ class IDERPC:
{"id": time.time(), "method": command, "params": params} {"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: if sid not in self._queue:
self._queue[sid] = [] self._queue[sid] = []
self._queue[sid].append(get_running_loop().create_future()) 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): def open_project(self, sid, project_dir):
return self.send_command(sid, "open_project", project_dir) return self.send_command(sid, "open_project", project_dir)

View File

@ -20,7 +20,7 @@ import sys
from io import StringIO from io import StringIO
import click import click
import jsonrpc from ajsonrpc.core import JSONRPC20DispatchException
from starlette.concurrency import run_in_threadpool from starlette.concurrency import run_in_threadpool
from platformio import __main__, __version__, fs, proc from platformio import __main__, __version__, fs, proc
@ -99,7 +99,7 @@ class PIOCoreRPC:
result = await PIOCoreRPC._call_subprocess(args, options) result = await PIOCoreRPC._call_subprocess(args, options)
return PIOCoreRPC._process_result(result, to_json) return PIOCoreRPC._process_result(result, to_json)
except Exception as e: # pylint: disable=bare-except except Exception as e: # pylint: disable=bare-except
raise jsonrpc.exceptions.JSONRPCDispatchException( raise JSONRPC20DispatchException(
code=4003, message="PIO Core Call Error", data=str(e) code=4003, message="PIO Core Call Error", data=str(e)
) )

View File

@ -18,7 +18,7 @@ import os
import shutil import shutil
import time import time
import jsonrpc from ajsonrpc.core import JSONRPC20DispatchException
from platformio import exception, fs from platformio import exception, fs
from platformio.commands.home.rpc.handlers.app import AppRPC from platformio.commands.home.rpc.handlers.app import AppRPC
@ -257,18 +257,16 @@ class ProjectRPC:
return arduino_project_dir return arduino_project_dir
is_arduino_project = any( is_arduino_project = any(
[ os.path.isfile(
os.path.isfile( os.path.join(
os.path.join( arduino_project_dir,
arduino_project_dir, "%s.%s" % (os.path.basename(arduino_project_dir), ext),
"%s.%s" % (os.path.basename(arduino_project_dir), ext),
)
) )
for ext in ("ino", "pde") )
] for ext in ("ino", "pde")
) )
if not is_arduino_project: if not is_arduino_project:
raise jsonrpc.exceptions.JSONRPCDispatchException( raise JSONRPC20DispatchException(
code=4000, message="Not an Arduino project: %s" % arduino_project_dir code=4000, message="Not an Arduino project: %s" % arduino_project_dir
) )
@ -303,7 +301,7 @@ class ProjectRPC:
@staticmethod @staticmethod
async def import_pio(project_dir): async def import_pio(project_dir):
if not project_dir or not is_platformio_project(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 code=4001, message="Not an PlatformIO project: %s" % project_dir
) )
new_project_dir = os.path.join( new_project_dir = os.path.join(

View File

@ -12,14 +12,12 @@
# 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 inspect
import json
import click import click
import jsonrpc from ajsonrpc.dispatcher import Dispatcher
from ajsonrpc.manager import AsyncJSONRPCResponseManager
from starlette.endpoints import WebSocketEndpoint 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 from platformio.proc import force_exit
@ -30,13 +28,15 @@ class JSONRPCServerFactoryBase:
def __init__(self, shutdown_timeout=0): def __init__(self, shutdown_timeout=0):
self.shutdown_timeout = shutdown_timeout self.shutdown_timeout = shutdown_timeout
self.dispatcher = jsonrpc.Dispatcher() self.manager = AsyncJSONRPCResponseManager(
Dispatcher(), is_server_error_verbose=True
)
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
raise NotImplementedError raise NotImplementedError
def addHandler(self, handler, namespace): def addObjectHandler(self, handler, namespace):
self.dispatcher.build_method_map(handler, prefix="%s." % namespace) self.manager.dispatcher.add_object(handler, prefix="%s." % namespace)
def on_client_connect(self): def on_client_connect(self):
self.connection_nums += 1 self.connection_nums += 1
@ -90,29 +90,8 @@ class WebSocketJSONRPCServer(WebSocketEndpoint):
self.factory.on_client_disconnect() # pylint: disable=no-member self.factory.on_client_disconnect() # pylint: disable=no-member
async def _handle_rpc(self, websocket, data): async def _handle_rpc(self, websocket, data):
response = jsonrpc.JSONRPCResponseManager.handle( # pylint: disable=no-member
data, self.factory.dispatcher # pylint: disable=no-member response = await self.factory.manager.get_response_for_payload(data)
)
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
if response.error: if response.error:
click.secho("Error: %s" % response.error, fg="red", err=True) click.secho("Error: %s" % response.error.data, fg="red", err=True)
if "result" in response.data and is_bytes(response.data["result"]): await websocket.send_text(self.factory.manager.serialize(response.body))
response.data["result"] = response.data["result"].decode("utf-8")
await websocket.send_text(json.dumps(response.data))

View File

@ -65,13 +65,13 @@ def run_server(host, port, no_open, shutdown_timeout, home_url):
raise PlatformioException("Invalid path to PIO Home Contrib") raise PlatformioException("Invalid path to PIO Home Contrib")
ws_rpc_factory = WebSocketJSONRPCServerFactory(shutdown_timeout) ws_rpc_factory = WebSocketJSONRPCServerFactory(shutdown_timeout)
ws_rpc_factory.addHandler(AccountRPC(), namespace="account") ws_rpc_factory.addObjectHandler(AccountRPC(), namespace="account")
ws_rpc_factory.addHandler(AppRPC(), namespace="app") ws_rpc_factory.addObjectHandler(AppRPC(), namespace="app")
ws_rpc_factory.addHandler(IDERPC(), namespace="ide") ws_rpc_factory.addObjectHandler(IDERPC(), namespace="ide")
ws_rpc_factory.addHandler(MiscRPC(), namespace="misc") ws_rpc_factory.addObjectHandler(MiscRPC(), namespace="misc")
ws_rpc_factory.addHandler(OSRPC(), namespace="os") ws_rpc_factory.addObjectHandler(OSRPC(), namespace="os")
ws_rpc_factory.addHandler(PIOCoreRPC(), namespace="core") ws_rpc_factory.addObjectHandler(PIOCoreRPC(), namespace="core")
ws_rpc_factory.addHandler(ProjectRPC(), namespace="project") ws_rpc_factory.addObjectHandler(ProjectRPC(), namespace="project")
path = urlparse(home_url).path path = urlparse(home_url).path
routes = [ routes = [

View File

@ -25,6 +25,7 @@ from tabulate import tabulate
from platformio import app, exception, fs, util from platformio import app, exception, fs, util
from platformio.commands.test.embedded import EmbeddedTestProcessor from platformio.commands.test.embedded import EmbeddedTestProcessor
from platformio.commands.test.native import NativeTestProcessor from platformio.commands.test.native import NativeTestProcessor
from platformio.platform.factory import PlatformFactory
from platformio.project.config import ProjectConfig 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, not environment and default_envs and envname not in default_envs,
testname != "*" testname != "*"
and patterns["filter"] 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 != "*" 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): if any(skip_conditions):
results.append({"env": envname, "test": testname}) results.append({"env": envname, "test": testname})
@ -140,9 +141,9 @@ def cli( # pylint: disable=redefined-builtin
print_processing_header(testname, envname) print_processing_header(testname, envname)
cls = ( cls = (
NativeTestProcessor EmbeddedTestProcessor
if config.get(section, "platform") == "native" if is_embedded_platform(config.get(section, "platform"))
else EmbeddedTestProcessor else NativeTestProcessor
) )
tp = cls( tp = cls(
ctx, ctx,
@ -194,6 +195,12 @@ def get_test_names(test_dir):
return names return names
def is_embedded_platform(name):
if not name:
return False
return PlatformFactory.new(name).is_embedded()
def print_processing_header(test, env): def print_processing_header(test, env):
click.echo( click.echo(
"Processing %s in %s environment" "Processing %s in %s environment"

View File

@ -95,7 +95,7 @@ class EmbeddedTestProcessor(TestProcessorBase):
if isinstance(line, bytes): if isinstance(line, bytes):
line = line.decode("utf8", "ignore") line = line.decode("utf8", "ignore")
self.on_run_out(line) 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 break
ser.close() ser.close()
return not self._run_failed return not self._run_failed

View File

@ -1,50 +1,96 @@
// AUTOMATICALLY GENERATED FILE. PLEASE DO NOT MODIFY IT MANUALLY % import codecs
% import json
// PIO Unified Debugger % import os
// %
// Documentation: https://docs.platformio.org/page/plus/debugging.html % def _escape(text):
// Configuration: https://docs.platformio.org/page/projectconf/section_env_debug.html % return text.replace('"', '\"')
% end
% from os.path import dirname, join
% %
% def _escape_path(path): % def _escape_path(path):
% return path.replace('\\\\', '/').replace('\\', '/').replace('"', '\\"') % return path.replace('\\\\', '/').replace('\\', '/').replace('"', '\\"')
% end % end
% %
{ % def get_pio_configurations():
"version": "0.2.0", % predebug = {
"configurations": [ % "type": "platformio-debug",
{ % "request": "launch",
"type": "platformio-debug", % "name": "PIO Debug (skip Pre-Debug)",
"request": "launch", % "executable": _escape_path(prog_path),
"name": "PIO Debug", % "projectEnvName": env_name,
"executable": "{{ _escape_path(prog_path) }}", % "toolchainBinDir": _escape_path(os.path.dirname(gdb_path)),
"projectEnvName": "{{ env_name }}", % "internalConsoleOptions": "openOnSessionStart",
"toolchainBinDir": "{{ _escape_path(dirname(gdb_path)) }}", % }
% if svd_path: %
"svdPath": "{{ _escape_path(svd_path) }}", % 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 % end
"preLaunchTask": { %
"type": "PlatformIO", % def _remove_comments(lines):
% if len(config.envs()) > 1: % data = ""
"task": "Pre-Debug ({{ env_name }})" % for line in lines:
% else: % line = line.strip()
"task": "Pre-Debug" % if not line.startswith("//"):
% data += line
% end
% end
% return data
% end % end
}, %
"internalConsoleOptions": "openOnSessionStart" % def _contains_external_configurations(launch_config):
}, % return any(
{ % c.get("type", "") != "platformio-debug"
"type": "platformio-debug", % for c in launch_config.get("configurations", [])
"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) }}",
% end % end
"internalConsoleOptions": "openOnSessionStart" %
} % 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) }}

View File

@ -349,8 +349,8 @@ def check_prune_system():
if threshold_mb <= 0: if threshold_mb <= 0:
return return
unnecessary_mb = calculate_unnecessary_system_data() / 1024 unnecessary_size = calculate_unnecessary_system_data()
if unnecessary_mb < threshold_mb: if (unnecessary_size / 1024) < threshold_mb:
return return
terminal_width, _ = click.get_terminal_size() terminal_width, _ = click.get_terminal_size()
@ -360,6 +360,6 @@ def check_prune_system():
"We found %s of unnecessary PlatformIO system data (temporary files, " "We found %s of unnecessary PlatformIO system data (temporary files, "
"unnecessary packages, etc.).\nUse `pio system prune --dry-run` to list " "unnecessary packages, etc.).\nUse `pio system prune --dry-run` to list "
"them or `pio system prune` to save disk space." "them or `pio system prune` to save disk space."
% fs.humanize_file_size(unnecessary_mb), % fs.humanize_file_size(unnecessary_size),
fg="yellow", fg="yellow",
) )

View File

@ -207,9 +207,9 @@ class PackageManageRegistryMixin(object):
time.sleep(1) time.sleep(1)
return (None, None) 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) assert not spec or isinstance(spec, PackageSpec)
best = None result = []
for version in versions: for version in versions:
semver = cast_version_to_semver(version["name"]) semver = cast_version_to_semver(version["name"])
if spec and spec.requirements and semver not in spec.requirements: 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"] self.is_system_compatible(f.get("system")) for f in version["files"]
): ):
continue 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"])): if not best or (semver > cast_version_to_semver(best["name"])):
best = version best = version
return best return best

View File

@ -137,6 +137,9 @@ def build_contrib_pysite_package(target_dir, with_metadata=True):
fs.rmtree(target_dir) fs.rmtree(target_dir)
os.makedirs(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 # build dependencies
args = [ args = [
get_pythonexe_path(), get_pythonexe_path(),

View File

@ -568,6 +568,7 @@ class LibraryPropertiesManifestParser(BaseManifestParser):
continue continue
found = True found = True
item["maintainer"] = True item["maintainer"] = True
# pylint: disable=unsupported-membership-test
if not item.get("email") and email and "@" in email: if not item.get("email") and email and "@" in email:
item["email"] = email item["email"] = email
if not found: if not found:

View File

@ -253,5 +253,9 @@ class ManifestSchema(BaseSchema):
@staticmethod @staticmethod
@memoized(expire="1h") @memoized(expire="1h")
def load_spdx_licenses(): 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)) return json.loads(fetch_remote_content(spdx_data_url))

View File

@ -134,7 +134,9 @@ class PlatformRunMixin(object):
args, args,
stdout=proc.BuildAsyncPipe( stdout=proc.BuildAsyncPipe(
line_callback=self._on_stdout_line, 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( stderr=proc.BuildAsyncPipe(
line_callback=self._on_stderr_line, line_callback=self._on_stderr_line,

View File

@ -252,6 +252,7 @@ class PlatformBase( # pylint: disable=too-many-instance-attributes,too-many-pub
click.secho( click.secho(
"Could not install Python packages -> %s" % e, fg="red", err=True "Could not install Python packages -> %s" % e, fg="red", err=True
) )
return None
def uninstall_python_packages(self): def uninstall_python_packages(self):
if not self.python_packages: if not self.python_packages:

View File

@ -43,7 +43,7 @@ if not PY2:
home_requirements = [ home_requirements = [
"aiofiles==0.6.*", "aiofiles==0.6.*",
"json-rpc==1.13.*", "ajsonrpc==1.1.*",
"starlette==0.14.*", "starlette==0.14.*",
"uvicorn==0.13.*", "uvicorn==0.13.*",
"wsproto==1.0.*", "wsproto==1.0.*",

View File

@ -23,7 +23,7 @@ def test_board_json_output(clirunner, validate_cliresult):
validate_cliresult(result) validate_cliresult(result)
boards = json.loads(result.output) boards = json.loads(result.output)
assert isinstance(boards, list) 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): def test_board_raw_output(clirunner, validate_cliresult):

View File

@ -521,3 +521,16 @@ int main() {}
verbose_errors, _, _ = count_defects(result.output) verbose_errors, _, _ = count_defects(result.output)
assert verbose_errors == errors == 1 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)

View File

@ -70,10 +70,8 @@ def test_init_ide_vscode(clirunner, validate_cliresult, tmpdir):
validate_cliresult(result) validate_cliresult(result)
validate_pioproject(str(tmpdir)) validate_pioproject(str(tmpdir))
assert all( assert all(
[ tmpdir.join(".vscode").join(f).check()
tmpdir.join(".vscode").join(f).check() for f in ("c_cpp_properties.json", "launch.json")
for f in ("c_cpp_properties.json", "launch.json")
]
) )
assert ( assert (
"framework-arduino-avr" "framework-arduino-avr"
@ -113,7 +111,7 @@ def test_init_ide_eclipse(clirunner, validate_cliresult):
result = clirunner.invoke(cmd_init, ["-b", "uno", "--ide", "eclipse"]) result = clirunner.invoke(cmd_init, ["-b", "uno", "--ide", "eclipse"])
validate_cliresult(result) validate_cliresult(result)
validate_pioproject(getcwd()) 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): def test_init_special_board(clirunner, validate_cliresult):

View File

@ -172,27 +172,23 @@ def test_global_lib_list(clirunner, validate_cliresult):
result = clirunner.invoke(cmd_lib, ["-g", "list"]) result = clirunner.invoke(cmd_lib, ["-g", "list"])
validate_cliresult(result) validate_cliresult(result)
assert all( assert all(
[ n in result.output
n in result.output for n in (
for n in ( "Source: https://github.com/Pedroalbuquerque/ESP32WebServer/archive/master.zip",
"Source: https://github.com/Pedroalbuquerque/ESP32WebServer/archive/master.zip", "Version: 5.10.1",
"Version: 5.10.1", "Source: git+https://github.com/gioblu/PJON.git#3.0",
"Source: git+https://github.com/gioblu/PJON.git#3.0", "Version: 3.0.0+sha.1fb26fd",
"Version: 3.0.0+sha.1fb26fd", )
)
]
) )
result = clirunner.invoke(cmd_lib, ["-g", "list", "--json-output"]) result = clirunner.invoke(cmd_lib, ["-g", "list", "--json-output"])
assert all( assert all(
[ n in result.output
n in result.output for n in (
for n in ( "__pkg_dir",
"__pkg_dir", '"__src_url": "git+https://github.com/gioblu/PJON.git#6.2"',
'"__src_url": "git+https://github.com/gioblu/PJON.git#6.2"', '"version": "5.10.1"',
'"version": "5.10.1"', )
)
]
) )
items1 = [i["name"] for i in json.loads(result.output)] items1 = [i["name"] for i in json.loads(result.output)]
items2 = [ items2 = [
@ -316,7 +312,7 @@ def test_global_lib_uninstall(clirunner, validate_cliresult, isolated_pio_core):
def test_lib_show(clirunner, validate_cliresult): def test_lib_show(clirunner, validate_cliresult):
result = clirunner.invoke(cmd_lib, ["show", "64"]) result = clirunner.invoke(cmd_lib, ["show", "64"])
validate_cliresult(result) 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"]) result = clirunner.invoke(cmd_lib, ["show", "OneWire", "--json-output"])
validate_cliresult(result) validate_cliresult(result)
assert "OneWire" in result.output assert "OneWire" in result.output
@ -333,10 +329,8 @@ def test_lib_stats(clirunner, validate_cliresult):
result = clirunner.invoke(cmd_lib, ["stats"]) result = clirunner.invoke(cmd_lib, ["stats"])
validate_cliresult(result) validate_cliresult(result)
assert all( assert all(
[ s in result.output
s in result.output for s in ("UPDATED", "POPULAR", "https://platformio.org/lib/show")
for s in ("UPDATED", "POPULAR", "https://platformio.org/lib/show")
]
) )
result = clirunner.invoke(cmd_lib, ["stats", "--json-output"]) result = clirunner.invoke(cmd_lib, ["stats", "--json-output"])

View File

@ -103,7 +103,7 @@ def test_list_json_output(clirunner, validate_cliresult):
def test_list_raw_output(clirunner, validate_cliresult): def test_list_raw_output(clirunner, validate_cliresult):
result = clirunner.invoke(cli_platform.platform_list) result = clirunner.invoke(cli_platform.platform_list)
validate_cliresult(result) 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): def test_update_check(clirunner, validate_cliresult, isolated_pio_core):

View File

@ -34,7 +34,7 @@ def test_local_env():
if result["returncode"] != 1: if result["returncode"] != 1:
pytest.fail(str(result)) pytest.fail(str(result))
# pylint: disable=unsupported-membership-test # 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): def test_multiple_env_build(clirunner, validate_cliresult, tmpdir):

View File

@ -21,7 +21,7 @@ def test_update(clirunner, validate_cliresult, isolated_pio_core):
matches = ("Platform Manager", "Library Manager") matches = ("Platform Manager", "Library Manager")
result = clirunner.invoke(cmd_update, ["--only-check"]) result = clirunner.invoke(cmd_update, ["--only-check"])
validate_cliresult(result) 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) result = clirunner.invoke(cmd_update)
validate_cliresult(result) validate_cliresult(result)
assert all([m in result.output for m in matches]) assert all(m in result.output for m in matches)

View File

@ -15,6 +15,10 @@
[tox] [tox]
envlist = py36,py37,py38,py39 envlist = py36,py37,py38,py39
[isort]
line_length = 88
known_third_party=OpenSSL, SCons, jsonrpc, twisted, zope
[testenv] [testenv]
passenv = * passenv = *
usedevelop = True usedevelop = True