From ee7ea77fc3e7d001c2b7b4e2d8a07436afa10d50 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 1 Apr 2021 21:15:14 +0300 Subject: [PATCH] Fixed an error "Unknown development platform" when running unit tests on a clean machine // Resolve #3901 --- HISTORY.rst | 1 + platformio/commands/debug.py | 18 +- platformio/commands/platform.py | 304 +++++++++++++++------------ platformio/commands/run/processor.py | 18 +- platformio/commands/test/command.py | 6 +- 5 files changed, 180 insertions(+), 167 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 3088ddd9..8f6a20cc 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -30,6 +30,7 @@ PlatformIO Core 5 * **Miscellaneous** - Ensure that a serial port is ready before running unit tests on a remote target (`issue #3742 `_) + - Fixed an error "Unknown development platform" when running unit tests on a clean machine (`issue #3901 `_) 5.1.1 (2021-03-17) ~~~~~~~~~~~~~~~~~~ diff --git a/platformio/commands/debug.py b/platformio/commands/debug.py index 661ad7e1..e176bab3 100644 --- a/platformio/commands/debug.py +++ b/platformio/commands/debug.py @@ -22,14 +22,12 @@ import subprocess import click from platformio import app, exception, fs, proc -from platformio.commands.platform import platform_install as cmd_platform_install +from platformio.commands.platform import init_platform from platformio.compat import IS_WINDOWS from platformio.debug import helpers from platformio.debug.config.factory import DebugConfigFactory from platformio.debug.exception import DebugInvalidOptionsError from platformio.debug.process.gdb import GDBClientProcess -from platformio.platform.exception import UnknownPlatform -from platformio.platform.factory import PlatformFactory from platformio.project.config import ProjectConfig from platformio.project.exception import ProjectEnvsNotAvailableError from platformio.project.helpers import is_platformio_project @@ -84,17 +82,9 @@ def cli(ctx, project_dir, project_conf, environment, verbose, interface, __unpro if "platform" not in env_options: raise ProjectEnvsNotAvailableError() - try: - platform = PlatformFactory.new(env_options["platform"]) - except UnknownPlatform: - ctx.invoke( - cmd_platform_install, - platforms=[env_options["platform"]], - skip_default_package=True, - ) - platform = PlatformFactory.new(env_options["platform"]) - - debug_config = DebugConfigFactory.new(platform, project_config, env_name) + debug_config = DebugConfigFactory.new( + init_platform(env_options["platform"]), project_config, env_name + ) if "--version" in __unprocessed: return subprocess.run( diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index f03f8833..84945e39 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -31,139 +31,6 @@ def cli(): pass -def _print_platforms(platforms): - for platform in platforms: - click.echo( - "{name} ~ {title}".format( - name=click.style(platform["name"], fg="cyan"), title=platform["title"] - ) - ) - click.echo("=" * (3 + len(platform["name"] + platform["title"]))) - click.echo(platform["description"]) - click.echo() - if "homepage" in platform: - click.echo("Home: %s" % platform["homepage"]) - if "frameworks" in platform and platform["frameworks"]: - click.echo("Frameworks: %s" % ", ".join(platform["frameworks"])) - if "packages" in platform: - click.echo("Packages: %s" % ", ".join(platform["packages"])) - if "version" in platform: - if "__src_url" in platform: - click.echo( - "Version: %s (%s)" % (platform["version"], platform["__src_url"]) - ) - else: - click.echo("Version: " + platform["version"]) - click.echo() - - -def _get_registry_platforms(): - regclient = PlatformPackageManager().get_registry_client_instance() - return regclient.fetch_json_data("get", "/v2/platforms", cache_valid="1d") - - -def _get_platform_data(*args, **kwargs): - try: - return _get_installed_platform_data(*args, **kwargs) - except UnknownPlatform: - return _get_registry_platform_data(*args, **kwargs) - - -def _get_installed_platform_data(platform, with_boards=True, expose_packages=True): - p = PlatformFactory.new(platform) - data = dict( - name=p.name, - title=p.title, - description=p.description, - version=p.version, - homepage=p.homepage, - url=p.homepage, - repository=p.repository_url, - license=p.license, - forDesktop=not p.is_embedded(), - frameworks=sorted(list(p.frameworks) if p.frameworks else []), - packages=list(p.packages) if p.packages else [], - ) - - # if dump to API - # del data['version'] - # return data - - # overwrite VCS version and add extra fields - manifest = PlatformPackageManager().legacy_load_manifest( - os.path.dirname(p.manifest_path) - ) - assert manifest - for key in manifest: - if key == "version" or key.startswith("__"): - data[key] = manifest[key] - - if with_boards: - data["boards"] = [c.get_brief_data() for c in p.get_boards().values()] - - if not data["packages"] or not expose_packages: - return data - - data["packages"] = [] - installed_pkgs = { - pkg.metadata.name: p.pm.load_manifest(pkg) for pkg in p.get_installed_packages() - } - for name, options in p.packages.items(): - item = dict( - name=name, - type=p.get_package_type(name), - requirements=options.get("version"), - optional=options.get("optional") is True, - ) - if name in installed_pkgs: - for key, value in installed_pkgs[name].items(): - if key not in ("url", "version", "description"): - continue - item[key] = value - if key == "version": - item["originalVersion"] = get_original_version(value) - data["packages"].append(item) - - return data - - -def _get_registry_platform_data( # pylint: disable=unused-argument - platform, with_boards=True, expose_packages=True -): - _data = None - for p in _get_registry_platforms(): - if p["name"] == platform: - _data = p - break - - if not _data: - return None - - data = dict( - ownername=_data.get("ownername"), - name=_data["name"], - title=_data["title"], - description=_data["description"], - homepage=_data["homepage"], - repository=_data["repository"], - url=_data["url"], - license=_data["license"], - forDesktop=_data["forDesktop"], - frameworks=_data["frameworks"], - packages=_data["packages"], - versions=_data.get("versions"), - ) - - if with_boards: - data["boards"] = [ - board - for board in PlatformPackageManager().get_registered_boards() - if board["platform"] == _data["name"] - ] - - return data - - @cli.command("search", short_help="Search for development platform") @click.argument("query", required=False) @click.option("--json-output", is_flag=True) @@ -319,13 +186,33 @@ def platform_install( # pylint: disable=too-many-arguments with_all_packages, silent, force, +): + return _platform_install( + platforms, + with_package, + without_package, + skip_default_package, + with_all_packages, + silent, + force, + ) + + +def _platform_install( # pylint: disable=too-many-arguments + platforms, + with_package=None, + without_package=None, + skip_default_package=False, + with_all_packages=False, + silent=False, + force=False, ): pm = PlatformPackageManager() for platform in platforms: pkg = pm.install( spec=platform, - with_packages=with_package, - without_packages=without_package, + with_packages=with_package or [], + without_packages=without_package or [], skip_default_package=skip_default_package, with_all_packages=with_all_packages, silent=silent, @@ -423,3 +310,150 @@ def platform_update( # pylint: disable=too-many-locals, too-many-arguments click.echo() return True + + +# +# Helpers +# + + +def init_platform(name, skip_default_package=True, auto_install=True): + try: + return PlatformFactory.new(name) + except UnknownPlatform: + if auto_install: + _platform_install([name], skip_default_package=skip_default_package) + return PlatformFactory.new(name) + + +def _print_platforms(platforms): + for platform in platforms: + click.echo( + "{name} ~ {title}".format( + name=click.style(platform["name"], fg="cyan"), title=platform["title"] + ) + ) + click.echo("=" * (3 + len(platform["name"] + platform["title"]))) + click.echo(platform["description"]) + click.echo() + if "homepage" in platform: + click.echo("Home: %s" % platform["homepage"]) + if "frameworks" in platform and platform["frameworks"]: + click.echo("Frameworks: %s" % ", ".join(platform["frameworks"])) + if "packages" in platform: + click.echo("Packages: %s" % ", ".join(platform["packages"])) + if "version" in platform: + if "__src_url" in platform: + click.echo( + "Version: %s (%s)" % (platform["version"], platform["__src_url"]) + ) + else: + click.echo("Version: " + platform["version"]) + click.echo() + + +def _get_registry_platforms(): + regclient = PlatformPackageManager().get_registry_client_instance() + return regclient.fetch_json_data("get", "/v2/platforms", cache_valid="1d") + + +def _get_platform_data(*args, **kwargs): + try: + return _get_installed_platform_data(*args, **kwargs) + except UnknownPlatform: + return _get_registry_platform_data(*args, **kwargs) + + +def _get_installed_platform_data(platform, with_boards=True, expose_packages=True): + p = PlatformFactory.new(platform) + data = dict( + name=p.name, + title=p.title, + description=p.description, + version=p.version, + homepage=p.homepage, + url=p.homepage, + repository=p.repository_url, + license=p.license, + forDesktop=not p.is_embedded(), + frameworks=sorted(list(p.frameworks) if p.frameworks else []), + packages=list(p.packages) if p.packages else [], + ) + + # if dump to API + # del data['version'] + # return data + + # overwrite VCS version and add extra fields + manifest = PlatformPackageManager().legacy_load_manifest( + os.path.dirname(p.manifest_path) + ) + assert manifest + for key in manifest: + if key == "version" or key.startswith("__"): + data[key] = manifest[key] + + if with_boards: + data["boards"] = [c.get_brief_data() for c in p.get_boards().values()] + + if not data["packages"] or not expose_packages: + return data + + data["packages"] = [] + installed_pkgs = { + pkg.metadata.name: p.pm.load_manifest(pkg) for pkg in p.get_installed_packages() + } + for name, options in p.packages.items(): + item = dict( + name=name, + type=p.get_package_type(name), + requirements=options.get("version"), + optional=options.get("optional") is True, + ) + if name in installed_pkgs: + for key, value in installed_pkgs[name].items(): + if key not in ("url", "version", "description"): + continue + item[key] = value + if key == "version": + item["originalVersion"] = get_original_version(value) + data["packages"].append(item) + + return data + + +def _get_registry_platform_data( # pylint: disable=unused-argument + platform, with_boards=True, expose_packages=True +): + _data = None + for p in _get_registry_platforms(): + if p["name"] == platform: + _data = p + break + + if not _data: + return None + + data = dict( + ownername=_data.get("ownername"), + name=_data["name"], + title=_data["title"], + description=_data["description"], + homepage=_data["homepage"], + repository=_data["repository"], + url=_data["url"], + license=_data["license"], + forDesktop=_data["forDesktop"], + frameworks=_data["frameworks"], + packages=_data["packages"], + versions=_data.get("versions"), + ) + + if with_boards: + data["boards"] = [ + board + for board in PlatformPackageManager().get_registered_boards() + if board["platform"] == _data["name"] + ] + + return data diff --git a/platformio/commands/run/processor.py b/platformio/commands/run/processor.py index d07c581c..191a071f 100644 --- a/platformio/commands/run/processor.py +++ b/platformio/commands/run/processor.py @@ -12,10 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from platformio.commands.platform import platform_install as cmd_platform_install +from platformio.commands.platform import init_platform from platformio.commands.test.processor import CTX_META_TEST_RUNNING_NAME -from platformio.platform.exception import UnknownPlatform -from platformio.platform.factory import PlatformFactory from platformio.project.exception import UndefinedEnvPlatformError # pylint: disable=too-many-instance-attributes @@ -66,15 +64,7 @@ class EnvironmentProcessor(object): if "monitor" in build_targets: build_targets.remove("monitor") - try: - p = PlatformFactory.new(self.options["platform"]) - except UnknownPlatform: - self.cmd_ctx.invoke( - cmd_platform_install, - platforms=[self.options["platform"]], - skip_default_package=True, - ) - p = PlatformFactory.new(self.options["platform"]) - - result = p.run(build_vars, build_targets, self.silent, self.verbose, self.jobs) + result = init_platform(self.options["platform"]).run( + build_vars, build_targets, self.silent, self.verbose, self.jobs + ) return result["returncode"] == 0 diff --git a/platformio/commands/test/command.py b/platformio/commands/test/command.py index 40780ab4..bc503093 100644 --- a/platformio/commands/test/command.py +++ b/platformio/commands/test/command.py @@ -22,10 +22,10 @@ import click from tabulate import tabulate from platformio import app, exception, fs, util +from platformio.commands.platform import init_platform from platformio.commands.test.embedded import EmbeddedTestProcessor from platformio.commands.test.helpers import get_test_names from platformio.commands.test.native import NativeTestProcessor -from platformio.platform.factory import PlatformFactory from platformio.project.config import ProjectConfig @@ -141,9 +141,7 @@ def cli( # pylint: disable=redefined-builtin cls = ( EmbeddedTestProcessor if config.get(section, "platform") - and PlatformFactory.new( - config.get(section, "platform") - ).is_embedded() + and init_platform(config.get(section, "platform")).is_embedded() else NativeTestProcessor ) tp = cls(