Support "force_ansi" option for core.exec and allow to raise exception on cmd error

This commit is contained in:
Ivan Kravets
2023-07-25 12:25:42 +03:00
parent e3557760df
commit d2fd0f242e
2 changed files with 31 additions and 12 deletions

View File

@ -14,6 +14,7 @@
import asyncio
import functools
import os
from platformio import __main__, __version__, app, proc, util
from platformio.compat import (
@ -21,10 +22,16 @@ from platformio.compat import (
aio_create_task,
aio_get_running_loop,
get_locale_encoding,
shlex_join,
)
from platformio.exception import UserSideException
from platformio.home.rpc.handlers.base import BaseRPCHandler
class PIOCoreCallError(UserSideException):
MESSAGE = 'An error occured while executing PIO Core command: "{0}"\n\n{1}'
class PIOCoreProtocol(asyncio.SubprocessProtocol):
def __init__(self, exit_future, on_data_callback=None):
self.exit_future = exit_future
@ -66,27 +73,41 @@ class CoreRPC(BaseRPCHandler):
def version():
return __version__
async def exec(self, args, options=None):
async def exec(self, args, options=None, raise_exception=False):
options = options or {}
loop = aio_get_running_loop()
exit_future = loop.create_future()
data_callback = functools.partial(
self._on_exec_data_received, exec_options=options
)
if args[0] != "--caller" and app.get_session_var("caller_id"):
args = ["--caller", app.get_session_var("caller_id")] + args
kwargs = options.get("spawn", {})
if "forceANSI" in options:
environ = kwargs.get("env", os.environ.copy())
environ["PLATFORMIO_FORCE_ANSI"] = "true"
kwargs["env"] = environ
transport, protocol = await loop.subprocess_exec(
lambda: PIOCoreProtocol(exit_future, data_callback),
get_core_fullpath(),
*args,
stdin=None,
**options.get("spawn", {}),
**kwargs,
)
await exit_future
transport.close()
return_code = transport.get_returncode()
if return_code != 0 and raise_exception:
raise PIOCoreCallError(
shlex_join(["pio"] + args), f"{protocol.stdout}\n{protocol.stderr}"
)
return {
"stdout": protocol.stdout,
"stderr": protocol.stderr,
"returncode": transport.get_returncode(),
"returncode": return_code,
}
def _on_exec_data_received(self, exec_options, pipe, data):

View File

@ -48,19 +48,15 @@ class ProjectRPC(BaseRPCHandler):
if not os.path.isdir(project_dir):
os.makedirs(project_dir)
envclone = os.environ.copy()
envclone["PLATFORMIO_FORCE_ANSI"] = "true"
options = options or {}
options["spawn"] = {"env": envclone, "cwd": project_dir}
args = ["project", "init"]
args = ["project", "init", "-d", project_dir]
ide = app.get_session_var("caller_id")
if ide in ProjectGenerator.get_supported_ides():
args.extend(["--ide", ide])
exec_options = options.get("exec", {})
if configuration.get("example"):
await self.factory.notify_clients(
method=options.get("stdoutNotificationMethod"),
method=exec_options.get("stdoutNotificationMethod"),
params=["Copying example files...\n"],
actor="frontend",
)
@ -68,7 +64,9 @@ class ProjectRPC(BaseRPCHandler):
else:
args.extend(self._pre_init_empty(configuration))
return await self.factory.manager.dispatcher["core.exec"](args, options=options)
return await self.factory.manager.dispatcher["core.exec"](
args, options=exec_options
)
@staticmethod
def _pre_init_empty(configuration):
@ -115,9 +113,9 @@ class ProjectRPC(BaseRPCHandler):
def configuration(project_dir, env):
assert is_platformio_project(project_dir)
with fs.cd(project_dir):
config = ProjectConfig(os.path.join(project_dir, "platformio.ini"))
platform = PlatformFactory.from_env(env, autoinstall=True)
platform_pkg = PlatformPackageManager().get_package(platform.get_dir())
config = ProjectConfig.get_instance()
board_id = config.get(f"env:{env}", "board", None)
# frameworks