diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index 445e6e0eaa..c7c020a3b5 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -8,7 +8,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-20.04, windows-latest, macos-latest] - python-version: ["3.6", "3.9", "3.11"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] runs-on: ${{ matrix.os }} @@ -27,12 +27,17 @@ jobs: python -m pip install --upgrade pip pip install tox + - name: Core System Info + run: | + tox -e py + - name: Python Lint if: ${{ matrix.python-version != '3.6' }} run: | tox -e lint - name: Integration Tests + if: ${{ matrix.python-version == '3.9' }} run: | tox -e testcore diff --git a/HISTORY.rst b/HISTORY.rst index 8ec95eb477..882860c3d2 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -13,7 +13,18 @@ Release Notes PlatformIO Core 6 ----------------- -**A professional collaborative platform for declarative, safety-critical, and test-driven embedded development.** +Unlock the true potential of embedded software development with +PlatformIO's collaborative ecosystem, embracing declarative principles, +test-driven methodologies, and modern toolchains for unrivaled success. + +6.1.10 (2023-08-11) +~~~~~~~~~~~~~~~~~~~ + +* Resolved an issue that caused generated projects for `PlatformIO IDE for VSCode `__ to break when the ``-iprefix`` compiler flag was used +* Resolved an issue encountered while utilizing the `pio pkg exec `__ command on the Windows platform to execute Python scripts from a package +* Implemented a crucial improvement to the `pio run `__ command, guaranteeing that the ``monitor`` target is not executed if any of the preceding targets, such as ``upload``, encounter failures +* `Cppcheck `__ v2.11 with new checks, CLI commands and various analysis improvements +* Resolved a critical issue that arose on macOS ARM platforms due to the Python "requests" module, leading to a "ModuleNotFoundError: No module named 'chardet'" (`issue #4702 `_) 6.1.9 (2023-07-06) ~~~~~~~~~~~~~~~~~~ diff --git a/README.rst b/README.rst index cd3454f52d..df73525eab 100644 --- a/README.rst +++ b/README.rst @@ -36,9 +36,11 @@ PlatformIO Core .. image:: https://raw.githubusercontent.com/platformio/platformio-web/develop/app/images/platformio-ide-laptop.png :target: https://platformio.org?utm_source=github&utm_medium=core -`PlatformIO `_ is a professional collaborative platform for embedded development. +`PlatformIO `_: Your Gateway to Embedded Software Development Excellence. -**A place where Developers and Teams have true Freedom! No more vendor lock-in!** +Unlock the true potential of embedded software development with +PlatformIO's collaborative ecosystem, embracing declarative principles, +test-driven methodologies, and modern toolchains for unrivaled success. * Open source, maximum permissive Apache 2.0 license * Cross-platform IDE and Unified Debugger diff --git a/docs b/docs index f8dbf012e4..295991a9c2 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit f8dbf012e4a7ddbe79279540e95c08a2d108c725 +Subproject commit 295991a9c228ab9b1509fbaf41c30d4df7fec553 diff --git a/examples b/examples index 4b572ec9fe..4bed26fd0d 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 4b572ec9fef6df5aacb1e113177f5ec28dda1cde +Subproject commit 4bed26fd0d0b559dcf52f6088c9c2b4ebffd5fd6 diff --git a/platformio/__init__.py b/platformio/__init__.py index c720d00553..b07d2bdc8d 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -12,20 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -VERSION = (6, 1, 9) +VERSION = (6, 1, 10) __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" __description__ = ( - "A professional collaborative platform for embedded development. " - "Cross-platform IDE and Unified Debugger. " - "Static Code Analyzer and Remote Unit Testing. " - "Multi-platform and Multi-architecture Build System. " - "Firmware File Explorer and Memory Inspection. " - "IoT, Arduino, CMSIS, ESP-IDF, FreeRTOS, libOpenCM3, mbedOS, Pulp OS, SPL, " - "STM32Cube, Zephyr RTOS, ARM, AVR, Espressif (ESP8266/ESP32), FPGA, " - "MCS-51 (8051), MSP430, Nordic (nRF51/nRF52), NXP i.MX RT, PIC32, RISC-V, " - "STMicroelectronics (STM8/STM32), Teensy" + "Your Gateway to Embedded Software Development Excellence. " + "Unlock the true potential of embedded software development " + "with PlatformIO's collaborative ecosystem, embracing " + "declarative principles, test-driven methodologies, and " + "modern toolchains for unrivaled success." ) __url__ = "https://platformio.org" @@ -46,7 +42,7 @@ "contrib-piohome": "~3.4.2", "contrib-pioremote": "~1.0.0", "tool-scons": "~4.40502.0", - "tool-cppcheck": "~1.270.0", + "tool-cppcheck": "~1.21100.0", "tool-clangtidy": "~1.150005.0", "tool-pvs-studio": "~7.18.0", } @@ -56,3 +52,22 @@ "88.198.170.159", # platformio.org "github.com", ] + __registry_mirror_hosts__ + +__install_requires__ = [ + # Core requirements + "bottle == 0.12.*", + "click >=8.0.4, <=8.2", + "colorama", + "marshmallow == 3.*", + "pyelftools == 0.29", + "pyserial == 3.5.*", # keep in sync "device/monitor/terminal.py" + "requests == 2.*", + "semantic_version == 2.10.*", + "tabulate == 0.*", +] + [ + # PIO Home requirements + "ajsonrpc == 1.2.*", + "starlette >=0.19, <0.32", + "uvicorn >=0.16, <0.24", + "wsproto == 1.*", +] diff --git a/platformio/app.py b/platformio/app.py index d94cdfefc7..7d2f1ea9b7 100644 --- a/platformio/app.py +++ b/platformio/app.py @@ -258,6 +258,10 @@ def get_cid(): return cid +def get_project_id(project_dir): + return hashlib.sha1(hashlib_encode_data(project_dir)).hexdigest() + + def get_user_agent(): data = [ "PlatformIO/%s" % __version__, @@ -270,6 +274,8 @@ def get_user_agent(): data.append("IDE/%s" % os.getenv("PLATFORMIO_IDE")) data.append("Python/%s" % platform.python_version()) data.append("Platform/%s" % platform.platform()) + if not get_setting("enable_telemetry"): + data.append("Telemetry/0") return " ".join(data) diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 2ca41f38cc..ea8b202b3e 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -38,7 +38,6 @@ # append CLI arguments to build environment clivars = Variables(None) clivars.AddVariables( - ("PLATFORM_MANIFEST",), ("BUILD_SCRIPT",), ("PROJECT_CONFIG",), ("PIOENV",), @@ -72,8 +71,7 @@ variables=clivars, # Propagating External Environment ENV=os.environ, - TIMESTAMP=int(time()), - UNIX_TIME="$TIMESTAMP", # deprecated + UNIX_TIME=int(time()), BUILD_DIR=os.path.join("$PROJECT_BUILD_DIR", "$PIOENV"), BUILD_SRC_DIR=os.path.join("$BUILD_DIR", "src"), BUILD_TEST_DIR=os.path.join("$BUILD_DIR", "test"), diff --git a/platformio/builder/tools/piointegration.py b/platformio/builder/tools/piointegration.py index 25ca1eb070..6f0a972ee1 100644 --- a/platformio/builder/tools/piointegration.py +++ b/platformio/builder/tools/piointegration.py @@ -12,11 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. - import glob import os -import click import SCons.Defaults # pylint: disable=import-error import SCons.Subst # pylint: disable=import-error from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error @@ -140,9 +138,9 @@ def dump_svd_path(env): return None -def _subst_cmd(env, cmd): - args = env.subst_list(cmd, SCons.Subst.SUBST_CMD)[0] - return " ".join([SCons.Subst.quote_spaces(arg) for arg in args]) +def _split_flags_string(env, s): + args = env.subst_list(s, SCons.Subst.SUBST_CMD)[0] + return [str(arg) for arg in args] def DumpIntegrationData(*args): @@ -155,12 +153,8 @@ def DumpIntegrationData(*args): ], "defines": dump_defines(projenv), "includes": projenv.DumpIntegrationIncludes(), - "cc_flags": click.parser.split_arg_string( - _subst_cmd(projenv, "$CFLAGS $CCFLAGS $CPPFLAGS") - ), - "cxx_flags": click.parser.split_arg_string( - _subst_cmd(projenv, "$CXXFLAGS $CCFLAGS $CPPFLAGS") - ), + "cc_flags": _split_flags_string(projenv, "$CFLAGS $CCFLAGS $CPPFLAGS"), + "cxx_flags": _split_flags_string(projenv, "$CXXFLAGS $CCFLAGS $CPPFLAGS"), "cc_path": where_is_program( globalenv.subst("$CC"), globalenv.subst("${ENV['PATH']}") ), diff --git a/platformio/builder/tools/pioplatform.py b/platformio/builder/tools/pioplatform.py index d13c78ec77..4ce4b91d59 100644 --- a/platformio/builder/tools/pioplatform.py +++ b/platformio/builder/tools/pioplatform.py @@ -33,9 +33,7 @@ @util.memoized() def _PioPlatform(): env = DefaultEnvironment() - p = PlatformFactory.new(os.path.dirname(env["PLATFORM_MANIFEST"])) - p.configure_project_packages(env["PIOENV"], COMMAND_LINE_TARGETS) - return p + return PlatformFactory.from_env(env["PIOENV"], targets=COMMAND_LINE_TARGETS) def PioPlatform(_): diff --git a/platformio/builder/tools/piosize.py b/platformio/builder/tools/piosize.py index f562fe64cb..3ac24311e8 100644 --- a/platformio/builder/tools/piosize.py +++ b/platformio/builder/tools/piosize.py @@ -53,7 +53,7 @@ def _get_symbol_locations(env, elf_path, addrs): locations = [line for line in result["out"].split("\n") if line] assert len(addrs) == len(locations) - return dict(zip(addrs, [l.strip() for l in locations])) + return dict(zip(addrs, [loc.strip() for loc in locations])) def _get_demangled_names(env, mangled_names): @@ -73,31 +73,7 @@ def _get_demangled_names(env, mangled_names): ) -def _determine_section(sections, symbol_addr): - for section, info in sections.items(): - if not _is_flash_section(info) and not _is_ram_section(info): - continue - if symbol_addr in range(info["start_addr"], info["start_addr"] + info["size"]): - return section - return "unknown" - - -def _is_ram_section(section): - return ( - section.get("type", "") in ("SHT_NOBITS", "SHT_PROGBITS") - and section.get("flags", "") == "WA" - ) - - -def _is_flash_section(section): - return section.get("type", "") == "SHT_PROGBITS" and "A" in section.get("flags", "") - - -def _is_valid_symbol(symbol_name, symbol_type, symbol_address): - return symbol_name and symbol_address != 0 and symbol_type != "STT_NOTYPE" - - -def _collect_sections_info(elffile): +def _collect_sections_info(env, elffile): sections = {} for section in elffile.iter_sections(): if section.is_null() or section.name.startswith(".debug"): @@ -107,13 +83,18 @@ def _collect_sections_info(elffile): section_flags = describe_sh_flags(section["sh_flags"]) section_size = section.data_size - sections[section.name] = { + section_data = { + "name": section.name, "size": section_size, "start_addr": section["sh_addr"], "type": section_type, "flags": section_flags, } + sections[section.name] = section_data + sections[section.name]["in_flash"] = env.pioSizeIsFlashSection(section_data) + sections[section.name]["in_ram"] = env.pioSizeIsRamSection(section_data) + return sections @@ -136,7 +117,7 @@ def _collect_symbols_info(env, elffile, elf_path, sections): symbol_size = s["st_size"] symbol_type = symbol_info["type"] - if not _is_valid_symbol(s.name, symbol_type, symbol_addr): + if not env.pioSizeIsValidSymbol(s.name, symbol_type, symbol_addr): continue symbol = { @@ -145,7 +126,7 @@ def _collect_symbols_info(env, elffile, elf_path, sections): "name": s.name, "type": symbol_type, "size": symbol_size, - "section": _determine_section(sections, symbol_addr), + "section": env.pioSizeDetermineSection(sections, symbol_addr), } if s.name.startswith("_Z"): @@ -175,12 +156,36 @@ def _collect_symbols_info(env, elffile, elf_path, sections): return symbols -def _calculate_firmware_size(sections): +def pioSizeDetermineSection(_, sections, symbol_addr): + for section, info in sections.items(): + if not info.get("in_flash", False) and not info.get("in_ram", False): + continue + if symbol_addr in range(info["start_addr"], info["start_addr"] + info["size"]): + return section + return "unknown" + + +def pioSizeIsValidSymbol(_, symbol_name, symbol_type, symbol_address): + return symbol_name and symbol_address != 0 and symbol_type != "STT_NOTYPE" + + +def pioSizeIsRamSection(_, section): + return ( + section.get("type", "") in ("SHT_NOBITS", "SHT_PROGBITS") + and section.get("flags", "") == "WA" + ) + + +def pioSizeIsFlashSection(_, section): + return section.get("type", "") == "SHT_PROGBITS" and "A" in section.get("flags", "") + + +def pioSizeCalculateFirmwareSize(_, sections): flash_size = ram_size = 0 for section_info in sections.values(): - if _is_flash_section(section_info): + if section_info.get("in_flash", False): flash_size += section_info.get("size", 0) - if _is_ram_section(section_info): + if section_info.get("in_ram", False): ram_size += section_info.get("size", 0) return ram_size, flash_size @@ -210,8 +215,8 @@ def DumpSizeData(_, target, source, env): # pylint: disable=unused-argument sys.stderr.write("Elf file doesn't contain DWARF information") env.Exit(1) - sections = _collect_sections_info(elffile) - firmware_ram, firmware_flash = _calculate_firmware_size(sections) + sections = _collect_sections_info(env, elffile) + firmware_ram, firmware_flash = env.pioSizeCalculateFirmwareSize(sections) data["memory"]["total"] = { "ram_size": firmware_ram, "flash_size": firmware_flash, @@ -226,9 +231,11 @@ def DumpSizeData(_, target, source, env): # pylint: disable=unused-argument symbol_size = symbol.get("size", 0) section = sections.get(symbol.get("section", ""), {}) - if _is_ram_section(section): + if not section: + continue + if section.get("in_ram", False): files[file_path]["ram_size"] += symbol_size - if _is_flash_section(section): + if section.get("in_flash", False): files[file_path]["flash_size"] += symbol_size files[file_path]["symbols"].append(symbol) @@ -250,5 +257,10 @@ def exists(_): def generate(env): + env.AddMethod(pioSizeIsRamSection) + env.AddMethod(pioSizeIsFlashSection) + env.AddMethod(pioSizeCalculateFirmwareSize) + env.AddMethod(pioSizeDetermineSection) + env.AddMethod(pioSizeIsValidSymbol) env.AddMethod(DumpSizeData) return env diff --git a/platformio/commands/upgrade.py b/platformio/commands/upgrade.py index 9e4d61d2eb..3fb611eaa6 100644 --- a/platformio/commands/upgrade.py +++ b/platformio/commands/upgrade.py @@ -18,7 +18,7 @@ import click -from platformio import VERSION, __version__, app, exception +from platformio import VERSION, __install_requires__, __version__, app, exception from platformio.http import fetch_remote_content from platformio.package.manager.core import update_core_packages from platformio.proc import get_pythonexe_path @@ -33,9 +33,14 @@ @click.command("upgrade", short_help="Upgrade PlatformIO Core to the latest version") @click.option("--dev", is_flag=True, help="Use development branch") +@click.option("--only-dependencies", is_flag=True) @click.option("--verbose", "-v", is_flag=True) -def cli(dev, verbose): +def cli(dev, only_dependencies, verbose): + if only_dependencies: + return upgrade_pypi_dependencies(verbose) + update_core_packages() + if not dev and __version__ == get_latest_version(): return click.secho( "You're up-to-date!\nPlatformIO %s is currently the " @@ -50,11 +55,21 @@ def cli(dev, verbose): pkg_spec = DEVELOP_ZIP_URL if to_develop else "platformio" try: + # PIO Core subprocess.run( [python_exe, "-m", "pip", "install", "--upgrade", pkg_spec], check=True, stdout=subprocess.PIPE if not verbose else None, ) + + # PyPI dependencies + subprocess.run( + [python_exe, "-m", "platformio", "upgrade", "--only-dependencies"], + check=False, + stdout=subprocess.PIPE, + ) + + # Check version output = subprocess.run( [python_exe, "-m", "platformio", "--version"], check=True, @@ -87,9 +102,20 @@ def cli(dev, verbose): return True -def get_pkg_spec(to_develop): - if to_develop: - return +def upgrade_pypi_dependencies(verbose): + subprocess.run( + [ + get_pythonexe_path(), + "-m", + "pip", + "install", + "--upgrade", + "pip", + *__install_requires__, + ], + check=True, + stdout=subprocess.PIPE if not verbose else None, + ) def get_latest_version(): diff --git a/platformio/debug/cli.py b/platformio/debug/cli.py index 12d6004af4..5c9375aec0 100644 --- a/platformio/debug/cli.py +++ b/platformio/debug/cli.py @@ -109,9 +109,7 @@ def cli( def _configure(ctx, project_config, env_name, load_mode, verbose, __unprocessed): - platform = PlatformFactory.new( - project_config.get(f"env:{env_name}", "platform"), autoinstall=True - ) + platform = PlatformFactory.from_env(env_name, autoinstall=True) debug_config = DebugConfigFactory.new( platform, project_config, diff --git a/platformio/home/rpc/handlers/project.py b/platformio/home/rpc/handlers/project.py index 65d05063a0..90b3ab78fe 100644 --- a/platformio/home/rpc/handlers/project.py +++ b/platformio/home/rpc/handlers/project.py @@ -25,6 +25,7 @@ from platformio.home.rpc.handlers.base import BaseRPCHandler from platformio.home.rpc.handlers.piocore import PIOCoreRPC from platformio.package.manager.platform import PlatformPackageManager +from platformio.platform.factory import PlatformFactory from platformio.project.config import ProjectConfig from platformio.project.exception import ProjectError from platformio.project.helpers import get_project_dir, is_platformio_project @@ -37,8 +38,12 @@ class ProjectRPC(BaseRPCHandler): def config_call(init_kwargs, method, *args): assert isinstance(init_kwargs, dict) assert "path" in init_kwargs - project_dir = get_project_dir() - if os.path.isfile(init_kwargs["path"]): + if os.path.isdir(init_kwargs["path"]): + project_dir = init_kwargs["path"] + init_kwargs["path"] = os.path.join(init_kwargs["path"], "platformio.ini") + elif os.path.isfile(init_kwargs["path"]): + project_dir = get_project_dir() + else: project_dir = os.path.dirname(init_kwargs["path"]) with fs.cd(project_dir): return getattr(ProjectConfig(**init_kwargs), method)(*args) @@ -335,3 +340,47 @@ async def _pre_init_example(self, configuration, project_dir): encoding="utf-8", ) return [] + + @staticmethod + 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()) + board_id = config.get(f"env:{env}", "board", None) + + # frameworks + frameworks = [] + for name in config.get(f"env:{env}", "framework", []): + if name not in platform.frameworks: + continue + f_pkg_name = platform.frameworks[name].get("package") + if not f_pkg_name: + continue + f_pkg = platform.get_package(f_pkg_name) + if not f_pkg: + continue + f_manifest = platform.pm.load_manifest(f_pkg) + frameworks.append( + dict( + name=name, + title=f_manifest.get("title"), + version=str(f_pkg.metadata.version), + ) + ) + + return dict( + platform=dict( + ownername=platform_pkg.metadata.spec.owner + if platform_pkg.metadata.spec + else None, + name=platform.name, + title=platform.title, + version=str(platform_pkg.metadata.version), + ), + board=platform.board_config(board_id).get_brief_data() + if board_id + else None, + frameworks=frameworks or None, + ) diff --git a/platformio/package/commands/exec.py b/platformio/package/commands/exec.py index fc100f1901..41386d5e4d 100644 --- a/platformio/package/commands/exec.py +++ b/platformio/package/commands/exec.py @@ -20,7 +20,7 @@ from platformio.compat import IS_MACOS, IS_WINDOWS from platformio.exception import ReturnErrorCode, UserSideException from platformio.package.manager.tool import ToolPackageManager -from platformio.proc import get_pythonexe_path +from platformio.proc import get_pythonexe_path, where_is_program @click.command("exec", short_help="Run command from package tool") @@ -52,9 +52,13 @@ def package_exec_cmd(obj, package, call, args): inject_pkg_to_environ(pkg) os.environ["PIO_PYTHON_EXE"] = get_pythonexe_path() + # inject current python interpreter on Windows - if IS_WINDOWS and args and args[0].endswith(".py"): + if args[0].endswith(".py"): args = [os.environ["PIO_PYTHON_EXE"]] + list(args) + if not os.path.exists(args[1]): + args[1] = where_is_program(args[1]) + result = None try: run_options = dict(shell=call is not None, env=os.environ) diff --git a/platformio/package/commands/install.py b/platformio/package/commands/install.py index e3eb05aa99..82c377d024 100644 --- a/platformio/package/commands/install.py +++ b/platformio/package/commands/install.py @@ -206,7 +206,7 @@ def _install_project_env_libraries(project_env, options): config = ProjectConfig.get_instance() compatibility_qualifiers = {} - if config.get(f"env:{project_env}", "platform"): + if config.get(f"env:{project_env}", "platform", None): try: p = PlatformFactory.new(config.get(f"env:{project_env}", "platform")) compatibility_qualifiers["platforms"] = [p.name] diff --git a/platformio/package/commands/list.py b/platformio/package/commands/list.py index 9d5fee4046..dd19973a47 100644 --- a/platformio/package/commands/list.py +++ b/platformio/package/commands/list.py @@ -22,6 +22,7 @@ from platformio.package.manager.platform import PlatformPackageManager from platformio.package.manager.tool import ToolPackageManager from platformio.package.meta import PackageItem, PackageSpec +from platformio.platform.exception import UnknownPlatform from platformio.platform.factory import PlatformFactory from platformio.project.config import ProjectConfig @@ -187,20 +188,20 @@ def list_project_packages(options): def print_project_env_platform_packages(project_env, options): - config = ProjectConfig.get_instance() - platform = config.get(f"env:{project_env}", "platform") - if not platform: - return None - pkg = PlatformPackageManager().get_package(platform) - if not pkg: + try: + p = PlatformFactory.from_env(project_env) + except UnknownPlatform: return None click.echo( "Platform %s" - % (humanize_package(pkg, platform, verbose=options.get("verbose"))) + % ( + humanize_package( + PlatformPackageManager().get_package(p.get_dir()), + p.config.get(f"env:{project_env}", "platform"), + verbose=options.get("verbose"), + ) + ) ) - p = PlatformFactory.new(pkg) - if project_env: - p.configure_project_packages(project_env) print_dependency_tree( p.pm, specs=[p.get_package_spec(name) for name in p.packages], diff --git a/platformio/package/commands/outdated.py b/platformio/package/commands/outdated.py index 18c3783aa1..769c937466 100644 --- a/platformio/package/commands/outdated.py +++ b/platformio/package/commands/outdated.py @@ -62,10 +62,9 @@ def is_outdated(self): ) @click.option("-e", "--environment", "environments", multiple=True) def package_outdated_cmd(project_dir, environments): - candidates = fetch_outdated_candidates( - project_dir, environments, with_progress=True - ) - print_outdated_candidates(candidates) + with fs.cd(project_dir): + candidates = fetch_outdated_candidates(environments, with_progress=True) + print_outdated_candidates(candidates) def print_outdated_candidates(candidates): @@ -126,8 +125,10 @@ def get_candidate_update_color(outdated): return None -def fetch_outdated_candidates(project_dir, environments, with_progress=False): +def fetch_outdated_candidates(environments, with_progress=False): candidates = [] + config = ProjectConfig.get_instance() + config.validate(environments) def _add_candidate(data): new_candidate = OutdatedCandidate( @@ -139,20 +140,16 @@ def _add_candidate(data): return candidates.append(new_candidate) - with fs.cd(project_dir): - config = ProjectConfig.get_instance() - config.validate(environments) - - # platforms - for item in find_platform_candidates(config, environments): - _add_candidate(item) - # platform package dependencies - for dep_item in find_platform_dependency_candidates(item): - _add_candidate(dep_item) + # platforms + for item in find_platform_candidates(config, environments): + _add_candidate(item) + # platform package dependencies + for dep_item in find_platform_dependency_candidates(item["env"]): + _add_candidate(dep_item) - # libraries - for item in find_library_candidates(config, environments): - _add_candidate(item) + # libraries + for item in find_library_candidates(config, environments): + _add_candidate(item) result = [] if not with_progress: @@ -172,7 +169,7 @@ def find_platform_candidates(config, environments): result = [] pm = PlatformPackageManager() for env in config.envs(): - platform = config.get(f"env:{env}", "platform") + platform = config.get(f"env:{env}", "platform", None) if not platform or (environments and env not in environments): continue spec = PackageSpec(platform) @@ -183,14 +180,13 @@ def find_platform_candidates(config, environments): return result -def find_platform_dependency_candidates(platform_candidate): +def find_platform_dependency_candidates(env): result = [] - p = PlatformFactory.new(platform_candidate["spec"]) - p.configure_project_packages(platform_candidate["env"]) + p = PlatformFactory.from_env(env) for pkg in p.get_installed_packages(): result.append( dict( - env=platform_candidate["env"], + env=env, pm=p.pm, pkg=pkg, spec=p.get_package_spec(pkg.metadata.name), diff --git a/platformio/package/manager/base.py b/platformio/package/manager/base.py index c4d8d5bd02..f197ea120d 100644 --- a/platformio/package/manager/base.py +++ b/platformio/package/manager/base.py @@ -35,7 +35,7 @@ from platformio.package.manifest.parser import ManifestParserFactory from platformio.package.meta import ( PackageItem, - PackageMetaData, + PackageMetadata, PackageSpec, PackageType, ) @@ -199,7 +199,7 @@ def generate_rand_version(): def build_metadata(self, pkg_dir, spec, vcs_revision=None): manifest = self.load_manifest(pkg_dir) - metadata = PackageMetaData( + metadata = PackageMetadata( type=self.pkg_type, name=manifest.get("name"), version=manifest.get("version"), diff --git a/platformio/package/meta.py b/platformio/package/meta.py index 36578a3726..b1c491d784 100644 --- a/platformio/package/meta.py +++ b/platformio/package/meta.py @@ -401,7 +401,7 @@ def _parse_name_from_uri(uri): return name -class PackageMetaData: +class PackageMetadata: def __init__( # pylint: disable=redefined-builtin self, type, name, version, spec=None ): @@ -416,7 +416,7 @@ def __init__( # pylint: disable=redefined-builtin def __repr__(self): return ( - "PackageMetaData base.PlatformBase: _instance = platform_cls(os.path.join(platform_dir, "platform.json")) assert isinstance(_instance, base.PlatformBase) return _instance + + @classmethod + def from_env(cls, env, targets=None, autoinstall=False): + config = ProjectConfig.get_instance() + spec = config.get(f"env:{env}", "platform", None) + if not spec: + raise UndefinedEnvPlatformError(env) + p = cls.new(spec, autoinstall=autoinstall) + p.project_env = env + p.configure_project_packages(env, targets) + return p diff --git a/platformio/proc.py b/platformio/proc.py index fb66bc7ffb..acfce4d942 100644 --- a/platformio/proc.py +++ b/platformio/proc.py @@ -185,10 +185,17 @@ def copy_pythonpath_to_osenv(): def where_is_program(program, envpath=None): - env = os.environ + env = os.environ.copy() if envpath: env["PATH"] = envpath + # look up in $PATH + for bin_dir in env.get("PATH", "").split(os.pathsep): + if os.path.isfile(os.path.join(bin_dir, program)): + return os.path.join(bin_dir, program) + if IS_WINDOWS and os.path.isfile(os.path.join(bin_dir, "%s.exe" % program)): + return os.path.join(bin_dir, "%s.exe" % program) + # try OS's built-in commands try: result = exec_command(["where" if IS_WINDOWS else "which", program], env=env) @@ -197,13 +204,6 @@ def where_is_program(program, envpath=None): except OSError: pass - # look up in $PATH - for bin_dir in env.get("PATH", "").split(os.pathsep): - if os.path.isfile(os.path.join(bin_dir, program)): - return os.path.join(bin_dir, program) - if os.path.isfile(os.path.join(bin_dir, "%s.exe" % program)): - return os.path.join(bin_dir, "%s.exe" % program) - return program diff --git a/platformio/project/commands/init.py b/platformio/project/commands/init.py index 098c31a57f..51ae46a48d 100644 --- a/platformio/project/commands/init.py +++ b/platformio/project/commands/init.py @@ -26,6 +26,7 @@ from platformio.platform.exception import UnknownBoard from platformio.platform.factory import PlatformFactory from platformio.project.config import ProjectConfig +from platformio.project.exception import UndefinedEnvPlatformError from platformio.project.helpers import is_platformio_project from platformio.project.integration.generator import ProjectGenerator from platformio.project.options import ProjectOptions @@ -366,13 +367,10 @@ def update_project_env(environment, extra_project_options=None): def init_sample_code(config, environment): - platform_spec = config.get(f"env:{environment}", "platform", None) - if not platform_spec: - return None - p = PlatformFactory.new(platform_spec) try: + p = PlatformFactory.from_env(environment) return p.generate_sample_code(config, environment) - except NotImplementedError: + except (NotImplementedError, UndefinedEnvPlatformError): pass framework = config.get(f"env:{environment}", "framework", None) diff --git a/platformio/project/integration/tpls/clion/.gitignore.tpl b/platformio/project/integration/tpls/clion/.gitignore.tpl index 3fe18ad479..03f4a3c192 100644 --- a/platformio/project/integration/tpls/clion/.gitignore.tpl +++ b/platformio/project/integration/tpls/clion/.gitignore.tpl @@ -1,3 +1 @@ .pio -CMakeListsPrivate.txt -cmake-build-*/ diff --git a/platformio/project/integration/tpls/clion/CMakeLists.txt.tpl b/platformio/project/integration/tpls/clion/CMakeLists.txt.tpl deleted file mode 100644 index ca3099eefc..0000000000 --- a/platformio/project/integration/tpls/clion/CMakeLists.txt.tpl +++ /dev/null @@ -1,33 +0,0 @@ -# !!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE -# https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags -# -# If you need to override existing CMake configuration or add extra, -# please create `CMakeListsUser.txt` in the root of project. -# The `CMakeListsUser.txt` will not be overwritten by PlatformIO. - -cmake_minimum_required(VERSION 3.13) -set(CMAKE_SYSTEM_NAME Generic) -set(CMAKE_C_COMPILER_WORKS 1) -set(CMAKE_CXX_COMPILER_WORKS 1) - -project("{{project_name}}" C CXX) - -include(CMakeListsPrivate.txt) - -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/CMakeListsUser.txt) -include(CMakeListsUser.txt) -endif() - -add_custom_target( - Production ALL - COMMAND platformio -c clion run "$<$>:-e${CMAKE_BUILD_TYPE}>" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) - -add_custom_target( - Debug ALL - COMMAND platformio -c clion debug "$<$>:-e${CMAKE_BUILD_TYPE}>" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) - -add_executable(Z_DUMMY_TARGET ${SRC_LIST}) diff --git a/platformio/project/integration/tpls/clion/CMakeListsPrivate.txt.tpl b/platformio/project/integration/tpls/clion/CMakeListsPrivate.txt.tpl deleted file mode 100644 index c65848f6b9..0000000000 --- a/platformio/project/integration/tpls/clion/CMakeListsPrivate.txt.tpl +++ /dev/null @@ -1,127 +0,0 @@ -# !!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE -# https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags -# -# If you need to override existing CMake configuration or add extra, -# please create `CMakeListsUser.txt` in the root of project. -# The `CMakeListsUser.txt` will not be overwritten by PlatformIO. - -% import os -% import re -% -% from platformio.compat import shlex_join -% from platformio.project.helpers import load_build_metadata -% -% def _normalize_path(path): -% if project_dir in path: -% path = path.replace(project_dir, "${CMAKE_CURRENT_LIST_DIR}") -% elif user_home_dir in path: -% if "windows" in systype: -% path = path.replace(user_home_dir, "${ENV_HOME_PATH}") -% else: -% path = path.replace(user_home_dir, "$ENV{HOME}") -% end -% end -% return path -% end -% -% def _fix_lib_dirs(lib_dirs): -% result = [] -% for lib_dir in lib_dirs: -% if not os.path.isabs(lib_dir): -% lib_dir = os.path.join(project_dir, lib_dir) -% end -% result.append(to_unix_path(os.path.normpath(lib_dir))) -% end -% return result -% end -% -% def _escape(text): -% return to_unix_path(text).replace('"', '\\"') -% end -% -% def _get_lib_dirs(envname): -% env_libdeps_dir = os.path.join(config.get("platformio", "libdeps_dir"), envname) -% env_lib_extra_dirs = config.get("env:" + envname, "lib_extra_dirs", []) -% return _fix_lib_dirs([env_libdeps_dir] + env_lib_extra_dirs) -% end -% -% envs = config.envs() - - -% if len(envs) > 1: -set(CMAKE_CONFIGURATION_TYPES "{{ ";".join(envs) }};" CACHE STRING "Build Types reflect PlatformIO Environments" FORCE) -% else: -set(CMAKE_CONFIGURATION_TYPES "{{ env_name }}" CACHE STRING "Build Types reflect PlatformIO Environments" FORCE) -% end - -# Convert "Home Directory" that may contain unescaped backslashes on Windows -% if "windows" in systype: -file(TO_CMAKE_PATH $ENV{HOMEDRIVE}$ENV{HOMEPATH} ENV_HOME_PATH) -% end - -% if svd_path: -set(CLION_SVD_FILE_PATH "{{ _normalize_path(svd_path) }}" CACHE FILEPATH "Peripheral Registers Definitions File" FORCE) -% end - -SET(CMAKE_C_COMPILER "{{ _normalize_path(cc_path) }}") -SET(CMAKE_CXX_COMPILER "{{ _normalize_path(cxx_path) }}") -SET(CMAKE_CXX_FLAGS {{ _normalize_path(to_unix_path(shlex_join(cxx_flags))) }}) -SET(CMAKE_C_FLAGS {{ _normalize_path(to_unix_path(shlex_join(cc_flags))) }}) - -% cc_stds = [arg for arg in cc_flags if arg.startswith("-std=")] -% cxx_stds = [arg for arg in cxx_flags if arg.startswith("-std=")] -% if cc_stds: -SET(CMAKE_C_STANDARD {{ cc_stds[-1][-2:] }}) -% end -% if cxx_stds: -set(CMAKE_CXX_STANDARD {{ cxx_stds[-1][-2:] }}) -% end - -if (CMAKE_BUILD_TYPE MATCHES "{{ env_name }}") -% for define in defines: - add_definitions(-D{{!re.sub(r"([\"\(\)\ #])", r"\\\1", define)}}) -% end - -% for include in filter_includes(includes): - include_directories("{{ _normalize_path(include) }}") -% end - - FILE(GLOB_RECURSE EXTRA_LIB_SOURCES -% for dir in _get_lib_dirs(env_name): - {{ _normalize_path(dir) + "/*.*" }} -% end - ) -endif() - -% leftover_envs = list(set(envs) ^ set([env_name])) -% -% ide_data = {} -% if leftover_envs: -% ide_data = load_build_metadata(project_dir, leftover_envs) -% end -% -% for env, data in ide_data.items(): -if (CMAKE_BUILD_TYPE MATCHES "{{ env }}") -% for define in data["defines"]: - add_definitions(-D{{!re.sub(r"([\"\(\)\ #])", r"\\\1", define)}}) -% end - -% for include in filter_includes(data["includes"]): - include_directories("{{ _normalize_path(to_unix_path(include)) }}") -% end - - FILE(GLOB_RECURSE EXTRA_LIB_SOURCES -% for dir in _get_lib_dirs(env): - {{ _normalize_path(dir) + "/*.*" }} -% end - ) -endif() -% end - -FILE(GLOB_RECURSE SRC_LIST -% for path in (project_src_dir, project_lib_dir, project_test_dir): - {{ _normalize_path(path) + "/*.*" }} -% end -) - -list(APPEND SRC_LIST ${EXTRA_LIB_SOURCES}) diff --git a/platformio/run/cli.py b/platformio/run/cli.py index dc3eb2ee51..1ed84a48b0 100644 --- a/platformio/run/cli.py +++ b/platformio/run/cli.py @@ -207,7 +207,7 @@ def process_env( verbose, ).process() - if "monitor" in targets and "nobuild" not in targets: + if result["succeeded"] and "monitor" in targets and "nobuild" not in targets: ctx.invoke( device_monitor_cmd, port=monitor_port, diff --git a/platformio/run/processor.py b/platformio/run/processor.py index 329c4bf6d0..051e35afc2 100644 --- a/platformio/run/processor.py +++ b/platformio/run/processor.py @@ -72,8 +72,8 @@ def process(self): # pre-clean if is_clean: - result = PlatformFactory.new( - self.options["platform"], autoinstall=True + result = PlatformFactory.from_env( + self.name, targets=self.targets, autoinstall=True ).run(build_vars, self.targets, self.silent, self.verbose, self.jobs) if not build_targets: return result["returncode"] == 0 @@ -85,7 +85,7 @@ def process(self): "piotest_running_name": build_vars.get("piotest_running_name"), }, ) - result = PlatformFactory.new(self.options["platform"], autoinstall=True).run( - build_vars, build_targets, self.silent, self.verbose, self.jobs - ) + result = PlatformFactory.from_env( + self.name, targets=build_targets, autoinstall=True + ).run(build_vars, build_targets, self.silent, self.verbose, self.jobs) return result["returncode"] == 0 diff --git a/platformio/telemetry.py b/platformio/telemetry.py index 820b1507a6..5b0734c9a2 100644 --- a/platformio/telemetry.py +++ b/platformio/telemetry.py @@ -13,7 +13,6 @@ # limitations under the License. import atexit -import hashlib import os import queue import re @@ -27,9 +26,8 @@ from platformio import __title__, __version__, app, exception, fs, util from platformio.cli import PlatformioCLI -from platformio.compat import hashlib_encode_data from platformio.debug.config.base import DebugConfigBase -from platformio.http import HTTPSession, ensure_internet_on +from platformio.http import HTTPSession from platformio.proc import is_ci KEEP_MAX_REPORTS = 100 @@ -135,7 +133,7 @@ def _commit_events(self, events): # print("_commit_payload", payload) try: r = self._http_session.post( - "https://telemetry.platformio.org/collect", + "https://collector.platformio.org/collect", json=payload, timeout=(2, 5), # connect, read ) @@ -220,7 +218,7 @@ def dump_project_env_params(config, env, platform): for option in non_sensitive_data if config.has_option(section, option) } - params["pid"] = hashlib.sha1(hashlib_encode_data(config.path)).hexdigest() + params["pid"] = app.get_project_id(os.path.dirname(config.path)) params["platform_name"] = platform.name params["platform_version"] = platform.version return params @@ -365,8 +363,6 @@ def postpone_events(events): def process_postponed_logs(): - if not ensure_internet_on(): - return None events = load_postponed_events() if not events: return None @@ -380,4 +376,5 @@ def process_postponed_logs(): timestamp=event["timestamp"], instant_sending=False, ) + telemetry.send() return True diff --git a/platformio/test/runners/base.py b/platformio/test/runners/base.py index 845a8c3771..e8919f84df 100644 --- a/platformio/test/runners/base.py +++ b/platformio/test/runners/base.py @@ -62,8 +62,8 @@ def __init__(self, test_suite, project_config, options=None): self.test_suite = test_suite self.options = options self.project_config = project_config - self.platform = PlatformFactory.new( - self.project_config.get(f"env:{self.test_suite.env_name}", "platform"), + self.platform = PlatformFactory.from_env( + self.test_suite.env_name, autoinstall=True, ) self.cmd_ctx = None diff --git a/scripts/docspregen.py b/scripts/docspregen.py index 09dd6777ec..a4d56c0382 100644 --- a/scripts/docspregen.py +++ b/scripts/docspregen.py @@ -51,6 +51,12 @@ "or physical experiences." ), }, + "cmsis": { + "title": "CMSIS", + "description": ( + "Vendor-independent hardware abstraction layer for the Cortex-M processor series" + ), + }, "freertos": { "title": "FreeRTOS", "description": ( diff --git a/scripts/get-platformio.py b/scripts/get-platformio.py deleted file mode 100644 index 9d99ea9771..0000000000 --- a/scripts/get-platformio.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright (c) 2014-present PlatformIO -# -# 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. - -import tempfile -import io -import sys -import subprocess - -MAIN_SCRIPT_URL = "https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py" - - -def download_with_requests(url, dst): - import requests - - resp = requests.get(url, stream=True) - itercontent = resp.iter_content(chunk_size=io.DEFAULT_BUFFER_SIZE) - with open(dst, "wb") as fp: - for chunk in itercontent: - fp.write(chunk) - return dst - - -def download_with_urllib3(url, dst): - import urllib3 - - http = urllib3.PoolManager() - r = http.request("GET", url, preload_content=False) - - with open(dst, "wb") as out: - while True: - data = r.read(io.DEFAULT_BUFFER_SIZE) - if not data: - break - out.write(data) - - r.release_conn() - return dst - - -def download_with_urllib(url, dst): - if sys.version_info[0] == 3: - from urllib.request import urlopen - else: - from urllib import urlopen - - response = urlopen(url) - CHUNK = 16 * 1024 - with open(dst, "wb") as f: - while True: - chunk = response.read(CHUNK) - if not chunk: - break - f.write(chunk) - - return dst - - -def download_with_curl(url, dst): - subprocess.check_output(["curl", "-o", dst, url]) - return dst - - -def download_with_wget(url, dst): - subprocess.check_output(["wget", "-O", dst, url]) - return dst - - -def download_file(url, dst): - methods = [ - download_with_requests, - download_with_urllib3, - download_with_urllib, - download_with_curl, - download_with_wget, - ] - for method in methods: - try: - method(url, dst) - return dst - except: - pass - raise Exception("Could not download file '%s' to '%s' " % (url, dst)) - - -def main(): - with tempfile.NamedTemporaryFile() as tmp_file: - dst = download_file(MAIN_SCRIPT_URL, str(tmp_file.name)) - command = [sys.executable, dst] - command.extend(sys.argv[1:]) - subprocess.check_call(command) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/setup.py b/setup.py index f37da675a6..46716cc507 100644 --- a/setup.py +++ b/setup.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import platform from setuptools import find_packages, setup from platformio import ( @@ -22,48 +23,12 @@ __title__, __url__, __version__, + __install_requires__, ) -env_marker_below_37 = "python_version < '3.7'" -env_marker_gte_37 = "python_version >= '3.7'" - -minimal_requirements = [ - "bottle==0.12.*", - "click==8.0.4; " + env_marker_below_37, - "click==8.1.*; " + env_marker_gte_37, - "colorama", - "marshmallow==3.14.1; " + env_marker_below_37, - "marshmallow==3.19.*; " + env_marker_gte_37, - "pyelftools==0.29", - "pyserial==3.5.*", # keep in sync "device/monitor/terminal.py" - "requests==2.*", - "semantic_version==2.10.*", - "tabulate==0.*", -] - -home_requirements = [ - "aiofiles>=0.8.0", - "ajsonrpc==1.2.*", - "starlette==0.19.1; " + env_marker_below_37, - "starlette==0.28.*; " + env_marker_gte_37, - "uvicorn==0.16.0; " + env_marker_below_37, - "uvicorn==0.22.*; " + env_marker_gte_37, - "wsproto==1.0.0; " + env_marker_below_37, - "wsproto==1.2.*; " + env_marker_gte_37, -] - -# issue 4614: urllib3 v2.0 only supports OpenSSL 1.1.1+ -try: - import ssl - - if ssl.OPENSSL_VERSION.startswith("OpenSSL ") and ssl.OPENSSL_VERSION_INFO < ( - 1, - 1, - 1, - ): - minimal_requirements.append("urllib3<2") -except ImportError: - pass +# issue #4702; Broken "requests/charset_normalizer" on macOS ARM +if platform.system() == "Darwin" and "arm" in platform.machine().lower(): + __install_requires__.append("chardet>=3.0.2,<4") setup( @@ -75,7 +40,7 @@ author_email=__email__, url=__url__, license=__license__, - install_requires=minimal_requirements + home_requirements, + install_requires=__install_requires__, python_requires=">=3.6", packages=find_packages(include=["platformio", "platformio.*"]), package_data={ diff --git a/tests/commands/test_check.py b/tests/commands/test_check.py index cb6f77772c..5403ee0fa7 100644 --- a/tests/commands/test_check.py +++ b/tests/commands/test_check.py @@ -69,7 +69,7 @@ EXPECTED_ERRORS = 5 EXPECTED_WARNINGS = 1 -EXPECTED_STYLE = 2 +EXPECTED_STYLE = 4 EXPECTED_DEFECTS = EXPECTED_ERRORS + EXPECTED_WARNINGS + EXPECTED_STYLE @@ -345,7 +345,10 @@ def test_check_individual_flags_passed(clirunner, validate_cliresult, tmpdir): assert pvs_flags_found -def test_check_cppcheck_misra_addon(clirunner, validate_cliresult, check_dir): +def test_check_cppcheck_misra_addon(clirunner, validate_cliresult, tmpdir_factory): + check_dir = tmpdir_factory.mktemp("project") + check_dir.join("platformio.ini").write(DEFAULT_CONFIG) + check_dir.mkdir("src").join("main.c").write(TEST_CODE) check_dir.join("misra.json").write( """ { @@ -509,15 +512,18 @@ def test_check_pvs_studio_fails_broken_license(clirunner, tmpdir): assert "license information is incorrect" in verbose_result.output.lower() -def test_check_embedded_platform_all_tools(clirunner, validate_cliresult, tmpdir): - config = """ +@pytest.mark.parametrize("framework", ["arduino", "stm32cube", "zephyr"]) +@pytest.mark.parametrize("check_tool", ["cppcheck", "clangtidy", "pvs-studio"]) +def test_check_embedded_platform_all_tools( + clirunner, validate_cliresult, tmpdir, framework, check_tool +): + config = f""" [env:test] platform = ststm32 board = nucleo_f401re -framework = %s -check_tool = %s +framework = {framework} +check_tool = {check_tool} """ - # tmpdir.join("platformio.ini").write(config) tmpdir.mkdir("src").join("main.c").write( PVS_STUDIO_FREE_LICENSE_HEADER + """ @@ -534,20 +540,11 @@ def test_check_embedded_platform_all_tools(clirunner, validate_cliresult, tmpdir """ ) - for framework in ( - "arduino", - "stm32cube", - "zephyr", - ): - for tool in ("cppcheck", "clangtidy", "pvs-studio"): - tmpdir.join("platformio.ini").write(config % (framework, tool)) - result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir)]) - validate_cliresult(result) - defects = sum(count_defects(result.output)) - assert defects > 0, "Failed %s with %s" % ( - framework, - tool, - ) + tmpdir.join("platformio.ini").write(config) + result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir)]) + validate_cliresult(result) + defects = sum(count_defects(result.output)) + assert defects > 0, "Not defects were found!" def test_check_skip_includes_from_packages(clirunner, validate_cliresult, tmpdir): diff --git a/tests/package/test_meta.py b/tests/package/test_meta.py index f7eae748e2..fc27453091 100644 --- a/tests/package/test_meta.py +++ b/tests/package/test_meta.py @@ -19,7 +19,7 @@ from platformio.package.meta import ( PackageCompatibility, - PackageMetaData, + PackageMetadata, PackageOutdatedResult, PackageSpec, PackageType, @@ -229,7 +229,7 @@ def test_spec_as_dependency(): def test_metadata_as_dict(): - metadata = PackageMetaData(PackageType.LIBRARY, "foo", "1.2.3") + metadata = PackageMetadata(PackageType.LIBRARY, "foo", "1.2.3") # test setter metadata.version = "0.1.2+12345" assert metadata.version == semantic_version.Version("0.1.2+12345") @@ -244,7 +244,7 @@ def test_metadata_as_dict(): ) assert not jsondiff.diff( - PackageMetaData( + PackageMetadata( PackageType.TOOL, "toolchain", "2.0.5", @@ -267,7 +267,7 @@ def test_metadata_as_dict(): def test_metadata_dump(tmpdir_factory): pkg_dir = tmpdir_factory.mktemp("package") - metadata = PackageMetaData( + metadata = PackageMetadata( PackageType.TOOL, "toolchain", "2.0.5", @@ -297,9 +297,9 @@ def test_metadata_load(tmpdir_factory): pkg_dir = tmpdir_factory.mktemp("package") dst = pkg_dir.join(".piopm") dst.write(contents) - metadata = PackageMetaData.load(str(dst)) + metadata = PackageMetadata.load(str(dst)) assert metadata.version == semantic_version.Version("0.1.3") - assert metadata == PackageMetaData( + assert metadata == PackageMetadata( PackageType.PLATFORM, "foo", "0.1.3", @@ -307,11 +307,11 @@ def test_metadata_load(tmpdir_factory): ) piopm_path = pkg_dir.join(".piopm") - metadata = PackageMetaData( + metadata = PackageMetadata( PackageType.LIBRARY, "mylib", version="1.2.3", spec=PackageSpec("mylib") ) metadata.dump(str(piopm_path)) - restored_metadata = PackageMetaData.load(str(piopm_path)) + restored_metadata = PackageMetadata.load(str(piopm_path)) assert metadata == restored_metadata diff --git a/tox.ini b/tox.ini index f8a15f3bc5..2eda9b906c 100644 --- a/tox.ini +++ b/tox.ini @@ -34,6 +34,7 @@ deps = jsondiff commands = {envpython} --version + pio system info [testenv:lint] commands =