mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-29 17:47:14 +02:00
Move exceptions to their components
This commit is contained in:
@ -16,7 +16,6 @@ PlatformIO Core 4.0
|
||||
|
||||
* Handle project configuration (monitor, test, and upload options) for PIO Remote commands (`issue #2591 <https://github.com/platformio/platformio-core/issues/2591>`_)
|
||||
* Warn about broken library manifest when scanning dependencies (`issue #3268 <https://github.com/platformio/platformio-core/issues/3268>`_)
|
||||
* Fixed an issue with the broken latest news for PIO Home
|
||||
* Fixed an issue when ``env.BoardConfig()`` does not work for custom boards in extra scripts of libraries (`issue #3264 <https://github.com/platformio/platformio-core/issues/3264>`_)
|
||||
* Fixed an issue with "start-group/end-group" linker flags on Native development platform (`issue #3282 <https://github.com/platformio/platformio-core/issues/3282>`_)
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import signal
|
||||
@ -26,13 +25,13 @@ from twisted.internet import reactor # pylint: disable=import-error
|
||||
from twisted.internet import stdio # pylint: disable=import-error
|
||||
from twisted.internet import task # pylint: disable=import-error
|
||||
|
||||
from platformio import app, exception, fs, proc, util
|
||||
from platformio import app, fs, proc, telemetry, util
|
||||
from platformio.commands.debug import helpers, initcfgs
|
||||
from platformio.commands.debug.exception import DebugInvalidOptionsError
|
||||
from platformio.commands.debug.process import BaseProcess
|
||||
from platformio.commands.debug.server import DebugServer
|
||||
from platformio.compat import hashlib_encode_data, is_bytes
|
||||
from platformio.project.helpers import get_project_cache_dir
|
||||
from platformio.telemetry import MeasurementProtocol
|
||||
|
||||
LOG_FILE = None
|
||||
|
||||
@ -58,6 +57,7 @@ class GDBClient(BaseProcess): # pylint: disable=too-many-instance-attributes
|
||||
self._target_is_run = False
|
||||
self._last_server_activity = 0
|
||||
self._auto_continue_timer = None
|
||||
self._errors_buffer = b""
|
||||
|
||||
def spawn(self, gdb_path, prog_path):
|
||||
session_hash = gdb_path + prog_path
|
||||
@ -94,7 +94,7 @@ class GDBClient(BaseProcess): # pylint: disable=too-many-instance-attributes
|
||||
]
|
||||
args.extend(self.args)
|
||||
if not gdb_path:
|
||||
raise exception.DebugInvalidOptions("GDB client is not configured")
|
||||
raise DebugInvalidOptionsError("GDB client is not configured")
|
||||
gdb_data_dir = self._get_data_dir(gdb_path)
|
||||
if gdb_data_dir:
|
||||
args.extend(["--data-directory", gdb_data_dir])
|
||||
@ -215,6 +215,9 @@ class GDBClient(BaseProcess): # pylint: disable=too-many-instance-attributes
|
||||
self._handle_error(data)
|
||||
# go to init break automatically
|
||||
if self.INIT_COMPLETED_BANNER.encode() in data:
|
||||
telemetry.send_event(
|
||||
"Debug", "Started", telemetry.encode_run_environment(self.env_options)
|
||||
)
|
||||
self._auto_continue_timer = task.LoopingCall(self._auto_exec_continue)
|
||||
self._auto_continue_timer.start(0.1)
|
||||
|
||||
@ -250,20 +253,19 @@ class GDBClient(BaseProcess): # pylint: disable=too-many-instance-attributes
|
||||
self._target_is_run = True
|
||||
|
||||
def _handle_error(self, data):
|
||||
self._errors_buffer += data
|
||||
if self.PIO_SRC_NAME.encode() not in data or b"Error in sourced" not in data:
|
||||
return
|
||||
configuration = {"debug": self.debug_options, "env": self.env_options}
|
||||
exd = re.sub(r'\\(?!")', "/", json.dumps(configuration))
|
||||
exd = re.sub(
|
||||
r'"(?:[a-z]\:)?((/[^"/]+)+)"',
|
||||
lambda m: '"%s"' % join(*m.group(1).split("/")[-2:]),
|
||||
exd,
|
||||
re.I | re.M,
|
||||
|
||||
last_erros = self._errors_buffer.decode()
|
||||
last_erros = " ".join(reversed(last_erros.split("\n")))
|
||||
last_erros = re.sub(r'((~|&)"|\\n\"|\\t)', " ", last_erros, flags=re.M)
|
||||
|
||||
err = "%s -> %s" % (
|
||||
telemetry.encode_run_environment(self.env_options),
|
||||
last_erros,
|
||||
)
|
||||
mp = MeasurementProtocol()
|
||||
mp["exd"] = "DebugGDBPioInitError: %s" % exd
|
||||
mp["exf"] = 1
|
||||
mp.send("exception")
|
||||
telemetry.send_exception("DebugInitError: %s" % err, is_fatal=True)
|
||||
self.transport.loseConnection()
|
||||
|
||||
def _kill_previous_session(self):
|
||||
|
@ -23,8 +23,10 @@ import click
|
||||
|
||||
from platformio import app, exception, fs, proc, util
|
||||
from platformio.commands.debug import helpers
|
||||
from platformio.commands.debug.exception import DebugInvalidOptionsError
|
||||
from platformio.managers.core import inject_contrib_pysite
|
||||
from platformio.project.config import ProjectConfig
|
||||
from platformio.project.exception import ProjectEnvsNotAvailableError
|
||||
from platformio.project.helpers import is_platformio_project, load_project_ide_data
|
||||
|
||||
|
||||
@ -70,7 +72,7 @@ def cli(ctx, project_dir, project_conf, environment, verbose, interface, __unpro
|
||||
env_name = environment or helpers.get_default_debug_env(config)
|
||||
env_options = config.items(env=env_name, as_dict=True)
|
||||
if not set(env_options.keys()) >= set(["platform", "board"]):
|
||||
raise exception.ProjectEnvsNotAvailable()
|
||||
raise ProjectEnvsNotAvailableError()
|
||||
debug_options = helpers.validate_debug_options(ctx, env_options)
|
||||
assert debug_options
|
||||
|
||||
@ -79,7 +81,7 @@ def cli(ctx, project_dir, project_conf, environment, verbose, interface, __unpro
|
||||
|
||||
configuration = load_project_ide_data(project_dir, env_name)
|
||||
if not configuration:
|
||||
raise exception.DebugInvalidOptions("Could not load debug configuration")
|
||||
raise DebugInvalidOptionsError("Could not load debug configuration")
|
||||
|
||||
if "--version" in __unprocessed:
|
||||
result = proc.exec_command([configuration["gdb_path"], "--version"])
|
||||
@ -140,7 +142,7 @@ def cli(ctx, project_dir, project_conf, environment, verbose, interface, __unpro
|
||||
helpers.is_prog_obsolete(configuration["prog_path"])
|
||||
|
||||
if not isfile(configuration["prog_path"]):
|
||||
raise exception.DebugInvalidOptions("Program/firmware is missed")
|
||||
raise DebugInvalidOptionsError("Program/firmware is missed")
|
||||
|
||||
# run debugging client
|
||||
inject_contrib_pysite()
|
||||
|
33
platformio/commands/debug/exception.py
Normal file
33
platformio/commands/debug/exception.py
Normal file
@ -0,0 +1,33 @@
|
||||
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from platformio.exception import PlatformioException, UserSideException
|
||||
|
||||
|
||||
class DebugError(PlatformioException):
|
||||
pass
|
||||
|
||||
|
||||
class DebugSupportError(DebugError, UserSideException):
|
||||
|
||||
MESSAGE = (
|
||||
"Currently, PlatformIO does not support debugging for `{0}`.\n"
|
||||
"Please request support at https://github.com/platformio/"
|
||||
"platformio-core/issues \nor visit -> https://docs.platformio.org"
|
||||
"/page/plus/debugging.html"
|
||||
)
|
||||
|
||||
|
||||
class DebugInvalidOptionsError(DebugError, UserSideException):
|
||||
pass
|
@ -22,6 +22,7 @@ from os.path import isfile
|
||||
|
||||
from platformio import exception, fs, util
|
||||
from platformio.commands import PlatformioCLI
|
||||
from platformio.commands.debug.exception import DebugInvalidOptionsError
|
||||
from platformio.commands.platform import platform_install as cmd_platform_install
|
||||
from platformio.commands.run.command import cli as cmd_run
|
||||
from platformio.compat import is_bytes
|
||||
@ -301,7 +302,5 @@ def reveal_debug_port(env_debug_port, tool_name, tool_settings):
|
||||
|
||||
debug_port = _look_for_serial_port(tool_settings.get("hwids", []))
|
||||
if not debug_port:
|
||||
raise exception.DebugInvalidOptions(
|
||||
"Please specify `debug_port` for environment"
|
||||
)
|
||||
raise DebugInvalidOptionsError("Please specify `debug_port` for environment")
|
||||
return debug_port
|
||||
|
@ -17,7 +17,8 @@ from os.path import isdir, isfile, join
|
||||
|
||||
from twisted.internet import reactor # pylint: disable=import-error
|
||||
|
||||
from platformio import exception, fs, util
|
||||
from platformio import fs, util
|
||||
from platformio.commands.debug.exception import DebugInvalidOptionsError
|
||||
from platformio.commands.debug.helpers import escape_gdbmi_stream, is_gdbmi_mode
|
||||
from platformio.commands.debug.process import BaseProcess
|
||||
from platformio.proc import where_is_program
|
||||
@ -53,7 +54,7 @@ class DebugServer(BaseProcess):
|
||||
if not isfile(server_executable):
|
||||
server_executable = where_is_program(server_executable)
|
||||
if not isfile(server_executable):
|
||||
raise exception.DebugInvalidOptions(
|
||||
raise DebugInvalidOptionsError(
|
||||
"\nCould not launch Debug Server '%s'. Please check that it "
|
||||
"is installed and is included in a system PATH\n\n"
|
||||
"See documentation or contact contact@platformio.org:\n"
|
||||
|
@ -22,6 +22,7 @@ from serial.tools import miniterm
|
||||
from platformio import exception, fs, util
|
||||
from platformio.compat import dump_json_to_unicode
|
||||
from platformio.project.config import ProjectConfig
|
||||
from platformio.project.exception import NotPlatformIOProjectError
|
||||
|
||||
|
||||
@click.group(short_help="Monitor device or list existing")
|
||||
@ -181,7 +182,7 @@ def device_monitor(**kwargs): # pylint: disable=too-many-branches
|
||||
with fs.cd(kwargs["project_dir"]):
|
||||
project_options = get_project_options(kwargs["environment"])
|
||||
kwargs = apply_project_monitor_options(kwargs, project_options)
|
||||
except exception.NotPlatformIOProject:
|
||||
except NotPlatformIOProjectError:
|
||||
pass
|
||||
|
||||
if not kwargs["port"]:
|
||||
|
@ -27,6 +27,7 @@ from platformio.compat import PY2, get_filesystem_encoding
|
||||
from platformio.ide.projectgenerator import ProjectGenerator
|
||||
from platformio.managers.platform import PlatformManager
|
||||
from platformio.project.config import ProjectConfig
|
||||
from platformio.project.exception import ProjectError
|
||||
from platformio.project.helpers import get_project_dir, is_platformio_project
|
||||
from platformio.project.options import get_config_options_schema
|
||||
|
||||
@ -113,7 +114,7 @@ class ProjectRPC(object):
|
||||
try:
|
||||
with fs.cd(project_dir):
|
||||
data = _get_project_data()
|
||||
except exception.PlatformIOProjectException:
|
||||
except ProjectError:
|
||||
continue
|
||||
|
||||
for board_id in data.get("boards", []):
|
||||
@ -158,7 +159,7 @@ class ProjectRPC(object):
|
||||
config = ProjectConfig(os.path.join(project_dir, "platformio.ini"))
|
||||
config.validate(silent=True)
|
||||
project_description = config.get("platformio", "description")
|
||||
except exception.PlatformIOProjectException:
|
||||
except ProjectError:
|
||||
continue
|
||||
|
||||
path_tokens = project_dir.split(os.path.sep)
|
||||
|
@ -23,6 +23,7 @@ import click
|
||||
from platformio import exception, fs
|
||||
from platformio.commands import device
|
||||
from platformio.managers.core import pioplus_call
|
||||
from platformio.project.exception import NotPlatformIOProjectError
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
@ -198,7 +199,7 @@ def device_monitor(ctx, **kwargs):
|
||||
with fs.cd(kwargs["project_dir"]):
|
||||
project_options = device.get_project_options(kwargs["environment"])
|
||||
kwargs = device.apply_project_monitor_options(kwargs, project_options)
|
||||
except exception.NotPlatformIOProject:
|
||||
except NotPlatformIOProjectError:
|
||||
pass
|
||||
|
||||
kwargs["baud"] = kwargs["baud"] or 9600
|
||||
|
@ -16,6 +16,7 @@ from platformio import exception, telemetry
|
||||
from platformio.commands.platform import platform_install as cmd_platform_install
|
||||
from platformio.commands.test.processor import CTX_META_TEST_RUNNING_NAME
|
||||
from platformio.managers.platform import PlatformFactory
|
||||
from platformio.project.exception import UndefinedEnvPlatformError
|
||||
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
|
||||
@ -56,12 +57,12 @@ class EnvironmentProcessor(object):
|
||||
|
||||
def process(self):
|
||||
if "platform" not in self.options:
|
||||
raise exception.UndefinedEnvPlatform(self.name)
|
||||
raise UndefinedEnvPlatformError(self.name)
|
||||
|
||||
build_vars = self.get_build_variables()
|
||||
build_targets = list(self.get_build_targets())
|
||||
|
||||
telemetry.on_run_environment(self.options, build_targets)
|
||||
telemetry.send_run_environment(self.options, build_targets)
|
||||
|
||||
# skip monitor target, we call it above
|
||||
if "monitor" in build_targets:
|
||||
|
@ -152,49 +152,6 @@ class FDSHASumMismatch(PlatformIOPackageException):
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Project
|
||||
#
|
||||
|
||||
|
||||
class PlatformIOProjectException(PlatformioException):
|
||||
pass
|
||||
|
||||
|
||||
class NotPlatformIOProject(PlatformIOProjectException):
|
||||
|
||||
MESSAGE = (
|
||||
"Not a PlatformIO project. `platformio.ini` file has not been "
|
||||
"found in current working directory ({0}). To initialize new project "
|
||||
"please use `platformio init` command"
|
||||
)
|
||||
|
||||
|
||||
class InvalidProjectConf(PlatformIOProjectException):
|
||||
|
||||
MESSAGE = "Invalid '{0}' (project configuration file): '{1}'"
|
||||
|
||||
|
||||
class UndefinedEnvPlatform(PlatformIOProjectException):
|
||||
|
||||
MESSAGE = "Please specify platform for '{0}' environment"
|
||||
|
||||
|
||||
class ProjectEnvsNotAvailable(PlatformIOProjectException):
|
||||
|
||||
MESSAGE = "Please setup environments in `platformio.ini` file"
|
||||
|
||||
|
||||
class UnknownEnvNames(PlatformIOProjectException):
|
||||
|
||||
MESSAGE = "Unknown environment names '{0}'. Valid names are '{1}'"
|
||||
|
||||
|
||||
class ProjectOptionValueError(PlatformIOProjectException):
|
||||
|
||||
MESSAGE = "{0} for option `{1}` in section [{2}]"
|
||||
|
||||
|
||||
#
|
||||
# Library
|
||||
#
|
||||
@ -319,7 +276,7 @@ class UpgradeError(PlatformioException):
|
||||
"""
|
||||
|
||||
|
||||
class HomeDirPermissionsError(PlatformioException):
|
||||
class HomeDirPermissionsError(UserSideException):
|
||||
|
||||
MESSAGE = (
|
||||
"The directory `{0}` or its parent directory is not owned by the "
|
||||
@ -338,20 +295,6 @@ class CygwinEnvDetected(PlatformioException):
|
||||
)
|
||||
|
||||
|
||||
class DebugSupportError(PlatformioException):
|
||||
|
||||
MESSAGE = (
|
||||
"Currently, PlatformIO does not support debugging for `{0}`.\n"
|
||||
"Please request support at https://github.com/platformio/"
|
||||
"platformio-core/issues \nor visit -> https://docs.platformio.org"
|
||||
"/page/plus/debugging.html"
|
||||
)
|
||||
|
||||
|
||||
class DebugInvalidOptions(PlatformioException):
|
||||
pass
|
||||
|
||||
|
||||
class TestDirNotExists(PlatformioException):
|
||||
|
||||
MESSAGE = (
|
||||
|
@ -151,7 +151,7 @@ def after_upgrade(ctx):
|
||||
"PlatformIO has been successfully upgraded to %s!\n" % __version__,
|
||||
fg="green",
|
||||
)
|
||||
telemetry.on_event(
|
||||
telemetry.send_event(
|
||||
category="Auto",
|
||||
action="Upgrade",
|
||||
label="%s > %s" % (last_version, __version__),
|
||||
@ -315,7 +315,7 @@ def check_internal_updates(ctx, what):
|
||||
ctx.invoke(cmd_lib_update, libraries=outdated_items)
|
||||
click.echo()
|
||||
|
||||
telemetry.on_event(category="Auto", action="Update", label=what.title())
|
||||
telemetry.send_event(category="Auto", action="Update", label=what.title())
|
||||
|
||||
click.echo("*" * terminal_width)
|
||||
click.echo("")
|
||||
|
@ -26,7 +26,7 @@ from platformio.project.config import ProjectConfig
|
||||
CORE_PACKAGES = {
|
||||
"contrib-piohome": ">=3.1.0-beta.3,<3.2.0",
|
||||
"contrib-pysite": "~2.%d%d.0" % (sys.version_info[0], sys.version_info[1]),
|
||||
"tool-pioplus": "^2.6.0",
|
||||
"tool-pioplus": "^2.6.1",
|
||||
"tool-unity": "~1.20403.0",
|
||||
"tool-scons": "~2.20501.7" if PY2 else "~3.30101.0",
|
||||
"tool-cppcheck": "~1.189.0",
|
||||
|
@ -24,7 +24,7 @@ import click
|
||||
import requests
|
||||
import semantic_version
|
||||
|
||||
from platformio import __version__, app, exception, fs, telemetry, util
|
||||
from platformio import __version__, app, exception, fs, util
|
||||
from platformio.compat import hashlib_encode_data
|
||||
from platformio.downloader import FileDownloader
|
||||
from platformio.lockfile import LockFile
|
||||
@ -660,7 +660,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
||||
|
||||
def install(
|
||||
self, name, requirements=None, silent=False, after_update=False, force=False
|
||||
):
|
||||
): # pylint: disable=unused-argument
|
||||
pkg_dir = None
|
||||
# interprocess lock
|
||||
with LockFile(self.package_dir):
|
||||
@ -709,13 +709,6 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
||||
manifest = self.load_manifest(pkg_dir)
|
||||
assert manifest
|
||||
|
||||
if not after_update:
|
||||
telemetry.on_event(
|
||||
category=self.__class__.__name__,
|
||||
action="Install",
|
||||
label=manifest["name"],
|
||||
)
|
||||
|
||||
click.secho(
|
||||
"{name} @ {version} has been successfully installed!".format(
|
||||
**manifest
|
||||
@ -725,7 +718,9 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
||||
|
||||
return pkg_dir
|
||||
|
||||
def uninstall(self, package, requirements=None, after_update=False):
|
||||
def uninstall(
|
||||
self, package, requirements=None, after_update=False
|
||||
): # pylint: disable=unused-argument
|
||||
# interprocess lock
|
||||
with LockFile(self.package_dir):
|
||||
self.cache_reset()
|
||||
@ -764,13 +759,6 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
||||
|
||||
click.echo("[%s]" % click.style("OK", fg="green"))
|
||||
|
||||
if not after_update:
|
||||
telemetry.on_event(
|
||||
category=self.__class__.__name__,
|
||||
action="Uninstall",
|
||||
label=manifest["name"],
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
def update(self, package, requirements=None, only_check=False):
|
||||
@ -819,9 +807,6 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
||||
self.uninstall(pkg_dir, after_update=True)
|
||||
self.install(name, latest, after_update=True)
|
||||
|
||||
telemetry.on_event(
|
||||
category=self.__class__.__name__, action="Update", label=manifest["name"]
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
|
@ -23,7 +23,11 @@ from os.path import basename, dirname, isdir, isfile, join
|
||||
import click
|
||||
import semantic_version
|
||||
|
||||
from platformio import __version__, app, exception, fs, proc, util
|
||||
from platformio import __version__, app, exception, fs, proc, telemetry, util
|
||||
from platformio.commands.debug.exception import (
|
||||
DebugInvalidOptionsError,
|
||||
DebugSupportError,
|
||||
)
|
||||
from platformio.compat import PY2, hashlib_encode_data, is_bytes, load_python_module
|
||||
from platformio.managers.core import get_core_package_dir
|
||||
from platformio.managers.package import BasePkgManager, PackageManager
|
||||
@ -799,11 +803,12 @@ class PlatformBoardConfig(object):
|
||||
if tool_name == "custom":
|
||||
return tool_name
|
||||
if not debug_tools:
|
||||
raise exception.DebugSupportError(self._manifest["name"])
|
||||
telemetry.send_event("Debug", "Request", self.id)
|
||||
raise DebugSupportError(self._manifest["name"])
|
||||
if tool_name:
|
||||
if tool_name in debug_tools:
|
||||
return tool_name
|
||||
raise exception.DebugInvalidOptions(
|
||||
raise DebugInvalidOptionsError(
|
||||
"Unknown debug tool `%s`. Please use one of `%s` or `custom`"
|
||||
% (tool_name, ", ".join(sorted(list(debug_tools))))
|
||||
)
|
||||
|
@ -20,8 +20,9 @@ from hashlib import sha1
|
||||
|
||||
import click
|
||||
|
||||
from platformio import exception, fs
|
||||
from platformio import fs
|
||||
from platformio.compat import PY2, WINDOWS, hashlib_encode_data
|
||||
from platformio.project import exception
|
||||
from platformio.project.options import ProjectOptions
|
||||
|
||||
try:
|
||||
@ -104,7 +105,7 @@ class ProjectConfigBase(object):
|
||||
try:
|
||||
self._parser.read(path)
|
||||
except ConfigParser.Error as e:
|
||||
raise exception.InvalidProjectConf(path, str(e))
|
||||
raise exception.InvalidProjectConfError(path, str(e))
|
||||
|
||||
if not parse_extra:
|
||||
return
|
||||
@ -273,7 +274,7 @@ class ProjectConfigBase(object):
|
||||
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
||||
pass # handle value from system environment
|
||||
except ConfigParser.Error as e:
|
||||
raise exception.InvalidProjectConf(self.path, str(e))
|
||||
raise exception.InvalidProjectConfError(self.path, str(e))
|
||||
|
||||
option_meta = ProjectOptions.get("%s.%s" % (section.split(":", 1)[0], option))
|
||||
if not option_meta:
|
||||
@ -327,14 +328,14 @@ class ProjectConfigBase(object):
|
||||
|
||||
def validate(self, envs=None, silent=False):
|
||||
if not os.path.isfile(self.path):
|
||||
raise exception.NotPlatformIOProject(self.path)
|
||||
raise exception.NotPlatformIOProjectError(self.path)
|
||||
# check envs
|
||||
known = set(self.envs())
|
||||
if not known:
|
||||
raise exception.ProjectEnvsNotAvailable()
|
||||
raise exception.ProjectEnvsNotAvailableError()
|
||||
unknown = set(list(envs or []) + self.default_envs()) - known
|
||||
if unknown:
|
||||
raise exception.UnknownEnvNames(", ".join(unknown), ", ".join(known))
|
||||
raise exception.UnknownEnvNamesError(", ".join(unknown), ", ".join(known))
|
||||
if not silent:
|
||||
for warning in self.warnings:
|
||||
click.secho("Warning! %s" % warning, fg="yellow")
|
||||
|
53
platformio/project/exception.py
Normal file
53
platformio/project/exception.py
Normal file
@ -0,0 +1,53 @@
|
||||
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from platformio.exception import PlatformioException, UserSideException
|
||||
|
||||
|
||||
class ProjectError(PlatformioException):
|
||||
pass
|
||||
|
||||
|
||||
class NotPlatformIOProjectError(ProjectError, UserSideException):
|
||||
|
||||
MESSAGE = (
|
||||
"Not a PlatformIO project. `platformio.ini` file has not been "
|
||||
"found in current working directory ({0}). To initialize new project "
|
||||
"please use `platformio init` command"
|
||||
)
|
||||
|
||||
|
||||
class InvalidProjectConfError(ProjectError, UserSideException):
|
||||
|
||||
MESSAGE = "Invalid '{0}' (project configuration file): '{1}'"
|
||||
|
||||
|
||||
class UndefinedEnvPlatformError(ProjectError, UserSideException):
|
||||
|
||||
MESSAGE = "Please specify platform for '{0}' environment"
|
||||
|
||||
|
||||
class ProjectEnvsNotAvailableError(ProjectError, UserSideException):
|
||||
|
||||
MESSAGE = "Please setup environments in `platformio.ini` file"
|
||||
|
||||
|
||||
class UnknownEnvNamesError(ProjectError, UserSideException):
|
||||
|
||||
MESSAGE = "Unknown environment names '{0}'. Valid names are '{1}'"
|
||||
|
||||
|
||||
class ProjectOptionValueError(ProjectError, UserSideException):
|
||||
|
||||
MESSAGE = "{0} for option `{1}` in section [{2}]"
|
@ -13,13 +13,12 @@
|
||||
# limitations under the License.
|
||||
|
||||
import atexit
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import sys
|
||||
import threading
|
||||
from collections import deque
|
||||
from os import getenv, sep
|
||||
from os.path import join
|
||||
from time import sleep, time
|
||||
from traceback import format_exc
|
||||
|
||||
@ -99,8 +98,8 @@ class MeasurementProtocol(TelemetryBase):
|
||||
dpdata.append("PlatformIO/%s" % __version__)
|
||||
if app.get_session_var("caller_id"):
|
||||
dpdata.append("Caller/%s" % app.get_session_var("caller_id"))
|
||||
if getenv("PLATFORMIO_IDE"):
|
||||
dpdata.append("IDE/%s" % getenv("PLATFORMIO_IDE"))
|
||||
if os.getenv("PLATFORMIO_IDE"):
|
||||
dpdata.append("IDE/%s" % os.getenv("PLATFORMIO_IDE"))
|
||||
self["an"] = " ".join(dpdata)
|
||||
|
||||
def _prefill_custom_data(self):
|
||||
@ -179,13 +178,10 @@ class MeasurementProtocol(TelemetryBase):
|
||||
cmd_path.append(sub_cmd)
|
||||
self["screen_name"] = " ".join([p.title() for p in cmd_path])
|
||||
|
||||
@staticmethod
|
||||
def _ignore_hit():
|
||||
def _ignore_hit(self):
|
||||
if not app.get_setting("enable_telemetry"):
|
||||
return True
|
||||
if app.get_session_var("caller_id") and all(
|
||||
c in sys.argv for c in ("run", "idedata")
|
||||
):
|
||||
if all(c in sys.argv for c in ("run", "idedata")) or self["ea"] == "Idedata":
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -296,29 +292,64 @@ def on_command():
|
||||
measure_ci()
|
||||
|
||||
|
||||
def on_exception(e):
|
||||
skip_conditions = [
|
||||
isinstance(e, cls)
|
||||
for cls in (IOError, exception.ReturnErrorCode, exception.UserSideException,)
|
||||
]
|
||||
try:
|
||||
skip_conditions.append("[API] Account: " in str(e))
|
||||
except UnicodeEncodeError as ue:
|
||||
e = ue
|
||||
if any(skip_conditions):
|
||||
return
|
||||
is_fatal = any(
|
||||
[
|
||||
not isinstance(e, exception.PlatformioException),
|
||||
"Error" in e.__class__.__name__,
|
||||
]
|
||||
)
|
||||
description = "%s: %s" % (
|
||||
type(e).__name__,
|
||||
" ".join(reversed(format_exc().split("\n"))) if is_fatal else str(e),
|
||||
)
|
||||
send_exception(description, is_fatal)
|
||||
|
||||
|
||||
def measure_ci():
|
||||
event = {"category": "CI", "action": "NoName", "label": None}
|
||||
known_cis = ("TRAVIS", "APPVEYOR", "GITLAB_CI", "CIRCLECI", "SHIPPABLE", "DRONE")
|
||||
for name in known_cis:
|
||||
if getenv(name, "false").lower() == "true":
|
||||
if os.getenv(name, "false").lower() == "true":
|
||||
event["action"] = name
|
||||
break
|
||||
on_event(**event)
|
||||
send_event(**event)
|
||||
|
||||
|
||||
def on_run_environment(options, targets):
|
||||
non_sensative_values = ["board", "platform", "framework"]
|
||||
safe_options = []
|
||||
for key, value in sorted(options.items()):
|
||||
if key in non_sensative_values:
|
||||
safe_options.append("%s=%s" % (key, value))
|
||||
else:
|
||||
safe_options.append(key)
|
||||
targets = [t.title() for t in targets or ["run"]]
|
||||
on_event("Env", " ".join(targets), "&".join(safe_options))
|
||||
def encode_run_environment(options):
|
||||
non_sensative_keys = [
|
||||
"platform",
|
||||
"framework",
|
||||
"board",
|
||||
"upload_protocol",
|
||||
"check_tool",
|
||||
"debug_tool",
|
||||
]
|
||||
safe_options = [
|
||||
"%s=%s" % (k, v) for k, v in sorted(options.items()) if k in non_sensative_keys
|
||||
]
|
||||
return "&".join(safe_options)
|
||||
|
||||
|
||||
def on_event(category, action, label=None, value=None, screen_name=None):
|
||||
def send_run_environment(options, targets):
|
||||
send_event(
|
||||
"Env",
|
||||
" ".join([t.title() for t in targets or ["run"]]),
|
||||
encode_run_environment(options),
|
||||
)
|
||||
|
||||
|
||||
def send_event(category, action, label=None, value=None, screen_name=None):
|
||||
mp = MeasurementProtocol()
|
||||
mp["event_category"] = category[:150]
|
||||
mp["event_action"] = action[:500]
|
||||
@ -331,43 +362,21 @@ def on_event(category, action, label=None, value=None, screen_name=None):
|
||||
mp.send("event")
|
||||
|
||||
|
||||
def on_exception(e):
|
||||
def _cleanup_description(text):
|
||||
text = text.replace("Traceback (most recent call last):", "")
|
||||
text = re.sub(
|
||||
r'File "([^"]+)"',
|
||||
lambda m: join(*m.group(1).split(sep)[-2:]),
|
||||
text,
|
||||
flags=re.M,
|
||||
)
|
||||
text = re.sub(r"\s+", " ", text, flags=re.M)
|
||||
return text.strip()
|
||||
|
||||
skip_conditions = [
|
||||
isinstance(e, cls)
|
||||
for cls in (
|
||||
IOError,
|
||||
exception.ReturnErrorCode,
|
||||
exception.UserSideException,
|
||||
exception.PlatformIOProjectException,
|
||||
)
|
||||
]
|
||||
try:
|
||||
skip_conditions.append("[API] Account: " in str(e))
|
||||
except UnicodeEncodeError as ue:
|
||||
e = ue
|
||||
if any(skip_conditions):
|
||||
return
|
||||
is_crash = any(
|
||||
[
|
||||
not isinstance(e, exception.PlatformioException),
|
||||
"Error" in e.__class__.__name__,
|
||||
]
|
||||
def send_exception(description, is_fatal=False):
|
||||
# cleanup sensitive information, such as paths
|
||||
description = description.replace("Traceback (most recent call last):", "")
|
||||
description = description.replace("\\", "/")
|
||||
description = re.sub(
|
||||
r'(^|\s+|")(?:[a-z]\:)?((/[^"/]+)+)(\s+|"|$)',
|
||||
lambda m: " %s " % os.path.join(*m.group(2).split("/")[-2:]),
|
||||
description,
|
||||
re.I | re.M,
|
||||
)
|
||||
description = re.sub(r"\s+", " ", description, flags=re.M)
|
||||
|
||||
mp = MeasurementProtocol()
|
||||
description = _cleanup_description(format_exc() if is_crash else str(e))
|
||||
mp["exd"] = ("%s: %s" % (type(e).__name__, description))[:2048]
|
||||
mp["exf"] = 1 if is_crash else 0
|
||||
mp["exd"] = description[:8192].strip()
|
||||
mp["exf"] = 1 if is_fatal else 0
|
||||
mp.send("exception")
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user