From 1a303113e98c4b887230d321424c8552a8a15a4b Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 4 Feb 2026 16:10:37 +0100 Subject: [PATCH] pioarduino v6.1.19 * remove telemetry * no full git clone * add intelhex as required * no core packages * add `rich_click` as pip dependencies * remove advertisings * add intelhex as required * install scons and Pio home from github * replace "get_core_package_dir" for piohome and pioremote --- .github/workflows/core.yml | 14 +- .github/workflows/deployment.yml | 45 -- .github/workflows/docs.yml | 109 --- .github/workflows/examples.yml | 73 -- .github/workflows/projects.yml | 51 +- .gitignore | 2 + README.rst | 8 +- platformio/__init__.py | 19 +- platformio/__main__.py | 2 - platformio/app.py | 7 - platformio/builder/main.py | 5 +- platformio/builder/tools/piobuild.py | 23 +- platformio/builder/tools/piolib.py | 1 + platformio/builder/tools/piomaxlen.py | 2 +- platformio/check/tools/clangtidy.py | 9 +- platformio/check/tools/cppcheck.py | 7 +- platformio/check/tools/pvsstudio.py | 13 +- platformio/debug/process/gdb.py | 6 - platformio/dependencies.py | 17 +- platformio/device/finder.py | 12 +- platformio/home/cli.py | 17 +- platformio/home/run.py | 5 +- platformio/maintenance.py | 140 +--- platformio/package/vcsclient.py | 6 +- platformio/platform/_run.py | 3 +- platformio/project/commands/init.py | 4 + platformio/project/helpers.py | 86 ++- .../tpls/vscode/.vscode/extensions.json.tpl | 4 +- platformio/remote/cli.py | 5 +- platformio/remote/client/base.py | 4 +- platformio/telemetry.py | 380 ---------- setup.py | 2 +- tests/commands/pkg/test_install.py | 242 ------- tests/commands/pkg/test_list.py | 122 ---- tests/commands/pkg/test_uninstall.py | 276 -------- tests/commands/pkg/test_update.py | 169 ----- tests/commands/test_check.py | 664 +----------------- tests/commands/test_run.py | 251 +++---- tests/package/test_manager.py | 107 ++- tests/package/test_manifest.py | 213 ------ tox.ini | 18 - 41 files changed, 374 insertions(+), 2769 deletions(-) delete mode 100644 .github/workflows/deployment.yml delete mode 100644 .github/workflows/docs.yml delete mode 100644 .github/workflows/examples.yml delete mode 100644 platformio/telemetry.py diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index 965a574c..d76c5298 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -37,17 +37,11 @@ jobs: run: | tox -e py + - name: Python Lint + run: | + tox -e lint + - name: Integration Tests if: ${{ matrix.python-version == '3.11' }} run: | tox -e testcore - - - name: Slack Notification - uses: homoluctus/slatify@master - if: failure() - with: - type: ${{ job.status }} - job_name: '*Core*' - commit: true - url: ${{ secrets.SLACK_BUILD_WEBHOOK }} - token: ${{ secrets.SLACK_GITHUB_TOKEN }} diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml deleted file mode 100644 index 032d1d5a..00000000 --- a/.github/workflows/deployment.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Deployment - -on: - push: - branches: - - "master" - - "release/**" - -jobs: - deployment: - runs-on: ubuntu-latest - environment: production - - steps: - - uses: actions/checkout@v6 - with: - submodules: "recursive" - - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: "3.11" - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install tox build - - - name: Deployment Tests - env: - TEST_EMAIL_LOGIN: ${{ secrets.TEST_EMAIL_LOGIN }} - TEST_EMAIL_PASSWORD: ${{ secrets.TEST_EMAIL_PASSWORD }} - TEST_EMAIL_IMAP_SERVER: ${{ secrets.TEST_EMAIL_IMAP_SERVER }} - run: | - tox -e testcore - - - name: Build Python distributions - run: python -m build - - - name: Publish package to PyPI - if: ${{ github.ref == 'refs/heads/master' }} - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index bb359ab7..00000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,109 +0,0 @@ -name: Docs - -on: [push, pull_request] - -jobs: - build: - name: Build Docs - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - submodules: "recursive" - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: "3.11" - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install tox - - - name: Build docs - run: | - tox -e docs - - - name: Slack Notification - uses: homoluctus/slatify@master - if: failure() - with: - type: ${{ job.status }} - job_name: '*Docs*' - commit: true - url: ${{ secrets.SLACK_BUILD_WEBHOOK }} - token: ${{ secrets.SLACK_GITHUB_TOKEN }} - - - name: Preserve Docs - if: ${{ github.event_name == 'push' }} - run: | - tar -czvf docs.tar.gz -C docs/_build html rtdpage - - - name: Save artifact - if: ${{ github.event_name == 'push' }} - uses: actions/upload-artifact@v4 - with: - name: docs - path: ./docs.tar.gz - - deploy: - name: Deploy Docs - needs: build - runs-on: ubuntu-latest - env: - DOCS_REPO: platformio/platformio-docs - DOCS_DIR: platformio-docs - LATEST_DOCS_DIR: latest-docs - RELEASE_BUILD: ${{ startsWith(github.ref, 'refs/tags/v') }} - if: ${{ github.event_name == 'push' }} - steps: - - name: Download artifact - uses: actions/download-artifact@v4 - with: - name: docs - - name: Unpack artifact - run: | - mkdir ./${{ env.LATEST_DOCS_DIR }} - tar -xzf ./docs.tar.gz -C ./${{ env.LATEST_DOCS_DIR }} - - name: Delete Artifact - uses: geekyeggo/delete-artifact@v5 - with: - name: docs - - name: Select Docs type - id: get-destination-dir - run: | - if [[ ${{ env.RELEASE_BUILD }} == true ]]; then - echo "::set-output name=dst_dir::stable" - else - echo "::set-output name=dst_dir::latest" - fi - - name: Checkout latest Docs - continue-on-error: true - uses: actions/checkout@v6 - with: - repository: ${{ env.DOCS_REPO }} - path: ${{ env.DOCS_DIR }} - ref: gh-pages - - name: Synchronize Docs - run: | - rm -rf ${{ env.DOCS_DIR }}/.git - rm -rf ${{ env.DOCS_DIR }}/en/${{ steps.get-destination-dir.outputs.dst_dir }} - mkdir -p ${{ env.DOCS_DIR }}/en/${{ steps.get-destination-dir.outputs.dst_dir }} - cp -rf ${{ env.LATEST_DOCS_DIR }}/html/* ${{ env.DOCS_DIR }}/en/${{ steps.get-destination-dir.outputs.dst_dir }} - if [[ ${{ env.RELEASE_BUILD }} == false ]]; then - rm -rf ${{ env.DOCS_DIR }}/page - mkdir -p ${{ env.DOCS_DIR }}/page - cp -rf ${{ env.LATEST_DOCS_DIR }}/rtdpage/* ${{ env.DOCS_DIR }}/page - fi - - name: Validate Docs - run: | - if [ -z "$(ls -A ${{ env.DOCS_DIR }})" ]; then - echo "Docs folder is empty. Aborting!" - exit 1 - fi - - name: Deploy to Github Pages - uses: peaceiris/actions-gh-pages@v4 - with: - personal_token: ${{ secrets.DEPLOY_GH_DOCS_TOKEN }} - external_repository: ${{ env.DOCS_REPO }} - publish_dir: ./${{ env.DOCS_DIR }} - commit_message: Sync Docs diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml deleted file mode 100644 index c34cb703..00000000 --- a/.github/workflows/examples.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: Examples - -on: [push, pull_request] - - -jobs: - build: - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - runs-on: ${{ matrix.os }} - env: - PIO_INSTALL_DEVPLATFORM_OWNERNAMES: "platformio" - PIO_INSTALL_DEVPLATFORM_NAMES: "aceinna_imu,atmelavr,atmelmegaavr,atmelsam,espressif32,espressif8266,nordicnrf52,raspberrypi,ststm32,teensy" - - steps: - - name: Free Disk Space - uses: endersonmenezes/free-disk-space@v3 - with: - remove_android: true - remove_dotnet: true - remove_haskell: true - # Faster cleanup - remove_packages_one_command: true - rm_cmd: "rmz" - - - uses: actions/checkout@v6 - with: - submodules: "recursive" - - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: "3.11" - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install tox - - - name: Run on Linux - if: startsWith(matrix.os, 'ubuntu') - run: | - # Free space - sudo apt clean - # docker rmi $(docker image ls -aq) - df -h - tox -e testexamples - - - name: Run on macOS - if: startsWith(matrix.os, 'macos') - run: | - df -h - tox -e testexamples - - - name: Run on Windows - if: startsWith(matrix.os, 'windows') - env: - PLATFORMIO_CORE_DIR: C:/pio - PLATFORMIO_WORKSPACE_DIR: C:/pio-workspace/$PROJECT_HASH - run: | - tox -e testexamples - - - name: Slack Notification - uses: homoluctus/slatify@master - if: failure() - with: - type: ${{ job.status }} - job_name: '*Examples*' - commit: true - url: ${{ secrets.SLACK_BUILD_WEBHOOK }} - token: ${{ secrets.SLACK_GITHUB_TOKEN }} diff --git a/.github/workflows/projects.yml b/.github/workflows/projects.yml index f3a4dff9..bd587c6c 100644 --- a/.github/workflows/projects.yml +++ b/.github/workflows/projects.yml @@ -1,6 +1,8 @@ name: Projects -on: [push, pull_request] +on: + workflow_dispatch: # Manually start a workflow + push: jobs: build: @@ -8,49 +10,40 @@ jobs: fail-fast: false matrix: project: - - marlin: - repository: "MarlinFirmware/Marlin" - folder: "Marlin" - config_dir: "Marlin" - env_name: "mega2560" - - smartknob: - repository: "scottbez1/smartknob" - folder: "smartknob" - config_dir: "smartknob" - env_name: "view" - - espurna: - repository: "xoseperez/espurna" - folder: "espurna" - config_dir: "espurna/code" - env_name: "nodemcu-lolin" - - OpenMQTTGateway: - repository: "1technophile/OpenMQTTGateway" - folder: "OpenMQTTGateway" - config_dir: "OpenMQTTGateway" - env_name: "esp32-m5atom-lite" + - PlatformTest: + repository: "Jason2866/platform-test" + folder: "src" + config_dir: "src" + env_name: "esp32-s3" os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 with: submodules: "recursive" - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v6 + uses: actions/setup-python@v5 with: - python-version: 3.11 + python-version: 3.13 + + - name: Install uv + uses: astral-sh/setup-uv@v6 + with: + version: "latest" + enable-cache: false - name: Install PlatformIO - run: pip install -U . + run: uv pip install --system -U . - name: Check out ${{ matrix.project.repository }} - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: submodules: "recursive" repository: ${{ matrix.project.repository }} path: ${{ matrix.project.folder }} - - name: Compile ${{ matrix.project.repository }} - run: pio run -d ${{ matrix.project.config_dir }} -e ${{ matrix.project.env_name }} - + - name: Compile example ${{ matrix.project.repository }} + run: | + pio run -d ${{ matrix.project.config_dir }} -e ${{ matrix.project.env_name }} diff --git a/.gitignore b/.gitignore index ceeaed9a..d1cc451d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ coverage.xml .coverage htmlcov .pytest_cache +.vscode/settings.json +.DS_Store diff --git a/README.rst b/README.rst index df73525e..b2baedcd 100644 --- a/README.rst +++ b/README.rst @@ -82,13 +82,11 @@ Contributing See `contributing guidelines `_. -Telemetry / Privacy Policy --------------------------- +Telemetry +--------- -Share minimal diagnostics and usage information to help us make PlatformIO better. -It is enabled by default. For more information see: +Removed -* `Telemetry Setting `_ License ------- diff --git a/platformio/__init__.py b/platformio/__init__.py index 2890cbb0..13877543 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -15,21 +15,17 @@ VERSION = (6, 1, 19) __version__ = ".".join([str(s) for s in VERSION]) -__title__ = "platformio" +__title__ = "pioarduino core" __description__ = ( - "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." + "pioarduino core is needed to run pioarduino Platform espressif32. " ) -__url__ = "https://platformio.org" +__url__ = "https://github.com/pioarduino" -__author__ = "PlatformIO Labs" -__email__ = "contact@piolabs.com" +__author__ = "PlatformIO Labs and pioarduino" +__email__ = "" __license__ = "Apache Software License" -__copyright__ = "Copyright 2014-present PlatformIO Labs" +__copyright__ = "Copyright 2014-present PlatformIO Labs and pioarduino" __accounts_api__ = "https://api.accounts.platformio.org" __registry_mirror_hosts__ = [ @@ -40,6 +36,5 @@ __pioremote_endpoint__ = "ssl:host=remote.platformio.org:port=4413" __check_internet_hosts__ = [ "185.199.110.153", # Github.com - "88.198.170.159", # platformio.org "github.com", -] + __registry_mirror_hosts__ +] diff --git a/platformio/__main__.py b/platformio/__main__.py index 58cabe8b..3b3430c1 100644 --- a/platformio/__main__.py +++ b/platformio/__main__.py @@ -106,7 +106,6 @@ def main(argv=None): exit_code = int(exc.code) except Exception as exc: # pylint: disable=broad-except if not isinstance(exc, exception.ReturnErrorCode): - maintenance.on_platformio_exception(exc) error_str = f"{exc.__class__.__name__}: " if isinstance(exc, exception.PlatformioException): error_str += str(exc) @@ -131,7 +130,6 @@ An unexpected error occurred. Further steps: click.secho(error_str, fg="red", err=True) exit_code = int(str(exc)) if str(exc).isdigit() else 1 - maintenance.on_platformio_exit() sys.argv = prev_sys_argv return exit_code diff --git a/platformio/app.py b/platformio/app.py index 7d2f1ea9..5bb02d6a 100644 --- a/platformio/app.py +++ b/platformio/app.py @@ -46,10 +46,6 @@ DEFAULT_SETTINGS = { "description": "Enable caching for HTTP API requests", "value": True, }, - "enable_telemetry": { - "description": ("Telemetry service (Yes/No)"), - "value": True, - }, "force_verbose": { "description": "Force verbose output when processing environments", "value": False, @@ -69,7 +65,6 @@ SESSION_VARS = { "command_ctx": None, "caller_id": None, "custom_project_conf": None, - "pause_telemetry": False, } @@ -274,8 +269,6 @@ 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 880ca155..db0bac63 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -151,7 +151,7 @@ if not os.path.isdir(env.subst("$BUILD_DIR")): os.makedirs(env.subst("$BUILD_DIR")) # Dynamically load dependent tools -if "compiledb" in COMMAND_LINE_TARGETS: +if "compiledb" in COMMAND_LINE_TARGETS or "compiledbtc" in COMMAND_LINE_TARGETS: env.Tool("compilation_db") env.LoadProjectOptions() @@ -195,6 +195,9 @@ if env.get("SIZETOOL") and not ( if "compiledb" in COMMAND_LINE_TARGETS: env.Alias("compiledb", env.CompilationDatabase("$COMPILATIONDB_PATH")) +if "compiledbtc" in COMMAND_LINE_TARGETS: + env.Alias("compiledbtc", env.CompilationDatabase("$COMPILATIONDB_PATH")) + # Print configured protocols env.AddPreAction( "upload", diff --git a/platformio/builder/tools/piobuild.py b/platformio/builder/tools/piobuild.py index 8ef2522c..8851194e 100644 --- a/platformio/builder/tools/piobuild.py +++ b/platformio/builder/tools/piobuild.py @@ -60,6 +60,7 @@ def GetBuildType(env): def BuildProgram(env): env.ProcessProgramDeps() env.ProcessCompileDbToolchainOption() + env.ProcessCompileDbIncludeToolchainOption() env.ProcessProjectDeps() # append into the beginning a main LD script @@ -128,10 +129,7 @@ def ProcessProgramDeps(env): env.ProcessUnFlags(env.get("BUILD_UNFLAGS")) -def ProcessCompileDbToolchainOption(env): - if "compiledb" not in COMMAND_LINE_TARGETS: - return - +def ProccessCompileDb(env, include_toolchain=False): # Resolve absolute path of toolchain for cmd in ("CC", "CXX", "AS"): if cmd not in env: @@ -142,13 +140,25 @@ def ProcessCompileDbToolchainOption(env): if " " in env[cmd]: # issue #4998: Space in compilator path env[cmd] = f'"{env[cmd]}"' - if env.get("COMPILATIONDB_INCLUDE_TOOLCHAIN"): - print("Warning! `COMPILATIONDB_INCLUDE_TOOLCHAIN` is scoping") + if include_toolchain: for scope, includes in env.DumpIntegrationIncludes().items(): if scope in ("toolchain",): env.Append(CPPPATH=includes) +def ProcessCompileDbToolchainOption(env): + if "compiledb" in COMMAND_LINE_TARGETS: + ProccessCompileDb(env) + + if env.get("COMPILATIONDB_INCLUDE_TOOLCHAIN"): + print("Warning! `COMPILATIONDB_INCLUDE_TOOLCHAIN` is scoping") + print("Use 'pio run -t compiledbtc' instead.") + ProccessCompileDb(env, include_toolchain=True) + +def ProcessCompileDbIncludeToolchainOption(env): + if "compiledbtc" in COMMAND_LINE_TARGETS: + ProccessCompileDb(env, include_toolchain=True) + def ProcessProjectDeps(env): plb = env.ConfigureProjectLibBuilder() @@ -388,6 +398,7 @@ def generate(env): env.AddMethod(BuildProgram) env.AddMethod(ProcessProgramDeps) env.AddMethod(ProcessCompileDbToolchainOption) + env.AddMethod(ProcessCompileDbIncludeToolchainOption) env.AddMethod(ProcessProjectDeps) env.AddMethod(ParseFlagsExtended) env.AddMethod(ProcessFlags) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 36b72d26..e9cc2980 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -497,6 +497,7 @@ class LibBuilderBase: self.env.PrependUnique(CPPPATH=self.get_include_dirs()) self.env.ProcessCompileDbToolchainOption() + self.env.ProcessCompileDbIncludeToolchainOption() if self.lib_ldf_mode == "off": for lb in self.env.GetLibBuilders(): diff --git a/platformio/builder/tools/piomaxlen.py b/platformio/builder/tools/piomaxlen.py index 8d45317c..1656a133 100644 --- a/platformio/builder/tools/piomaxlen.py +++ b/platformio/builder/tools/piomaxlen.py @@ -70,7 +70,7 @@ def _file_long_data(env, data): def exists(env): - return "compiledb" not in COMMAND_LINE_TARGETS and not env.IsIntegrationDump() + return "compiledb" and "compiledbtc" not in COMMAND_LINE_TARGETS and not env.IsIntegrationDump() def generate(env): diff --git a/platformio/check/tools/clangtidy.py b/platformio/check/tools/clangtidy.py index 496acc7c..a6448908 100644 --- a/platformio/check/tools/clangtidy.py +++ b/platformio/check/tools/clangtidy.py @@ -12,11 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os import re -from os.path import join from platformio.check.defect import DefectItem from platformio.check.tools.base import CheckToolBase +from platformio.project.config import ProjectConfig class ClangtidyCheckTool(CheckToolBase): @@ -55,7 +56,11 @@ class ClangtidyCheckTool(CheckToolBase): return cmd_result["returncode"] < 2 def configure_command(self): - tool_path = join(self.get_tool_dir("tool-clangtidy"), "clang-tidy") + tool_path = os.path.join( + ProjectConfig.get_instance().get("platformio","packages_dir"), + "tool-clangtidy", + "clang-tidy" + ) cmd = [tool_path, "--quiet"] flags = self.get_flags("clangtidy") diff --git a/platformio/check/tools/cppcheck.py b/platformio/check/tools/cppcheck.py index c3c59537..0d12dc6f 100644 --- a/platformio/check/tools/cppcheck.py +++ b/platformio/check/tools/cppcheck.py @@ -19,6 +19,7 @@ import click from platformio import proc from platformio.check.defect import DefectItem from platformio.check.tools.base import CheckToolBase +from platformio.project.config import ProjectConfig class CppcheckCheckTool(CheckToolBase): @@ -103,7 +104,11 @@ class CppcheckCheckTool(CheckToolBase): return DefectItem(**args) def configure_command(self, language, src_file): # pylint: disable=arguments-differ - tool_path = os.path.join(self.get_tool_dir("tool-cppcheck"), "cppcheck") + tool_path = os.path.join( + ProjectConfig.get_instance().get("platformio","packages_dir"), + "tool-cppcheck", + "cppcheck" + ) cmd = [ tool_path, diff --git a/platformio/check/tools/pvsstudio.py b/platformio/check/tools/pvsstudio.py index 35d4023f..4c87747a 100644 --- a/platformio/check/tools/pvsstudio.py +++ b/platformio/check/tools/pvsstudio.py @@ -22,10 +22,15 @@ import click from platformio import proc from platformio.check.defect import DefectItem from platformio.check.tools.base import CheckToolBase +from platformio.project.config import ProjectConfig from platformio.compat import IS_WINDOWS class PvsStudioCheckTool(CheckToolBase): # pylint: disable=too-many-instance-attributes + pvs_path = os.path.join( + ProjectConfig.get_instance().get("platformio","packages_dir"), + "tool-pvs-studio" + ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._tmp_dir = tempfile.mkdtemp(prefix="piocheck") @@ -34,7 +39,7 @@ class PvsStudioCheckTool(CheckToolBase): # pylint: disable=too-many-instance-at self._tmp_cfg_file = self._generate_tmp_file_path() + ".cfg" self._tmp_cmd_file = self._generate_tmp_file_path() + ".cmd" self.tool_path = os.path.join( - self.get_tool_dir("tool-pvs-studio"), + self.pvs_path, "x64" if IS_WINDOWS else "bin", "pvs-studio", ) @@ -74,8 +79,12 @@ class PvsStudioCheckTool(CheckToolBase): # pylint: disable=too-many-instance-at self._on_defect_callback(defect) def _demangle_report(self, output_file): + pvs_path = os.path.join( + ProjectConfig.get_instance().get("platformio","packages_dir"), + "tool-pvs-studio" + ) converter_tool = os.path.join( - self.get_tool_dir("tool-pvs-studio"), + pvs_path, "HtmlGenerator" if IS_WINDOWS else os.path.join("bin", "plog-converter"), ) diff --git a/platformio/debug/process/gdb.py b/platformio/debug/process/gdb.py index 29a8ba3a..eef2ee2e 100644 --- a/platformio/debug/process/gdb.py +++ b/platformio/debug/process/gdb.py @@ -16,10 +16,8 @@ import os import signal import time -from platformio import telemetry from platformio.compat import aio_get_running_loop, is_bytes from platformio.debug import helpers -from platformio.debug.exception import DebugInitError from platformio.debug.process.client import DebugClientProcess @@ -130,7 +128,6 @@ class GDBClientProcess(DebugClientProcess): self._handle_error(data) # go to init break automatically if self.INIT_COMPLETED_BANNER.encode() in data: - telemetry.log_debug_started(self.debug_config) self._auto_exec_continue() def console_log(self, msg): @@ -175,7 +172,4 @@ class GDBClientProcess(DebugClientProcess): and b"Error in sourced" in self._errors_buffer ): return - telemetry.log_debug_exception( - DebugInitError(self._errors_buffer.decode()), self.debug_config - ) self.transport.close() diff --git a/platformio/dependencies.py b/platformio/dependencies.py index b36b42b5..a2f2dfdc 100644 --- a/platformio/dependencies.py +++ b/platformio/dependencies.py @@ -17,12 +17,14 @@ from platformio.compat import is_proxy_set def get_core_dependencies(): return { - "contrib-piohome": "~3.4.2", - "contrib-pioremote": "~1.0.0", - "tool-scons": "~4.40801.0", - "tool-cppcheck": "~1.21100.0", - "tool-clangtidy": "~1.150005.0", - "tool-pvs-studio": "~7.18.0", + "contrib-piohome": ( + "https://github.com/pioarduino/registry/releases/" + "download/0.0.1/contrib-piohome-3.4.4.tar.gz" + ), + "tool-scons": ( + "https://github.com/pioarduino/scons/releases/" + "download/4.8.1/scons-local-4.8.1.tar.gz" + ), } @@ -37,6 +39,9 @@ def get_pip_dependencies(): "requests%s == 2.*" % ("[socks]" if is_proxy_set(socks=True) else ""), "semantic_version == 2.10.*", "tabulate == 0.*", + "certifi", + "intelhex", # actual esptool.py requirement + "rich_click", # latest esptool.py requirement ] home = [ diff --git a/platformio/device/finder.py b/platformio/device/finder.py index cd448098..88754f0e 100644 --- a/platformio/device/finder.py +++ b/platformio/device/finder.py @@ -13,6 +13,7 @@ # limitations under the License. import os +import sys from fnmatch import fnmatch from functools import lru_cache @@ -154,7 +155,16 @@ class SerialPortFinder: # pick the best PID:VID USB device port = best_port = None - for item in list_serial_ports(): + port_list = list_serial_ports() + # macOS-specific: filter out unwanted ports + if sys.platform == "darwin": + port_list = [ + item for item in port_list + if not item["port"].endswith( + ("Bluetooth-Incoming-Port", "wlan-debug", "debug-console") + ) + ] + for item in port_list: if self.ensure_ready and not is_serial_port_ready(item["port"]): continue port = item["port"] diff --git a/platformio/home/cli.py b/platformio/home/cli.py index 103822b4..1dfc9316 100644 --- a/platformio/home/cli.py +++ b/platformio/home/cli.py @@ -22,7 +22,7 @@ from platformio.home.run import run_server from platformio.package.manager.core import get_core_package_dir -@click.command("home", short_help="GUI to manage PlatformIO") +@click.command("home", short_help="GUI to manage PIO") @click.option("--port", type=int, default=8008, help="HTTP port, default=8008") @click.option( "--host", @@ -52,8 +52,13 @@ from platformio.package.manager.core import get_core_package_dir def cli(port, host, no_open, shutdown_timeout, session_id): # hook for `platformio-node-helpers` if host == "__do_not_start__": - # download all dependent packages - get_core_package_dir("contrib-piohome") + # Ensure contrib-piohome package is installed + try: + get_core_package_dir("contrib-piohome") + except Exception as exc: # pylint: disable=broad-except + click.secho( + "Warning! Could not install contrib-piohome: %s" % exc, fg="yellow" + ) return # Ensure PIO Home mimetypes are known @@ -71,7 +76,7 @@ def cli(port, host, no_open, shutdown_timeout, session_id): [ "", " ___I_", - " /\\-_--\\ PlatformIO Home", + " /\\-_--\\ PIO Home", "/ \\_-__\\", "|[]| [] | %s" % home_url, "|__|____|__%s" % ("_" * len(home_url)), @@ -79,11 +84,11 @@ def cli(port, host, no_open, shutdown_timeout, session_id): ) ) click.echo("") - click.echo("Open PlatformIO Home in your browser by this URL => %s" % home_url) + click.echo("Open PIO Home in your browser by this URL => %s" % home_url) if is_port_used(host, port): click.secho( - "PlatformIO Home server is already started in another process.", fg="yellow" + "PIO Home server is already started in another process.", fg="yellow" ) if not no_open: click_launch(home_url) diff --git a/platformio/home/run.py b/platformio/home/run.py index df3fa47e..b251ae47 100644 --- a/platformio/home/run.py +++ b/platformio/home/run.py @@ -62,9 +62,12 @@ async def protected_page(_): def run_server(host, port, no_open, shutdown_timeout, home_url): + # Ensure contrib-piohome is installed before starting the server contrib_dir = get_core_package_dir("contrib-piohome") if not os.path.isdir(contrib_dir): - raise PlatformioException("Invalid path to PIO Home Contrib") + raise PlatformioException( + "Invalid path to PIO Home Contrib: %s" % contrib_dir + ) ws_rpc_factory = WebSocketJSONRPCServerFactory(shutdown_timeout) ws_rpc_factory.add_object_handler(AccountRPC(), namespace="account") diff --git a/platformio/maintenance.py b/platformio/maintenance.py index 45b4e5c9..ef95ba67 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -19,11 +19,9 @@ from time import time import click import semantic_version -from platformio import __version__, app, exception, fs, telemetry +from platformio import __version__, app, fs from platformio.cache import cleanup_content_cache from platformio.cli import PlatformioCLI -from platformio.commands.upgrade import get_latest_version -from platformio.http import HTTPClientError, InternetConnectionError, ensure_internet_on from platformio.package.manager.core import update_core_packages from platformio.package.version import pepver_to_semver from platformio.system.prune import calculate_unnecessary_system_data @@ -32,37 +30,14 @@ from platformio.system.prune import calculate_unnecessary_system_data def on_cmd_start(ctx, caller): app.set_session_var("command_ctx", ctx) set_caller(caller) - telemetry.on_cmd_start(ctx) if PlatformioCLI.in_silence(): return after_upgrade(ctx) def on_cmd_end(): - if PlatformioCLI.in_silence(): - return - - try: - check_platformio_upgrade() - check_prune_system() - except ( - HTTPClientError, - InternetConnectionError, - exception.GetLatestVersionError, - ): - click.secho( - "Failed to check for PlatformIO upgrades. " - "Please check your Internet connection.", - fg="red", - ) - - -def on_platformio_exception(exc): - telemetry.log_exception(exc) - - -def on_platformio_exit(): - telemetry.on_exit() + # pioarduino change: never check for upgrades + return def set_caller(caller=None): @@ -103,7 +78,6 @@ class Upgrader: state_path = app.resolve_state_path("core_dir", "appstate.json") if not os.path.isfile(state_path): return True - app.delete_state_item("telemetry") created_at = app.get_state_item("created_at", None) if not created_at: state_stat = os.stat(state_path) @@ -119,35 +93,21 @@ class Upgrader: def after_upgrade(ctx): - terminal_width = shutil.get_terminal_size().columns last_version_str = app.get_state_item("last_version", "0.0.0") if last_version_str == __version__: return None if last_version_str == "0.0.0": app.set_state_item("last_version", __version__) - return print_welcome_banner() + return None last_version = pepver_to_semver(last_version_str) current_version = pepver_to_semver(__version__) if last_version > current_version and not last_version.prerelease: - click.secho("*" * terminal_width, fg="yellow") - click.secho( - "Obsolete PIO Core v%s is used (previous was %s)" - % (__version__, last_version_str), - fg="yellow", - ) - click.secho("Please remove multiple PIO Cores from a system:", fg="yellow") - click.secho( - "https://docs.platformio.org/en/latest/core" - "/installation/troubleshooting.html", - fg="cyan", - ) - click.secho("*" * terminal_width, fg="yellow") return None - click.secho("Please wait while upgrading PlatformIO...", fg="yellow") + click.secho("Please wait while upgrading...", fg="yellow") # Update PlatformIO's Core packages cleanup_content_cache("http") @@ -157,96 +117,16 @@ def after_upgrade(ctx): if u.run(ctx): app.set_state_item("last_version", __version__) click.secho( - "PlatformIO has been successfully upgraded to %s!\n" % __version__, + "Pio has been successfully upgraded to %s!\n" % __version__, fg="green", ) - telemetry.log_event( - "pio_upgrade_core", - { - "label": "%s > %s" % (last_version_str, __version__), - "from_version": last_version_str, - "to_version": __version__, - }, - ) - return print_welcome_banner() - - -def print_welcome_banner(): - terminal_width = shutil.get_terminal_size().columns - click.echo("*" * terminal_width) - click.echo("If you like %s, please:" % (click.style("PlatformIO", fg="cyan"))) - click.echo( - "- %s it on GitHub > %s" - % ( - click.style("star", fg="cyan"), - click.style("https://github.com/platformio/platformio-core", fg="cyan"), - ) - ) - click.echo( - "- %s us on LinkedIn to stay up-to-date " - "on the latest project news > %s" - % ( - click.style("follow", fg="cyan"), - click.style("https://www.linkedin.com/company/platformio/", fg="cyan"), - ) - ) - if not os.getenv("PLATFORMIO_IDE"): - click.echo( - "- %s PlatformIO IDE for embedded development > %s" - % ( - click.style("try", fg="cyan"), - click.style("https://platformio.org/platformio-ide", fg="cyan"), - ) - ) - - click.echo("*" * terminal_width) - click.echo("") + return None def check_platformio_upgrade(): - interval = int(app.get_setting("check_platformio_interval")) * 3600 * 24 - check_state = app.get_state_item("last_check", {}) - last_checked_time = check_state.get("platformio_upgrade", 0) - if (time() - interval) < last_checked_time: - return - - check_state["platformio_upgrade"] = int(time()) - app.set_state_item("last_check", check_state) - if not last_checked_time: - return - - ensure_internet_on(raise_exception=True) - - # Update PlatformIO Core packages - update_core_packages() - - latest_version = get_latest_version() - if pepver_to_semver(latest_version) <= pepver_to_semver(__version__): - return - - terminal_width = shutil.get_terminal_size().columns - - click.echo("") - click.echo("*" * terminal_width) - click.secho( - "There is a new version %s of PlatformIO available.\n" - "Please upgrade it via `" % latest_version, - fg="yellow", - nl=False, - ) - if os.path.join("Cellar", "platformio") in fs.get_source_dir(): - click.secho("brew update && brew upgrade", fg="cyan", nl=False) - click.secho("` command.", fg="yellow") - else: - click.secho("platformio upgrade", fg="cyan", nl=False) - click.secho("` or `", fg="yellow", nl=False) - click.secho("python -m pip install -U platformio", fg="cyan", nl=False) - click.secho("` command.", fg="yellow") - click.secho("Changes: ", fg="yellow", nl=False) - click.secho("https://docs.platformio.org/en/latest/history.html", fg="cyan") - click.echo("*" * terminal_width) - click.echo("") + # pioarduino change: never check for upgrade + return def check_prune_system(): @@ -274,7 +154,7 @@ def check_prune_system(): click.echo() click.echo("*" * terminal_width) click.secho( - "We found %s of unnecessary PlatformIO system data (temporary files, " + "We found %s of unnecessary pioarduino system data (temporary files, " "unnecessary packages, etc.).\nUse `pio system prune --dry-run` to list " "them or `pio system prune` to save disk space." % fs.humanize_file_size(unnecessary_size), diff --git a/platformio/package/vcsclient.py b/platformio/package/vcsclient.py index 67348391..8c80c9d2 100644 --- a/platformio/package/vcsclient.py +++ b/platformio/package/vcsclient.py @@ -190,8 +190,12 @@ class GitClient(VCSClientBase): if self.tag: args += ["--branch", self.tag] args += [self.remote_url, self.src_dir] - assert self.run_cmd(args, cwd=os.getcwd()) + if not is_commit: + assert self.run_cmd(args, cwd=os.getcwd()) if is_commit: + assert self.run_cmd(["init", self.src_dir], cwd=os.getcwd()) + assert self.run_cmd(["remote", "add", "origin", self.remote_url]) + assert self.run_cmd(["fetch", "--depth=1", "origin", self.tag]) assert self.run_cmd(["reset", "--hard", self.tag]) return self.run_cmd( ["submodule", "update", "--init", "--recursive", "--force"] diff --git a/platformio/platform/_run.py b/platformio/platform/_run.py index 81d697f5..ced6d686 100644 --- a/platformio/platform/_run.py +++ b/platformio/platform/_run.py @@ -21,7 +21,7 @@ from urllib.parse import quote import click -from platformio import app, fs, proc, telemetry +from platformio import app, fs, proc from platformio.compat import hashlib_encode_data from platformio.package.manager.core import get_core_package_dir from platformio.platform.exception import BuildScriptNotFound @@ -60,7 +60,6 @@ class PlatformRunMixin: if not os.path.isfile(variables["build_script"]): raise BuildScriptNotFound(variables["build_script"]) - telemetry.log_platform_run(self, self.config, variables["pioenv"], targets) result = self._run_scons(variables, targets, jobs) assert "returncode" in result diff --git a/platformio/project/commands/init.py b/platformio/project/commands/init.py index f4702eb3..3ccde013 100644 --- a/platformio/project/commands/init.py +++ b/platformio/project/commands/init.py @@ -314,6 +314,10 @@ def update_board_envs(project_dir, boards, extra_project_options, env_prefix): modified = True envopts = {"platform": board_config["platform"], "board": id_} + platform_value = board_config["platform"] + if platform_value == "espressif32": + platform_value = "https://github.com/pioarduino/platform-espressif32/releases/download/stable/platform-espressif32.zip" + envopts = {"platform": platform_value, "board": id_} # find default framework for board frameworks = board_config.get("frameworks") if frameworks: diff --git a/platformio/project/helpers.py b/platformio/project/helpers.py index 2732e6bd..cb4f638a 100644 --- a/platformio/project/helpers.py +++ b/platformio/project/helpers.py @@ -25,16 +25,37 @@ from platformio.project.config import ProjectConfig def get_project_dir(): + """Get the current project directory. + + Returns: + str: Current working directory path + """ return os.getcwd() def is_platformio_project(project_dir=None): + """Check if the given directory is a PlatformIO project. + + Args: + project_dir (str, optional): Directory path to check. Defaults to current directory. + + Returns: + bool: True if directory contains platformio.ini file + """ if not project_dir: project_dir = get_project_dir() return os.path.isfile(os.path.join(project_dir, "platformio.ini")) def find_project_dir_above(path): + """Find PlatformIO project directory by traversing up the directory tree. + + Args: + path (str): Starting path to search from + + Returns: + str or None: Path to project directory if found, None otherwise + """ if os.path.isfile(path): path = os.path.dirname(path) if is_platformio_project(path): @@ -45,7 +66,13 @@ def find_project_dir_above(path): def get_project_watch_lib_dirs(): - """Used by platformio-node-helpers.project.observer.fetchLibDirs""" + """Get library directories that should be watched for changes. + + Used by platformio-node-helpers.project.observer.fetchLibDirs + + Returns: + list: List of library directory paths + """ config = ProjectConfig.get_instance() result = [ config.get("platformio", "globallib_dir"), @@ -60,15 +87,27 @@ def get_project_watch_lib_dirs(): return result +# Backward compatibility alias get_project_all_lib_dirs = get_project_watch_lib_dirs def get_project_cache_dir(): - """Deprecated, use ProjectConfig.get("platformio", "cache_dir") instead""" + """Get project cache directory. + + Deprecated, use ProjectConfig.get("platformio", "cache_dir") instead + + Returns: + str: Cache directory path + """ return ProjectConfig.get_instance().get("platformio", "cache_dir") def get_default_projects_dir(): + """Get the default directory for PlatformIO projects. + + Returns: + str: Default projects directory path (usually ~/Documents/PlatformIO/Projects) + """ docs_dir = os.path.join(fs.expanduser("~"), "Documents") try: assert IS_WINDOWS @@ -91,6 +130,14 @@ def get_default_projects_dir(): def compute_project_checksum(config): + """Compute project checksum based on configuration and file structure. + + Args: + config (ProjectConfig): Project configuration instance + + Returns: + str: Hexadecimal checksum string + """ # rebuild when PIO Core version changes checksum = sha1(hashlib_encode_data(__version__)) @@ -132,6 +179,17 @@ def compute_project_checksum(config): def load_build_metadata(project_dir, env_or_envs, cache=False, build_type=None): + """Load build metadata for specified environments. + + Args: + project_dir (str): Project directory path + env_or_envs (str or list): Environment name(s) to load metadata for + cache (bool, optional): Use cached metadata if available. Defaults to False. + build_type (str, optional): Build type (release/debug). Defaults to None. + + Returns: + dict or None: Build metadata dictionary or None if not available + """ assert env_or_envs env_names = env_or_envs if not isinstance(env_names, list): @@ -163,8 +221,20 @@ load_project_ide_data = load_build_metadata def _load_build_metadata(project_dir, env_names, build_type=None): + """Internal function to load build metadata by running idedata target. + + Args: + project_dir (str): Project directory path + env_names (list): List of environment names + build_type (str, optional): Build type. Defaults to None. + + Returns: + dict: Build metadata dictionary + + Raises: + exception.UserSideException: If build metadata generation fails + """ # pylint: disable=import-outside-toplevel - from platformio import app from platformio.run.cli import cli as cmd_run args = ["--project-dir", project_dir, "--target", "__idedata"] @@ -174,9 +244,7 @@ def _load_build_metadata(project_dir, env_names, build_type=None): # args.extend(["--target", "__test"]) for name in env_names: args.extend(["-e", name]) - app.set_session_var("pause_telemetry", True) result = CliRunner().invoke(cmd_run, args) - app.set_session_var("pause_telemetry", False) if result.exit_code != 0 and not isinstance( result.exception, exception.ReturnErrorCode ): @@ -187,6 +255,14 @@ def _load_build_metadata(project_dir, env_names, build_type=None): def _get_cached_build_metadata(env_names): + """Get cached build metadata from idedata.json files. + + Args: + env_names (list): List of environment names + + Returns: + dict: Dictionary mapping environment names to their build metadata + """ build_dir = ProjectConfig.get_instance().get("platformio", "build_dir") result = {} for env_name in env_names: diff --git a/platformio/project/integration/tpls/vscode/.vscode/extensions.json.tpl b/platformio/project/integration/tpls/vscode/.vscode/extensions.json.tpl index 8d8e8a02..52e9c558 100644 --- a/platformio/project/integration/tpls/vscode/.vscode/extensions.json.tpl +++ b/platformio/project/integration/tpls/vscode/.vscode/extensions.json.tpl @@ -2,7 +2,7 @@ % import os % import re % -% recommendations = set(["platformio.platformio-ide"]) +% recommendations = set(["pioarduino.pioarduino-ide"]) % unwantedRecommendations = set(["ms-vscode.cpptools-extension-pack"]) % previous_json = os.path.join(project_dir, ".vscode", "extensions.json") % if os.path.isfile(previous_json): @@ -20,8 +20,6 @@ % end % end { - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format "recommendations": [ % for i, item in enumerate(sorted(recommendations)): "{{ item }}"{{ ("," if (i + 1) < len(recommendations) else "") }} diff --git a/platformio/remote/cli.py b/platformio/remote/cli.py index 423980f5..0f5d5c88 100644 --- a/platformio/remote/cli.py +++ b/platformio/remote/cli.py @@ -31,7 +31,7 @@ from platformio.device.monitor.command import ( device_monitor_cmd, get_project_options, ) -from platformio.package.manager.core import get_core_package_dir +from platformio.project.config import ProjectConfig from platformio.project.exception import NotPlatformIOProjectError from platformio.project.options import ProjectOptions from platformio.run.cli import cli as cmd_run @@ -44,7 +44,8 @@ from platformio.test.cli import cli as test_cmd def cli(ctx, agent): ctx.obj = agent # inject twisted dependencies - contrib_dir = get_core_package_dir("contrib-pioremote") + packages_dir = ProjectConfig.get_instance().get("platformio", "packages_dir") + contrib_dir = os.path.join(packages_dir, "contrib-pioremote") if contrib_dir not in sys.path: addsitedir(contrib_dir) sys.path.insert(0, contrib_dir) diff --git a/platformio/remote/client/base.py b/platformio/remote/client/base.py index cf5c2405..f2a0c645 100644 --- a/platformio/remote/client/base.py +++ b/platformio/remote/client/base.py @@ -25,7 +25,7 @@ from twisted.python import failure # pylint: disable=import-error from twisted.spread import pb # pylint: disable=import-error from zope.interface import provider # pylint: disable=import-error -from platformio import __pioremote_endpoint__, __version__, app, exception, maintenance +from platformio import __pioremote_endpoint__, __version__, app, exception from platformio.remote.factory.client import RemoteClientFactory from platformio.remote.factory.ssl import SSLContextFactory @@ -186,7 +186,5 @@ class RemoteClientBase( # pylint: disable=too-many-instance-attributes "a remote machine using `pio remote agent start` command.\n" "See http://docs.platformio.org/page/plus/pio-remote.html" ) - else: - maintenance.on_platformio_exception(Exception(err.type)) click.secho(msg, fg="red", err=True) self.disconnect(exit_code=1) diff --git a/platformio/telemetry.py b/platformio/telemetry.py deleted file mode 100644 index 5b0734c9..00000000 --- a/platformio/telemetry.py +++ /dev/null @@ -1,380 +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 atexit -import os -import queue -import re -import sys -import threading -import time -import traceback -from collections import deque - -import requests - -from platformio import __title__, __version__, app, exception, fs, util -from platformio.cli import PlatformioCLI -from platformio.debug.config.base import DebugConfigBase -from platformio.http import HTTPSession -from platformio.proc import is_ci - -KEEP_MAX_REPORTS = 100 -SEND_MAX_EVENTS = 25 - - -class MeasurementProtocol: - def __init__(self, events=None): - self.client_id = app.get_cid() - self._events = events or [] - self._user_properties = {} - - self.set_user_property("systype", util.get_systype()) - created_at = app.get_state_item("created_at", None) - if created_at: - self.set_user_property("created_at", int(created_at)) - - @staticmethod - def event_to_dict(name, params, timestamp=None): - event = {"name": name, "params": params} - if timestamp is not None: - event["timestamp"] = timestamp - return event - - def set_user_property(self, name, value): - self._user_properties[name] = value - - def add_event(self, name, params): - self._events.append(self.event_to_dict(name, params)) - - def to_payload(self): - return { - "client_id": self.client_id, - "user_properties": self._user_properties, - "events": self._events, - } - - -@util.singleton -class TelemetryLogger: - def __init__(self): - self._events = deque() - - self._sender_thread = None - self._sender_queue = queue.Queue() - self._sender_terminated = False - - self._http_session = HTTPSession() - self._http_offline = False - - def close(self): - self._http_session.close() - - def log_event(self, name, params, timestamp=None, instant_sending=False): - if not app.get_setting("enable_telemetry") or app.get_session_var( - "pause_telemetry" - ): - return None - timestamp = timestamp or int(time.time()) - self._events.append( - MeasurementProtocol.event_to_dict(name, params, timestamp=timestamp) - ) - if self._http_offline: # if network is off-line - return False - if instant_sending: - self.send() - return True - - def send(self): - if not self._events or self._sender_terminated: - return - if not self._sender_thread: - self._sender_thread = threading.Thread( - target=self._sender_worker, daemon=True - ) - self._sender_thread.start() - while self._events: - events = [] - try: - while len(events) < SEND_MAX_EVENTS: - events.append(self._events.popleft()) - except IndexError: - pass - self._sender_queue.put(events) - - def _sender_worker(self): - while True: - if self._sender_terminated: - return - try: - events = self._sender_queue.get() - if not self._commit_events(events): - self._events.extend(events) - self._sender_queue.task_done() - except (queue.Empty, ValueError): - pass - - def _commit_events(self, events): - if self._http_offline: - return False - mp = MeasurementProtocol(events) - payload = mp.to_payload() - # print("_commit_payload", payload) - try: - r = self._http_session.post( - "https://collector.platformio.org/collect", - json=payload, - timeout=(2, 5), # connect, read - ) - r.raise_for_status() - return True - except requests.exceptions.HTTPError as exc: - # skip Bad Request - if exc.response.status_code >= 400 and exc.response.status_code < 500: - return True - except: # pylint: disable=bare-except - pass - self._http_offline = True - return False - - def terminate_sender(self): - self._sender_terminated = True - - def is_sending(self): - return self._sender_queue.unfinished_tasks - - def get_unsent_events(self): - result = list(self._events) - try: - while True: - result.extend(self._sender_queue.get_nowait()) - except queue.Empty: - pass - return result - - -def log_event(name, params, instant_sending=False): - TelemetryLogger().log_event(name, params, instant_sending=instant_sending) - - -def on_cmd_start(cmd_ctx): - process_postponed_logs() - log_command(cmd_ctx) - - -def on_exit(): - TelemetryLogger().send() - - -def log_command(ctx): - params = { - "path_args": PlatformioCLI.reveal_cmd_path_args(ctx), - } - if is_ci(): - params["ci_actor"] = resolve_ci_actor() or "Unknown" - log_event("cmd_run", params) - - -def resolve_ci_actor(): - known_cis = ( - "GITHUB_ACTIONS", - "TRAVIS", - "APPVEYOR", - "GITLAB_CI", - "CIRCLECI", - "SHIPPABLE", - "DRONE", - ) - for name in known_cis: - if os.getenv(name, "false").lower() == "true": - return name - return None - - -def dump_project_env_params(config, env, platform): - non_sensitive_data = [ - "platform", - "framework", - "board", - "upload_protocol", - "check_tool", - "debug_tool", - "test_framework", - ] - section = f"env:{env}" - params = { - option: config.get(section, option) - for option in non_sensitive_data - if config.has_option(section, option) - } - params["pid"] = app.get_project_id(os.path.dirname(config.path)) - params["platform_name"] = platform.name - params["platform_version"] = platform.version - return params - - -def log_platform_run(platform, project_config, project_env, targets=None): - params = dump_project_env_params(project_config, project_env, platform) - if targets: - params["targets"] = targets - log_event("platform_run", params, instant_sending=True) - - -def log_exception(exc): - skip_conditions = [ - isinstance(exc, cls) - for cls in ( - IOError, - exception.ReturnErrorCode, - exception.UserSideException, - ) - ] - skip_conditions.append(not isinstance(exc, Exception)) - if any(skip_conditions): - return - is_fatal = any( - [ - not isinstance(exc, exception.PlatformioException), - "Error" in exc.__class__.__name__, - ] - ) - - def _strip_module_path(match): - module_path = match.group(1).replace(fs.get_source_dir() + os.sep, "") - sp_folder_name = "site-packages" - sp_pos = module_path.find(sp_folder_name) - if sp_pos != -1: - module_path = module_path[sp_pos + len(sp_folder_name) + 1 :] - module_path = fs.to_unix_path(module_path) - return f'File "{module_path}",' - - trace = re.sub( - r'File "([^"]+)",', - _strip_module_path, - traceback.format_exc(), - flags=re.MULTILINE, - ) - - params = { - "name": exc.__class__.__name__, - "description": str(exc), - "traceback": trace, - "cmd_args": sys.argv[1:], - "is_fatal": is_fatal, - } - log_event("exception", params) - - -def log_debug_started(debug_config: DebugConfigBase): - log_event( - "debug_started", - dump_project_env_params( - debug_config.project_config, debug_config.env_name, debug_config.platform - ), - ) - - -def log_debug_exception(exc, debug_config: DebugConfigBase): - # cleanup sensitive information, such as paths - description = fs.to_unix_path(str(exc)) - description = re.sub( - r'(^|\s+|")(?:[a-z]\:)?((/[^"/]+)+)(\s+|"|$)', - lambda m: " %s " % os.path.join(*m.group(2).split("/")[-2:]), - description, - re.I | re.M, - ) - params = { - "name": exc.__class__.__name__, - "description": description.strip(), - } - params.update( - dump_project_env_params( - debug_config.project_config, debug_config.env_name, debug_config.platform - ) - ) - log_event("debug_exception", params) - - -@atexit.register -def _finalize(): - timeout = 1000 # msec - elapsed = 0 - telemetry = TelemetryLogger() - telemetry.terminate_sender() - try: - while elapsed < timeout: - if not telemetry.is_sending(): - break - time.sleep(0.2) - elapsed += 200 - except KeyboardInterrupt: - pass - postpone_events(telemetry.get_unsent_events()) - telemetry.close() - - -def load_postponed_events(): - state_path = app.resolve_state_path( - "cache_dir", "telemetry.json", ensure_dir_exists=False - ) - if not os.path.isfile(state_path): - return [] - with app.State(state_path) as state: - return state.get("events", []) - - -def save_postponed_events(events): - state_path = app.resolve_state_path("cache_dir", "telemetry.json") - if not events: - try: - if os.path.isfile(state_path): - os.remove(state_path) - except: # pylint: disable=bare-except - pass - return None - with app.State(state_path, lock=True) as state: - state["events"] = events - state.modified = True - return True - - -def postpone_events(events): - if not events: - return None - postponed_events = load_postponed_events() or [] - timestamp = int(time.time()) - for event in events: - if "timestamp" not in event: - event["timestamp"] = timestamp - postponed_events.append(event) - save_postponed_events(postponed_events[KEEP_MAX_REPORTS * -1 :]) - return True - - -def process_postponed_logs(): - events = load_postponed_events() - if not events: - return None - save_postponed_events([]) # clean - telemetry = TelemetryLogger() - for event in events: - if set(["name", "params", "timestamp"]) <= set(event.keys()): - telemetry.log_event( - event["name"], - event["params"], - timestamp=event["timestamp"], - instant_sending=False, - ) - telemetry.send() - return True diff --git a/setup.py b/setup.py index e4eae238..7e9e133c 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ setup( url=__url__, license=__license__, install_requires=get_pip_dependencies(), - python_requires=">=3.6", + python_requires=">=3.10", packages=find_packages(include=["platformio", "platformio.*"]), package_data={ "platformio": [ diff --git a/tests/commands/pkg/test_install.py b/tests/commands/pkg/test_install.py index c1cafe54..6c5b9c0c 100644 --- a/tests/commands/pkg/test_install.py +++ b/tests/commands/pkg/test_install.py @@ -19,7 +19,6 @@ import os import pytest from platformio import fs -from platformio.dependencies import get_core_dependencies from platformio.package.commands.install import package_install_cmd from platformio.package.manager.library import LibraryPackageManager from platformio.package.manager.platform import PlatformPackageManager @@ -34,9 +33,6 @@ lib_deps = milesburton/DallasTemperature@^4.0.4 https://github.com/esphome/ESPAsyncWebServer/archive/refs/tags/v2.1.0.zip -[env:baremetal] -board = uno - [env:devkit] framework = arduino board = attiny88 @@ -50,184 +46,6 @@ def pkgs_to_specs(pkgs): ] -def test_global_packages( - clirunner, - validate_cliresult, - func_isolated_pio_core, - get_pkg_latest_version, - tmp_path, -): - # libraries - result = clirunner.invoke( - package_install_cmd, - [ - "--global", - "-l", - "https://github.com/milesburton/Arduino-Temperature-Control-Library.git#3.9.0", - "--skip-dependencies", - ], - ) - validate_cliresult(result) - assert pkgs_to_specs(LibraryPackageManager().get_installed()) == [ - PackageSpec("DallasTemperature@3.9.0+sha.964939d") - ] - # with dependencies - result = clirunner.invoke( - package_install_cmd, - [ - "--global", - "-l", - "https://github.com/milesburton/Arduino-Temperature-Control-Library.git#3.9.0", - "-l", - "bblanchon/ArduinoJson@^5", - ], - ) - validate_cliresult(result) - assert pkgs_to_specs(LibraryPackageManager().get_installed()) == [ - PackageSpec("ArduinoJson@5.13.4"), - PackageSpec("DallasTemperature@3.9.0+sha.964939d"), - PackageSpec("OneWire@%s" % get_pkg_latest_version("paulstoffregen/OneWire")), - ] - # custom storage - storage_dir = tmp_path / "custom_lib_storage" - storage_dir.mkdir() - result = clirunner.invoke( - package_install_cmd, - [ - "--global", - "--storage-dir", - str(storage_dir), - "-l", - "bblanchon/ArduinoJson@^5", - ], - ) - validate_cliresult(result) - assert pkgs_to_specs(LibraryPackageManager(storage_dir).get_installed()) == [ - PackageSpec("ArduinoJson@5.13.4") - ] - - # tools - result = clirunner.invoke( - package_install_cmd, - ["--global", "-t", "platformio/framework-arduino-avr-attiny@^1.5.2"], - ) - validate_cliresult(result) - assert pkgs_to_specs(ToolPackageManager().get_installed()) == [ - PackageSpec("framework-arduino-avr-attiny@1.5.2") - ] - - # platforms - result = clirunner.invoke( - package_install_cmd, - ["--global", "-p", "platformio/atmelavr@^3.4.0", "--skip-dependencies"], - ) - validate_cliresult(result) - assert pkgs_to_specs(PlatformPackageManager().get_installed()) == [ - PackageSpec("atmelavr@3.4.0") - ] - - -def test_skip_dependencies( - clirunner, validate_cliresult, isolated_pio_core, get_pkg_latest_version, tmp_path -): - project_dir = tmp_path / "project" - project_dir.mkdir() - (project_dir / "platformio.ini").write_text(PROJECT_CONFIG_TPL) - result = clirunner.invoke( - package_install_cmd, - ["-d", str(project_dir), "-e", "devkit", "--skip-dependencies"], - ) - validate_cliresult(result) - with fs.cd(str(project_dir)): - installed_lib_pkgs = LibraryPackageManager( - os.path.join(ProjectConfig().get("platformio", "libdeps_dir"), "devkit") - ).get_installed() - assert pkgs_to_specs(installed_lib_pkgs) == [ - PackageSpec( - "DallasTemperature@%s" - % get_pkg_latest_version("milesburton/DallasTemperature") - ), - PackageSpec("ESPAsyncWebServer-esphome@2.1.0"), - ] - assert len(ToolPackageManager().get_installed()) == 1 # SCons - - -def test_baremetal_project( - clirunner, validate_cliresult, isolated_pio_core, get_pkg_latest_version, tmp_path -): - project_dir = tmp_path / "project" - project_dir.mkdir() - (project_dir / "platformio.ini").write_text(PROJECT_CONFIG_TPL) - result = clirunner.invoke( - package_install_cmd, - ["-d", str(project_dir), "-e", "baremetal"], - ) - validate_cliresult(result) - with fs.cd(str(project_dir)): - installed_lib_pkgs = LibraryPackageManager( - os.path.join(ProjectConfig().get("platformio", "libdeps_dir"), "baremetal") - ).get_installed() - assert pkgs_to_specs(installed_lib_pkgs) == [ - PackageSpec( - "DallasTemperature@%s" - % get_pkg_latest_version("milesburton/DallasTemperature") - ), - PackageSpec("ESPAsyncWebServer-esphome@2.1.0"), - PackageSpec( - "OneWire@%s" % get_pkg_latest_version("paulstoffregen/OneWire") - ), - ] - assert pkgs_to_specs(ToolPackageManager().get_installed()) == [ - PackageSpec("tool-scons@%s" % get_core_dependencies()["tool-scons"][1:]), - PackageSpec("toolchain-atmelavr@1.70300.191015"), - ] - - -def test_project( - clirunner, validate_cliresult, isolated_pio_core, get_pkg_latest_version, tmp_path -): - project_dir = tmp_path / "project" - project_dir.mkdir() - (project_dir / "platformio.ini").write_text(PROJECT_CONFIG_TPL) - result = clirunner.invoke( - package_install_cmd, - ["-d", str(project_dir)], - ) - validate_cliresult(result) - with fs.cd(str(project_dir)): - config = ProjectConfig() - lm = LibraryPackageManager( - os.path.join(config.get("platformio", "libdeps_dir"), "devkit") - ) - assert pkgs_to_specs(lm.get_installed()) == [ - PackageSpec( - "DallasTemperature@%s" - % get_pkg_latest_version("milesburton/DallasTemperature") - ), - PackageSpec("ESPAsyncWebServer-esphome@2.1.0"), - PackageSpec( - "OneWire@%s" % get_pkg_latest_version("paulstoffregen/OneWire") - ), - ] - assert pkgs_to_specs(ToolPackageManager().get_installed()) == [ - PackageSpec("framework-arduino-avr-attiny@1.5.2"), - PackageSpec("tool-scons@%s" % get_core_dependencies()["tool-scons"][1:]), - PackageSpec("toolchain-atmelavr@1.70300.191015"), - ] - assert config.get("env:devkit", "lib_deps") == [ - "milesburton/DallasTemperature@^4.0.4", - "https://github.com/esphome/ESPAsyncWebServer/archive/refs/tags/v2.1.0.zip", - ] - - # test "Already up-to-date" - result = clirunner.invoke( - package_install_cmd, - ["-d", str(project_dir)], - ) - validate_cliresult(result) - assert "Already up-to-date" in result.output - - def test_private_lib_deps( clirunner, validate_cliresult, isolated_pio_core, get_pkg_latest_version, tmp_path ): @@ -288,66 +106,6 @@ platform = native ] -def test_remove_project_unused_libdeps( - clirunner, validate_cliresult, isolated_pio_core, get_pkg_latest_version, tmp_path -): - project_dir = tmp_path / "project" - project_dir.mkdir() - (project_dir / "platformio.ini").write_text(PROJECT_CONFIG_TPL) - result = clirunner.invoke( - package_install_cmd, - ["-d", str(project_dir), "-e", "baremetal"], - ) - validate_cliresult(result) - with fs.cd(str(project_dir)): - config = ProjectConfig() - storage_dir = os.path.join(config.get("platformio", "libdeps_dir"), "baremetal") - lm = LibraryPackageManager(storage_dir) - assert pkgs_to_specs(lm.get_installed()) == [ - PackageSpec( - "DallasTemperature@%s" - % get_pkg_latest_version("milesburton/DallasTemperature") - ), - PackageSpec("ESPAsyncWebServer-esphome@2.1.0"), - PackageSpec( - "OneWire@%s" % get_pkg_latest_version("paulstoffregen/OneWire") - ), - ] - - # add new deps - lib_deps = config.get("env:baremetal", "lib_deps") - config.set("env:baremetal", "lib_deps", lib_deps + ["bblanchon/ArduinoJson@^5"]) - config.save() - result = clirunner.invoke( - package_install_cmd, - ["-e", "baremetal"], - ) - validate_cliresult(result) - lm = LibraryPackageManager(storage_dir) - assert pkgs_to_specs(lm.get_installed()) == [ - PackageSpec("ArduinoJson@5.13.4"), - PackageSpec( - "DallasTemperature@%s" - % get_pkg_latest_version("milesburton/DallasTemperature") - ), - PackageSpec("ESPAsyncWebServer-esphome@2.1.0"), - PackageSpec( - "OneWire@%s" % get_pkg_latest_version("paulstoffregen/OneWire") - ), - ] - - # manually remove from configuration file - config.set("env:baremetal", "lib_deps", ["bblanchon/ArduinoJson@^5"]) - config.save() - result = clirunner.invoke( - package_install_cmd, - ["-e", "baremetal"], - ) - validate_cliresult(result) - lm = LibraryPackageManager(storage_dir) - assert pkgs_to_specs(lm.get_installed()) == [PackageSpec("ArduinoJson@5.13.4")] - - def test_unknown_project_dependencies( clirunner, validate_cliresult, isolated_pio_core, tmp_path ): diff --git a/tests/commands/pkg/test_list.py b/tests/commands/pkg/test_list.py index c917879e..4e396c38 100644 --- a/tests/commands/pkg/test_list.py +++ b/tests/commands/pkg/test_list.py @@ -13,125 +13,3 @@ # limitations under the License. # pylint: disable=unused-argument - -from platformio.package.commands.install import package_install_cmd -from platformio.package.commands.list import package_list_cmd - -PROJECT_CONFIG_TPL = """ -[env] -platform = platformio/atmelavr@^3.4.0 - -[env:baremetal] -board = uno - -[env:devkit] -framework = arduino -board = attiny88 -lib_deps = - milesburton/DallasTemperature@^3.9.1 - https://github.com/bblanchon/ArduinoJson.git#v6.19.0 -""" - - -def test_project(clirunner, validate_cliresult, isolated_pio_core, tmp_path): - project_dir = tmp_path / "project" - project_dir.mkdir() - (project_dir / "platformio.ini").write_text(PROJECT_CONFIG_TPL) - result = clirunner.invoke( - package_install_cmd, - ["-d", str(project_dir)], - ) - validate_cliresult(result) - - # test all envs - result = clirunner.invoke( - package_list_cmd, - ["-d", str(project_dir)], - ) - validate_cliresult(result) - assert all(token in result.output for token in ("baremetal", "devkit")) - assert result.output.count("Platform atmelavr @ 3.4.0") == 2 - assert ( - result.output.count( - "toolchain-atmelavr @ 1.70300.191015 (required: " - "platformio/toolchain-atmelavr @ ~1.70300.0)" - ) - == 2 - ) - assert result.output.count("Libraries") == 1 - assert ( - "ArduinoJson @ 6.19.0+sha.9693fd2 (required: " - "git+https://github.com/bblanchon/ArduinoJson.git#v6.19.0)" - ) in result.output - assert "OneWire @ 2" in result.output - - # test "baremetal" - result = clirunner.invoke( - package_list_cmd, - ["-d", str(project_dir), "-e", "baremetal"], - ) - validate_cliresult(result) - assert "Platform atmelavr @ 3" in result.output - assert "Libraries" not in result.output - - # filter by "tool" package - result = clirunner.invoke( - package_list_cmd, - ["-d", str(project_dir), "-t", "toolchain-atmelavr@~1.70300.0"], - ) - assert "framework-arduino" not in result.output - assert "Libraries" not in result.output - - # list only libraries - result = clirunner.invoke( - package_list_cmd, - ["-d", str(project_dir), "--only-libraries"], - ) - assert "Platform atmelavr" not in result.output - - # list only libraries for baremetal - result = clirunner.invoke( - package_list_cmd, - ["-d", str(project_dir), "-e", "baremetal", "--only-libraries"], - ) - assert "No packages" in result.output - - -def test_global_packages(clirunner, validate_cliresult, isolated_pio_core, tmp_path): - result = clirunner.invoke(package_list_cmd, ["-g"]) - validate_cliresult(result) - assert "atmelavr @ 3" in result.output - assert "framework-arduino-avr-attiny" in result.output - - # only tools - result = clirunner.invoke(package_list_cmd, ["-g", "--only-tools"]) - validate_cliresult(result) - assert "toolchain-atmelavr" in result.output - assert "Platforms" not in result.output - - # find tool package - result = clirunner.invoke(package_list_cmd, ["-g", "-t", "toolchain-atmelavr"]) - validate_cliresult(result) - assert "toolchain-atmelavr" in result.output - assert "framework-arduino-avr-attiny@" not in result.output - - # only libraries - no packages - result = clirunner.invoke(package_list_cmd, ["-g", "--only-libraries"]) - validate_cliresult(result) - assert not result.output.strip() - - # check global libs - result = clirunner.invoke( - package_install_cmd, ["-g", "-l", "milesburton/DallasTemperature@^3.9.1"] - ) - validate_cliresult(result) - result = clirunner.invoke(package_list_cmd, ["-g", "--only-libraries"]) - validate_cliresult(result) - assert "DallasTemperature" in result.output - assert "OneWire" in result.output - - # filter by lib - result = clirunner.invoke(package_list_cmd, ["-g", "-l", "OneWire"]) - validate_cliresult(result) - assert "DallasTemperature" in result.output - assert "OneWire" in result.output diff --git a/tests/commands/pkg/test_uninstall.py b/tests/commands/pkg/test_uninstall.py index 0d854bc3..7fe125c5 100644 --- a/tests/commands/pkg/test_uninstall.py +++ b/tests/commands/pkg/test_uninstall.py @@ -30,9 +30,6 @@ PROJECT_CONFIG_TPL = """ platform = platformio/atmelavr@^3.4.0 lib_deps = milesburton/DallasTemperature@^3.9.1 -[env:baremetal] -board = uno - [env:devkit] framework = arduino board = attiny88 @@ -43,279 +40,6 @@ def pkgs_to_names(pkgs): return [pkg.metadata.name for pkg in pkgs] -def test_global_packages( - clirunner, validate_cliresult, func_isolated_pio_core, tmp_path -): - # libraries - result = clirunner.invoke( - package_install_cmd, - [ - "--global", - "-l", - "marvinroger/Homie@^3.0.1", - ], - ) - validate_cliresult(result) - assert pkgs_to_names(LibraryPackageManager().get_installed()) == [ - "ArduinoJson", - "Async TCP", - "AsyncMqttClient", - "AsyncTCP", - "AsyncTCP_RP2040W", - "Bounce2", - "ESP Async WebServer", - "ESPAsyncTCP", - "ESPAsyncTCP-esphome", - "Homie", - ] - # uninstall all deps - result = clirunner.invoke( - package_uninstall_cmd, - [ - "--global", - "-l", - "Homie", - ], - ) - validate_cliresult(result) - assert not pkgs_to_names(LibraryPackageManager().get_installed()) - - # skip dependencies - validate_cliresult( - clirunner.invoke( - package_install_cmd, - [ - "--global", - "-l", - "marvinroger/Homie@^3.0.1", - ], - ) - ) - result = clirunner.invoke( - package_uninstall_cmd, - ["--global", "-l", "marvinroger/Homie@^3.0.1", "--skip-dependencies"], - ) - validate_cliresult(result) - assert pkgs_to_names(LibraryPackageManager().get_installed()) == [ - "ArduinoJson", - "Async TCP", - "AsyncMqttClient", - "AsyncTCP", - "AsyncTCP_RP2040W", - "Bounce2", - "ESP Async WebServer", - "ESPAsyncTCP", - "ESPAsyncTCP-esphome", - ] - # remove specific dependency - result = clirunner.invoke( - package_uninstall_cmd, - [ - "--global", - "-l", - "ESP Async WebServer", - ], - ) - validate_cliresult(result) - assert pkgs_to_names(LibraryPackageManager().get_installed()) == [ - "ArduinoJson", - "AsyncMqttClient", - "AsyncTCP", - "Bounce2", - "ESPAsyncTCP", - ] - - # custom storage - storage_dir = tmp_path / "custom_lib_storage" - storage_dir.mkdir() - result = clirunner.invoke( - package_install_cmd, - [ - "--global", - "--storage-dir", - str(storage_dir), - "-l", - "marvinroger/Homie@^3.0.1", - "--skip-dependencies", - ], - ) - validate_cliresult(result) - assert pkgs_to_names(LibraryPackageManager(storage_dir).get_installed()) == [ - "Homie" - ] - result = clirunner.invoke( - package_uninstall_cmd, - [ - "--global", - "--storage-dir", - str(storage_dir), - "-l", - "marvinroger/Homie@^3.0.1", - ], - ) - validate_cliresult(result) - assert not pkgs_to_names(LibraryPackageManager(storage_dir).get_installed()) - - # tools - result = clirunner.invoke( - package_install_cmd, - ["--global", "-t", "platformio/framework-arduino-avr-attiny@^1.5.2"], - ) - validate_cliresult(result) - assert pkgs_to_names(ToolPackageManager().get_installed()) == [ - "framework-arduino-avr-attiny" - ] - result = clirunner.invoke( - package_uninstall_cmd, - ["--global", "-t", "framework-arduino-avr-attiny"], - ) - validate_cliresult(result) - assert not pkgs_to_names(ToolPackageManager().get_installed()) - - # platforms - result = clirunner.invoke( - package_install_cmd, - ["--global", "-p", "platformio/atmelavr@^3.4.0"], - ) - validate_cliresult(result) - assert pkgs_to_names(PlatformPackageManager().get_installed()) == ["atmelavr"] - assert pkgs_to_names(ToolPackageManager().get_installed()) == ["toolchain-atmelavr"] - result = clirunner.invoke( - package_uninstall_cmd, - ["--global", "-p", "platformio/atmelavr@^3.4.0"], - ) - validate_cliresult(result) - assert not pkgs_to_names(PlatformPackageManager().get_installed()) - assert not pkgs_to_names(ToolPackageManager().get_installed()) - - -def test_project(clirunner, validate_cliresult, isolated_pio_core, tmp_path): - project_dir = tmp_path / "project" - project_dir.mkdir() - (project_dir / "platformio.ini").write_text(PROJECT_CONFIG_TPL) - result = clirunner.invoke( - package_install_cmd, - ["-d", str(project_dir)], - ) - validate_cliresult(result) - with fs.cd(str(project_dir)): - config = ProjectConfig() - lm = LibraryPackageManager( - os.path.join(config.get("platformio", "libdeps_dir"), "devkit") - ) - assert pkgs_to_names(lm.get_installed()) == ["DallasTemperature", "OneWire"] - assert pkgs_to_names(ToolPackageManager().get_installed()) == [ - "framework-arduino-avr-attiny", - "tool-scons", - "toolchain-atmelavr", - ] - assert config.get("env:devkit", "lib_deps") == [ - "milesburton/DallasTemperature@^3.9.1" - ] - - # try again - result = clirunner.invoke( - package_install_cmd, - ["-d", str(project_dir)], - ) - validate_cliresult(result) - assert "Already up-to-date" in result.output - - # uninstall - result = clirunner.invoke( - package_uninstall_cmd, - ["-d", str(project_dir)], - ) - validate_cliresult(result) - with fs.cd(str(project_dir)): - config = ProjectConfig() - lm = LibraryPackageManager( - os.path.join(config.get("platformio", "libdeps_dir"), "devkit") - ) - assert not pkgs_to_names(lm.get_installed()) - assert pkgs_to_names(ToolPackageManager().get_installed()) == ["tool-scons"] - assert config.get("env:devkit", "lib_deps") == [ - "milesburton/DallasTemperature@^3.9.1" - ] - - -def test_custom_project_libraries( - clirunner, validate_cliresult, func_isolated_pio_core, tmp_path -): - project_dir = tmp_path / "project" - project_dir.mkdir() - (project_dir / "platformio.ini").write_text(PROJECT_CONFIG_TPL) - spec = "bblanchon/ArduinoJson@^6.19.2" - result = clirunner.invoke( - package_install_cmd, - ["-d", str(project_dir), "-e", "devkit", "-l", spec], - ) - validate_cliresult(result) - assert "Already up-to-date" not in result.output - with fs.cd(str(project_dir)): - # check folders - config = ProjectConfig() - lm = LibraryPackageManager( - os.path.join(config.get("platformio", "libdeps_dir"), "devkit") - ) - assert pkgs_to_names(lm.get_installed()) == ["ArduinoJson"] - # do not expect any platforms/tools - assert not os.path.exists(config.get("platformio", "platforms_dir")) - assert not os.path.exists(config.get("platformio", "packages_dir")) - # check saved deps - assert config.get("env:devkit", "lib_deps") == [ - "bblanchon/ArduinoJson@^6.19.2", - ] - # uninstall - result = clirunner.invoke( - package_uninstall_cmd, - ["-e", "devkit", "-l", spec], - ) - validate_cliresult(result) - config = ProjectConfig() - lm = LibraryPackageManager( - os.path.join(config.get("platformio", "libdeps_dir"), "devkit") - ) - assert not pkgs_to_names(lm.get_installed()) - # do not expect any platforms/tools - assert not os.path.exists(config.get("platformio", "platforms_dir")) - assert not os.path.exists(config.get("platformio", "packages_dir")) - # check saved deps - assert config.get("env:devkit", "lib_deps") == [ - "milesburton/DallasTemperature@^3.9.1" - ] - - # install library without saving to config - result = clirunner.invoke( - package_install_cmd, - ["-e", "devkit", "-l", spec, "--no-save"], - ) - validate_cliresult(result) - config = ProjectConfig() - lm = LibraryPackageManager( - os.path.join(config.get("platformio", "libdeps_dir"), "devkit") - ) - assert pkgs_to_names(lm.get_installed()) == ["ArduinoJson"] - assert config.get("env:devkit", "lib_deps") == [ - "milesburton/DallasTemperature@^3.9.1", - ] - result = clirunner.invoke( - package_uninstall_cmd, - ["-e", "devkit", "-l", spec, "--no-save"], - ) - validate_cliresult(result) - config = ProjectConfig() - assert config.get("env:devkit", "lib_deps") == [ - "milesburton/DallasTemperature@^3.9.1", - ] - - # unknown libraries - result = clirunner.invoke( - package_uninstall_cmd, ["-l", "platformio/unknown_library"] - ) - assert isinstance(result.exception, UnknownPackageError) - - def test_custom_project_tools( clirunner, validate_cliresult, func_isolated_pio_core, tmp_path ): diff --git a/tests/commands/pkg/test_update.py b/tests/commands/pkg/test_update.py index 71f5dbf3..cb031bc5 100644 --- a/tests/commands/pkg/test_update.py +++ b/tests/commands/pkg/test_update.py @@ -17,7 +17,6 @@ import os from platformio import fs -from platformio.dependencies import get_core_dependencies from platformio.package.commands.install import package_install_cmd from platformio.package.commands.update import package_update_cmd from platformio.package.exception import UnknownPackageError @@ -53,174 +52,6 @@ def pkgs_to_specs(pkgs): ] -def test_global_packages( - clirunner, validate_cliresult, func_isolated_pio_core, tmp_path -): - # libraries - result = clirunner.invoke( - package_install_cmd, - ["--global", "-l", "bblanchon/ArduinoJson@^5"], - ) - validate_cliresult(result) - assert pkgs_to_specs(LibraryPackageManager().get_installed()) == [ - PackageSpec("ArduinoJson@5.13.4") - ] - # update to the latest version - result = clirunner.invoke( - package_update_cmd, - ["--global", "-l", "bblanchon/ArduinoJson"], - ) - validate_cliresult(result) - pkgs = LibraryPackageManager().get_installed() - assert len(pkgs) == 1 - assert pkgs[0].metadata.version.major > 5 - # custom storage - storage_dir = tmp_path / "custom_lib_storage" - storage_dir.mkdir() - result = clirunner.invoke( - package_install_cmd, - [ - "--global", - "--storage-dir", - str(storage_dir), - "-l", - "bblanchon/ArduinoJson@^5", - ], - ) - validate_cliresult(result) - assert pkgs_to_specs(LibraryPackageManager(storage_dir).get_installed()) == [ - PackageSpec("ArduinoJson@5.13.4") - ] - # update to the latest version - result = clirunner.invoke( - package_update_cmd, - ["--global", "--storage-dir", str(storage_dir), "-l", "bblanchon/ArduinoJson"], - ) - validate_cliresult(result) - pkgs = LibraryPackageManager(storage_dir).get_installed() - assert len(pkgs) == 1 - assert pkgs[0].metadata.version.major > 5 - - # tools - result = clirunner.invoke( - package_install_cmd, - ["--global", "-t", "platformio/framework-arduino-avr-attiny@~1.4"], - ) - validate_cliresult(result) - assert pkgs_to_specs(ToolPackageManager().get_installed()) == [ - PackageSpec("framework-arduino-avr-attiny@1.4.1") - ] - # update to the latest version - result = clirunner.invoke( - package_update_cmd, - ["--global", "-t", "platformio/framework-arduino-avr-attiny@^1"], - ) - validate_cliresult(result) - pkgs = ToolPackageManager().get_installed() - assert len(pkgs) == 1 - assert pkgs[0].metadata.version.major == 1 - assert pkgs[0].metadata.version.minor > 4 - - # platforms - result = clirunner.invoke( - package_install_cmd, - ["--global", "-p", "platformio/atmelavr@^2", "--skip-dependencies"], - ) - validate_cliresult(result) - assert pkgs_to_specs(PlatformPackageManager().get_installed()) == [ - PackageSpec("atmelavr@2.2.0") - ] - # update to the latest version - result = clirunner.invoke( - package_update_cmd, - ["--global", "-p", "platformio/atmelavr", "--skip-dependencies"], - ) - validate_cliresult(result) - pkgs = PlatformPackageManager().get_installed() - assert len(pkgs) == 1 - assert pkgs[0].metadata.version.major > 2 - - # update unknown package - result = clirunner.invoke( - package_update_cmd, - ["--global", "-l", "platformio/unknown_package_for_update"], - ) - assert isinstance(result.exception, UnknownPackageError) - - -def test_project( - clirunner, validate_cliresult, isolated_pio_core, get_pkg_latest_version, tmp_path -): - project_dir = tmp_path / "project" - project_dir.mkdir() - (project_dir / "platformio.ini").write_text(PROJECT_OUTDATED_CONFIG_TPL) - result = clirunner.invoke( - package_install_cmd, - ["-d", str(project_dir)], - ) - validate_cliresult(result) - with fs.cd(str(project_dir)): - config = ProjectConfig() - lm = LibraryPackageManager( - os.path.join(config.get("platformio", "libdeps_dir"), "devkit") - ) - assert pkgs_to_specs(lm.get_installed()) == [ - PackageSpec(f"DallasTemperature@{DALLASTEMPERATURE_LATEST_VERSION}"), - PackageSpec( - "OneWire@%s" % get_pkg_latest_version("paulstoffregen/OneWire") - ), - ] - assert pkgs_to_specs(PlatformPackageManager().get_installed()) == [ - PackageSpec("atmelavr@2.2.0") - ] - assert pkgs_to_specs(ToolPackageManager().get_installed()) == [ - PackageSpec("framework-arduino-avr-attiny@1.3.2"), - PackageSpec("tool-scons@%s" % get_core_dependencies()["tool-scons"][1:]), - PackageSpec("toolchain-atmelavr@1.50400.190710"), - ] - assert config.get("env:devkit", "lib_deps") == [ - "milesburton/DallasTemperature@^3.9.1" - ] - - # update packages - (project_dir / "platformio.ini").write_text(PROJECT_UPDATED_CONFIG_TPL) - result = clirunner.invoke(package_update_cmd) - validate_cliresult(result) - config = ProjectConfig() - lm = LibraryPackageManager( - os.path.join(config.get("platformio", "libdeps_dir"), "devkit") - ) - pkgs = PlatformPackageManager().get_installed() - assert len(pkgs) == 1 - assert pkgs[0].metadata.name == "atmelavr" - assert pkgs[0].metadata.version.major == 3 - assert pkgs_to_specs(lm.get_installed()) == [ - PackageSpec("DallasTemperature@3.11.0"), - PackageSpec( - "OneWire@%s" % get_pkg_latest_version("paulstoffregen/OneWire") - ), - ] - assert pkgs_to_specs(ToolPackageManager().get_installed()) == [ - PackageSpec("framework-arduino-avr-attiny@1.3.2"), - PackageSpec("tool-scons@%s" % get_core_dependencies()["tool-scons"][1:]), - PackageSpec("toolchain-atmelavr@1.70300.191015"), - PackageSpec("toolchain-atmelavr@1.50400.190710"), - ] - assert config.get("env:devkit", "lib_deps") == [ - "milesburton/DallasTemperature@^3.9.1" - ] - - # update again - result = clirunner.invoke(package_update_cmd) - validate_cliresult(result) - assert "Already up-to-date." in result.output - - # update again in the silent ,pde - result = clirunner.invoke(package_update_cmd, ["--silent"]) - validate_cliresult(result) - assert not result.output - - def test_custom_project_libraries( clirunner, validate_cliresult, isolated_pio_core, get_pkg_latest_version, tmp_path ): diff --git a/tests/commands/test_check.py b/tests/commands/test_check.py index bc4a55ac..cb971a0c 100644 --- a/tests/commands/test_check.py +++ b/tests/commands/test_check.py @@ -14,13 +14,8 @@ # pylint: disable=redefined-outer-name -import json -import os -import sys - import pytest -from platformio import fs from platformio.check.cli import cli as cmd_check DEFAULT_CONFIG = """ @@ -93,27 +88,6 @@ def count_defects(output): return error, warning, style -def test_check_cli_output(clirunner, validate_cliresult, check_dir): - result = clirunner.invoke(cmd_check, ["--project-dir", str(check_dir)]) - validate_cliresult(result) - - errors, warnings, style = count_defects(result.output) - - assert errors + warnings + style == EXPECTED_DEFECTS - - -def test_check_json_output(clirunner, validate_cliresult, check_dir): - result = clirunner.invoke( - cmd_check, ["--project-dir", str(check_dir), "--json-output"] - ) - validate_cliresult(result) - - output = json.loads(result.stdout.strip()) - - assert isinstance(output, list) - assert len(output[0].get("defects", [])) == EXPECTED_DEFECTS - - def test_check_tool_defines_passed(clirunner, check_dir): result = clirunner.invoke(cmd_check, ["--project-dir", str(check_dir), "--verbose"]) output = result.output @@ -122,46 +96,6 @@ def test_check_tool_defines_passed(clirunner, check_dir): assert "__GNUC__" in output -def test_check_tool_complex_defines_handled( - clirunner, validate_cliresult, tmpdir_factory -): - project_dir = tmpdir_factory.mktemp("project_dir") - - project_dir.join("platformio.ini").write(DEFAULT_CONFIG + R""" -check_tool = cppcheck, clangtidy, pvs-studio -build_flags = - -DEXTERNAL_INCLUDE_FILE=\"test.h\" - "-DDEFINE_WITH_SPACE="Hello World!"" -""") - - src_dir = project_dir.mkdir("src") - src_dir.join("test.h").write(""" -#ifndef TEST_H -#define TEST_H -#define ARBITRARY_CONST_VALUE 10 -#endif -""") - - src_dir.join("main.c").write(PVS_STUDIO_FREE_LICENSE_HEADER + """ -#if !defined(EXTERNAL_INCLUDE_FILE) -#error "EXTERNAL_INCLUDE_FILE is not declared!" -#else -#include EXTERNAL_INCLUDE_FILE -#endif - -int main() -{ - /* Index out of bounds */ - int arr[ARBITRARY_CONST_VALUE]; - for(int i=0; i < ARBITRARY_CONST_VALUE+1; i++) { - arr[i] = 0; /* High */ - } - return 0; -} -""") - - default_result = clirunner.invoke(cmd_check, ["--project-dir", str(project_dir)]) - validate_cliresult(default_result) def test_check_language_standard_definition_passed(clirunner, tmpdir): @@ -175,9 +109,12 @@ def test_check_language_standard_definition_passed(clirunner, tmpdir): def test_check_language_standard_option_is_converted(clirunner, tmpdir): - config = DEFAULT_CONFIG + """ + config = ( + DEFAULT_CONFIG + + """ build_flags = -std=gnu++1y """ + ) tmpdir.join("platformio.ini").write(config) tmpdir.mkdir("src").join("main.cpp").write(TEST_CODE) result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir), "-v"]) @@ -186,10 +123,13 @@ build_flags = -std=gnu++1y def test_check_language_standard_is_prioritized_over_build_flags(clirunner, tmpdir): - config = DEFAULT_CONFIG + """ + config = ( + DEFAULT_CONFIG + + """ check_flags = --std=c++03 build_flags = -std=c++17 """ + ) tmpdir.join("platformio.ini").write(config) tmpdir.mkdir("src").join("main.cpp").write(TEST_CODE) result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir), "-v"]) @@ -209,40 +149,6 @@ def test_check_language_standard_for_c_language(clirunner, tmpdir): assert "__cplusplus" not in result.output -def test_check_severity_threshold(clirunner, validate_cliresult, check_dir): - result = clirunner.invoke( - cmd_check, ["--project-dir", str(check_dir), "--severity=high"] - ) - validate_cliresult(result) - - errors, warnings, style = count_defects(result.output) - - assert errors == EXPECTED_ERRORS - assert warnings == 0 - assert style == 0 - - -def test_check_includes_passed(clirunner, check_dir): - result = clirunner.invoke(cmd_check, ["--project-dir", str(check_dir), "--verbose"]) - - inc_count = 0 - for line in result.output.split("\n"): - if line.startswith("Includes:"): - inc_count = line.count("-I") - - # at least 1 include path for default mode - assert inc_count > 0 - - -def test_check_silent_mode(clirunner, validate_cliresult, check_dir): - result = clirunner.invoke(cmd_check, ["--project-dir", str(check_dir), "--silent"]) - validate_cliresult(result) - - errors, warnings, style = count_defects(result.output) - - assert errors == EXPECTED_ERRORS - assert warnings == 0 - assert style == 0 def test_check_no_source_files(clirunner, tmpdir): @@ -270,557 +176,3 @@ def test_check_bad_flag_passed(clirunner, check_dir): assert errors == 0 assert warnings == 0 assert style == 0 - - -def test_check_success_if_no_errors(clirunner, validate_cliresult, tmpdir): - tmpdir.join("platformio.ini").write(DEFAULT_CONFIG) - tmpdir.mkdir("src").join("main.c").write(""" -#include - -void unused_function(){ - int unusedVar = 0; - int* iP = &unusedVar; - *iP++; -} - -int main() { -} -""") - - result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir)]) - validate_cliresult(result) - - errors, warnings, style = count_defects(result.output) - - assert "[PASSED]" in result.output - assert errors == 0 - assert warnings == 1 - assert style == 1 - - -def test_check_individual_flags_passed(clirunner, validate_cliresult, tmpdir): - config = DEFAULT_CONFIG + "\ncheck_tool = cppcheck, clangtidy, pvs-studio" - config += """\ncheck_flags = - cppcheck: --std=c++11 - clangtidy: --fix-errors - pvs-studio: --analysis-mode=4 -""" - - tmpdir.join("platformio.ini").write(config) - tmpdir.mkdir("src").join("main.cpp").write( - PVS_STUDIO_FREE_LICENSE_HEADER + TEST_CODE - ) - result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir), "-v"]) - validate_cliresult(result) - - clang_flags_found = cppcheck_flags_found = pvs_flags_found = False - for l in result.output.split("\n"): - if "--fix" in l and "clang-tidy" in l and "--std=c++11" not in l: - clang_flags_found = True - elif "--std=c++11" in l and "cppcheck" in l and "--fix" not in l: - cppcheck_flags_found = True - elif ( - "--analysis-mode=4" in l and "pvs-studio" in l.lower() and "--fix" not in l - ): - pvs_flags_found = True - - assert clang_flags_found - assert cppcheck_flags_found - assert pvs_flags_found - - -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(""" -{ - "script": "addons/misra.py", - "args": ["--rule-texts=rules.txt"] -} -""") - - check_dir.join("rules.txt").write(""" -Appendix A Summary of guidelines -Rule 3.1 Required -R3.1 text. -Rule 4.1 Required -R4.1 text. -Rule 10.4 Mandatory -R10.4 text. -Rule 11.5 Advisory -R11.5 text. -Rule 15.5 Advisory -R15.5 text. -Rule 15.6 Required -R15.6 text. -Rule 17.7 Required -R17.7 text. -Rule 20.1 Advisory -R20.1 text. -Rule 21.3 Required -R21.3 Found MISRA defect -Rule 21.4 -R21.4 text. -""") - - result = clirunner.invoke( - cmd_check, ["--project-dir", str(check_dir), "--flags=--addon=misra.json"] - ) - - validate_cliresult(result) - assert "R21.3 Found MISRA defect" in result.output - assert not os.path.isfile(os.path.join(str(check_dir), "src", "main.cpp.dump")) - - -def test_check_fails_on_defects_only_with_flag(clirunner, validate_cliresult, tmpdir): - config = DEFAULT_CONFIG + "\ncheck_tool = cppcheck, clangtidy" - tmpdir.join("platformio.ini").write(config) - tmpdir.mkdir("src").join("main.cpp").write(TEST_CODE) - - default_result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir)]) - - result_with_flag = clirunner.invoke( - cmd_check, ["--project-dir", str(tmpdir), "--fail-on-defect=high"] - ) - - validate_cliresult(default_result) - assert result_with_flag.exit_code != 0 - - -def test_check_fails_on_defects_only_on_specified_level( - clirunner, validate_cliresult, tmpdir -): - config = DEFAULT_CONFIG + "\ncheck_tool = cppcheck, clangtidy" - tmpdir.join("platformio.ini").write(config) - tmpdir.mkdir("src").join("main.c").write(""" -#include - -void unused_function(){ - int unusedVar = 0; - int* iP = &unusedVar; - *iP++; -} - -int main() { -} -""") - - high_result = clirunner.invoke( - cmd_check, ["--project-dir", str(tmpdir), "--fail-on-defect=high"] - ) - validate_cliresult(high_result) - - low_result = clirunner.invoke( - cmd_check, ["--project-dir", str(tmpdir), "--fail-on-defect=low"] - ) - - assert low_result.exit_code != 0 - - -def test_check_pvs_studio_free_license(clirunner, tmpdir): - config = """ -[env:test] -platform = teensy -board = teensy35 -framework = arduino -check_tool = pvs-studio -""" - - tmpdir.join("platformio.ini").write(config) - tmpdir.mkdir("src").join("main.c").write(PVS_STUDIO_FREE_LICENSE_HEADER + TEST_CODE) - - result = clirunner.invoke( - cmd_check, ["--project-dir", str(tmpdir), "--fail-on-defect=high", "-v"] - ) - - errors, warnings, style = count_defects(result.output) - - assert result.exit_code != 0 - assert errors != 0 - assert warnings != 0 - assert style == 0 - - -def test_check_pvs_studio_fails_without_license(clirunner, tmpdir): - config = DEFAULT_CONFIG + "\ncheck_tool = pvs-studio" - - tmpdir.join("platformio.ini").write(config) - tmpdir.mkdir("src").join("main.c").write(TEST_CODE) - - default_result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir)]) - verbose_result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir), "-v"]) - - assert default_result.exit_code != 0 - assert "failed to perform check" in default_result.output.lower() - - assert verbose_result.exit_code != 0 - assert "license was not entered" in verbose_result.output.lower() - - -@pytest.mark.skipif( - sys.platform != "win32", - reason="For some reason the error message is different on Windows", -) -def test_check_pvs_studio_fails_broken_license(clirunner, tmpdir): - config = DEFAULT_CONFIG + """ -check_tool = pvs-studio -check_flags = --lic-file=./pvs-studio.lic -""" - - tmpdir.join("platformio.ini").write(config) - tmpdir.mkdir("src").join("main.c").write(TEST_CODE) - tmpdir.join("pvs-studio.lic").write(""" -TEST -TEST-TEST-TEST-TEST -""") - - default_result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir)]) - verbose_result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir), "-v"]) - - assert default_result.exit_code != 0 - assert "failed to perform check" in default_result.output.lower() - - assert verbose_result.exit_code != 0 - assert "license information is incorrect" in verbose_result.output.lower() - - -@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 = {framework} -check_tool = {check_tool} -""" - tmpdir.mkdir("src").join("main.c").write(PVS_STUDIO_FREE_LICENSE_HEADER + """ -#include - -void unused_function(int val){ - int unusedVar = 0; - int* iP = &unusedVar; - *iP++; -} - -int main() { -} -""") - - if framework == "zephyr": - zephyr_dir = tmpdir.mkdir("zephyr") - zephyr_dir.join("prj.conf").write("# nothing here") - zephyr_dir.join("CMakeLists.txt").write( - """cmake_minimum_required(VERSION 3.16.0) -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(hello_world) -target_sources(app PRIVATE ../src/main.c)""" - ) - - 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): - config = """ -[env:test] -platform = nordicnrf52 -board = nrf52_dk -framework = arduino -""" - - tmpdir.join("platformio.ini").write(config) - tmpdir.mkdir("src").join("main.c").write(TEST_CODE) - - result = clirunner.invoke( - cmd_check, ["--project-dir", str(tmpdir), "--skip-packages", "-v"] - ) - validate_cliresult(result) - - project_path = fs.to_unix_path(str(tmpdir)) - for line in result.output.split("\n"): - if not line.startswith("Includes:"): - continue - for inc in line.split(" "): - if inc.startswith("-I") and project_path not in inc: - pytest.fail("Detected an include path from packages: " + inc) - - -def test_check_multiline_error(clirunner, tmpdir_factory): - project_dir = tmpdir_factory.mktemp("project") - project_dir.join("platformio.ini").write(DEFAULT_CONFIG) - - project_dir.mkdir("include").join("main.h").write(""" -#error This is a multiline error message \\ -that should be correctly reported \\ -in both default and verbose modes. -""") - - project_dir.mkdir("src").join("main.c").write(""" -#include -#include "main.h" - -int main() {} -""") - - result = clirunner.invoke(cmd_check, ["--project-dir", str(project_dir)]) - errors, _, _ = count_defects(result.output) - - result = clirunner.invoke(cmd_check, ["--project-dir", str(project_dir), "-v"]) - verbose_errors, _, _ = count_defects(result.output) - - assert verbose_errors == errors == 1 - - -@pytest.mark.parametrize("check_tool", ["cppcheck", "clangtidy", "pvs-studio"]) -def test_check_handles_spaces_in_paths( - clirunner, validate_cliresult, tmpdir_factory, check_tool -): - package_dir_with_spaces = tmpdir_factory.mktemp("pio pkg dir") - project_dir_with_spaces = tmpdir_factory.mktemp("project dir") - config = f""" -[platformio] -; redirect toolchain and tool packages to a directory with whitespaces -packages_dir = {package_dir_with_spaces} - -[env:test] -platform = atmelsam -board = adafruit_feather_m0 -framework = arduino -check_tool = {check_tool} -""" - project_dir_with_spaces.join("platformio.ini").write(config) - project_dir_with_spaces.mkdir("src").join("main.cpp").write( - PVS_STUDIO_FREE_LICENSE_HEADER + TEST_CODE - ) - - result = clirunner.invoke( - cmd_check, ["--project-dir", str(project_dir_with_spaces), "-v"] - ) - - validate_cliresult(result) - - # Make sure toolchain defines were successfully extracted - if check_tool != "pvs-studio": - # PVS doesn't write defines to stdout - assert "__GNUC__" in result.output - - -# -# Files filtering functionality -# - - -@pytest.mark.parametrize( - "src_filter,number_of_checked_files", - [ - (["+"], 1), - (["+"], 1), - (["+", "-"], 2), - (["-<*> + + +"], 3), - ], - ids=["Single file", "Glob pattern", "Exclude pattern", "Filter as string"], -) -def test_check_src_filter( - clirunner, - validate_cliresult, - tmpdir_factory, - src_filter, - number_of_checked_files, -): - tmpdir = tmpdir_factory.mktemp("project") - tmpdir.join("platformio.ini").write(DEFAULT_CONFIG) - - src_dir = tmpdir.mkdir("src") - src_dir.join("main.cpp").write(TEST_CODE) - src_dir.join("app.cpp").write(TEST_CODE) - src_dir.mkdir("uart").join("uart.cpp").write(TEST_CODE) - src_dir.mkdir("spi").join("spi.cpp").write(TEST_CODE) - tmpdir.mkdir("tests").join("test.cpp").write(TEST_CODE) - - cmd_args = ["--project-dir", str(tmpdir)] + [ - "--src-filters=%s" % f for f in src_filter - ] - - result = clirunner.invoke(cmd_check, cmd_args) - validate_cliresult(result) - - errors, warnings, style = count_defects(result.output) - - assert errors + warnings + style == EXPECTED_DEFECTS * number_of_checked_files - - -def test_check_src_filter_from_config(clirunner, validate_cliresult, tmpdir_factory): - tmpdir = tmpdir_factory.mktemp("project") - - config = DEFAULT_CONFIG + """ -check_src_filters = - + - + - """ - tmpdir.join("platformio.ini").write(config) - - src_dir = tmpdir.mkdir("src") - src_dir.join("main.cpp").write(TEST_CODE) - src_dir.mkdir("spi").join("spi.cpp").write(TEST_CODE) - tmpdir.mkdir("tests").join("test.cpp").write(TEST_CODE) - - result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir)]) - validate_cliresult(result) - - errors, warnings, style = count_defects(result.output) - - assert errors + warnings + style == EXPECTED_DEFECTS * 2 - assert "main.cpp" not in result.output - - -def test_check_custom_pattern_absolute_path_legacy( - clirunner, validate_cliresult, tmpdir_factory -): - project_dir = tmpdir_factory.mktemp("project") - project_dir.join("platformio.ini").write(DEFAULT_CONFIG) - - check_dir = tmpdir_factory.mktemp("custom_src_dir") - check_dir.join("main.cpp").write(TEST_CODE) - - result = clirunner.invoke( - cmd_check, ["--project-dir", str(project_dir), "--pattern=" + str(check_dir)] - ) - - validate_cliresult(result) - - errors, warnings, style = count_defects(result.output) - - assert errors == EXPECTED_ERRORS - assert warnings == EXPECTED_WARNINGS - assert style == EXPECTED_STYLE - - -def test_check_custom_pattern_relative_path_legacy( - clirunner, validate_cliresult, tmpdir_factory -): - tmpdir = tmpdir_factory.mktemp("project") - tmpdir.join("platformio.ini").write(DEFAULT_CONFIG) - - src_dir = tmpdir.mkdir("src") - src_dir.join("main.cpp").write(TEST_CODE) - src_dir.mkdir("uart").join("uart.cpp").write(TEST_CODE) - src_dir.mkdir("spi").join("spi.cpp").write(TEST_CODE) - - result = clirunner.invoke( - cmd_check, - ["--project-dir", str(tmpdir), "--pattern=src/uart", "--pattern=src/spi"], - ) - validate_cliresult(result) - - errors, warnings, style = count_defects(result.output) - - assert errors + warnings + style == EXPECTED_DEFECTS * 2 - - -def test_check_src_filter_from_config_legacy( - clirunner, validate_cliresult, tmpdir_factory -): - tmpdir = tmpdir_factory.mktemp("project") - - config = DEFAULT_CONFIG + """ -check_patterns = - src/spi/*.c* - tests/test.cpp - """ - tmpdir.join("platformio.ini").write(config) - - src_dir = tmpdir.mkdir("src") - src_dir.join("main.cpp").write(TEST_CODE) - src_dir.mkdir("spi").join("spi.cpp").write(TEST_CODE) - tmpdir.mkdir("tests").join("test.cpp").write(TEST_CODE) - - result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir)]) - validate_cliresult(result) - - errors, warnings, style = count_defects(result.output) - - assert errors + warnings + style == EXPECTED_DEFECTS * 2 - assert "main.cpp" not in result.output - - -def test_check_src_filter_multiple_envs(clirunner, validate_cliresult, tmpdir_factory): - tmpdir = tmpdir_factory.mktemp("project") - - config = """ -[env] -check_tool = cppcheck -check_src_filters = - + - -[env:check_sources] -platform = native - -[env:check_tests] -platform = native -check_src_filters = - + - """ - tmpdir.join("platformio.ini").write(config) - - src_dir = tmpdir.mkdir("src") - src_dir.join("main.cpp").write(TEST_CODE) - src_dir.mkdir("spi").join("spi.cpp").write(TEST_CODE) - tmpdir.mkdir("test").join("test.cpp").write(TEST_CODE) - - result = clirunner.invoke( - cmd_check, ["--project-dir", str(tmpdir), "-e", "check_tests"] - ) - validate_cliresult(result) - - errors, warnings, style = count_defects(result.output) - - assert errors + warnings + style == EXPECTED_DEFECTS - assert "test.cpp" in result.output - assert "main.cpp" not in result.output - - -def test_check_sources_in_project_root(clirunner, validate_cliresult, tmpdir_factory): - tmpdir = tmpdir_factory.mktemp("project") - - config = """ -[platformio] -src_dir = ./ - """ + DEFAULT_CONFIG - tmpdir.join("platformio.ini").write(config) - tmpdir.join("main.cpp").write(TEST_CODE) - tmpdir.mkdir("spi").join("uart.cpp").write(TEST_CODE) - - result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir)]) - validate_cliresult(result) - - errors, warnings, style = count_defects(result.output) - - assert result.exit_code == 0 - assert errors + warnings + style == EXPECTED_DEFECTS * 2 - - -def test_check_sources_in_external_dir(clirunner, validate_cliresult, tmpdir_factory): - tmpdir = tmpdir_factory.mktemp("project") - external_src_dir = tmpdir_factory.mktemp("external_src_dir") - - config = f""" -[platformio] -src_dir = {external_src_dir} - """ + DEFAULT_CONFIG - tmpdir.join("platformio.ini").write(config) - external_src_dir.join("main.cpp").write(TEST_CODE) - - result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir)]) - validate_cliresult(result) - - errors, warnings, style = count_defects(result.output) - - assert result.exit_code == 0 - assert errors + warnings + style == EXPECTED_DEFECTS diff --git a/tests/commands/test_run.py b/tests/commands/test_run.py index 9250b7a6..fa5976ab 100644 --- a/tests/commands/test_run.py +++ b/tests/commands/test_run.py @@ -17,131 +17,9 @@ from pathlib import Path from platformio.run.cli import cli as cmd_run -def test_generic_build(clirunner, validate_cliresult, tmpdir): - build_flags = [ - ("-D TEST_INT=13", "-DTEST_INT=13"), - ("-DTEST_SINGLE_MACRO", "-DTEST_SINGLE_MACRO"), - ('-DTEST_STR_SPACE="Andrew Smith"', '"-DTEST_STR_SPACE=Andrew Smith"'), - ("-Iinclude", "-Iinclude"), - ("-include cpppath-include.h", "cpppath-include.h"), - ("-Iextra_inc", "-Iextra_inc"), - ("-Inon-existing-dir", "non-existing-dir"), - ( - "-include $PROJECT_DIR/lib/component/component-forced-include.h", - "component-forced-include.h", - ), - ] - - tmpdir.join("platformio.ini").write(""" -[env:native] -platform = native -extra_scripts = - pre:pre_script.py - post_script.py -lib_ldf_mode = deep+ -build_src_flags = -DI_AM_ONLY_SRC_FLAG -build_flags = - ; -DCOMMENTED_MACRO - %s ; inline comment - """ % " ".join([f[0] for f in build_flags])) - - tmpdir.join("pre_script.py").write(""" -Import("env") - -def post_prog_action(source, target, env): - print("post_prog_action is called") - -env.AddPostAction("$PROGPATH", post_prog_action) - """) - tmpdir.join("post_script.py").write(""" -Import("projenv") - -projenv.Append(CPPDEFINES="POST_SCRIPT_MACRO") - """) - - tmpdir.mkdir("extra_inc").join("foo.h").write(""" -#define FOO - """) - - tmpdir.mkdir("src").join("main.cpp").write(""" -#include "foo.h" - -#ifndef FOO -#error "FOO" -#endif - -#ifdef I_AM_ONLY_SRC_FLAG -#include -#else -#error "I_AM_ONLY_SRC_FLAG" -#endif - -#if !defined(TEST_INT) || TEST_INT != 13 -#error "TEST_INT" -#endif - -#ifndef TEST_STR_SPACE -#error "TEST_STR_SPACE" -#endif - -#ifndef I_AM_COMPONENT -#error "I_AM_COMPONENT" -#endif - -#ifndef POST_SCRIPT_MACRO -#error "POST_SCRIPT_MACRO" -#endif - -#ifndef I_AM_FORCED_COMPONENT_INCLUDE -#error "I_AM_FORCED_COMPONENT_INCLUDE" -#endif - -#ifndef I_AM_FORCED_CPPPATH_INCLUDE -#error "I_AM_FORCED_CPPPATH_INCLUDE" -#endif - -#ifdef COMMENTED_MACRO -#error "COMMENTED_MACRO" -#endif - -int main() { -} -""") - - tmpdir.mkdir("include").join("cpppath-include.h").write(""" -#define I_AM_FORCED_CPPPATH_INCLUDE -""") - component_dir = tmpdir.mkdir("lib").mkdir("component") - component_dir.join("component.h").write(""" -#define I_AM_COMPONENT - -#ifndef I_AM_ONLY_SRC_FLAG -#error "I_AM_ONLY_SRC_FLAG" -#endif - -void dummy(void); - """) - component_dir.join("component.cpp").write(""" -#ifdef I_AM_ONLY_SRC_FLAG -#error "I_AM_ONLY_SRC_FLAG" -#endif - -void dummy(void ) {}; - """) - component_dir.join("component-forced-include.h").write(""" -#define I_AM_FORCED_COMPONENT_INCLUDE - """) - - result = clirunner.invoke(cmd_run, ["--project-dir", str(tmpdir), "--verbose"]) - validate_cliresult(result) - assert "post_prog_action is called" in result.output - build_output = result.output[result.output.find("Scanning dependencies...") :] - for flag in build_flags: - assert flag[1] in build_output, flag - - def test_build_unflags(clirunner, validate_cliresult, tmpdir): - tmpdir.join("platformio.ini").write(""" + tmpdir.join("platformio.ini").write( + """ [env:native] platform = native build_unflags = @@ -155,9 +33,11 @@ build_unflags = build_flags = -DTMP_MACRO_3=10 extra_scripts = pre:extra.py -""") +""" + ) - tmpdir.join("extra.py").write(""" + tmpdir.join("extra.py").write( + """ Import("env") env.Append(CPPPATH="%s") env.Append(CPPDEFINES="TMP_MACRO_1") @@ -166,9 +46,12 @@ env.Append(CPPDEFINES=[("TMP_MACRO_3", 13)]) env.Append(CPPDEFINES=[("TMP_MACRO_4", 4)]) env.Append(CCFLAGS=["-Os"]) env.Append(LIBS=["unknownLib"]) - """ % str(tmpdir)) + """ + % str(tmpdir) + ) - tmpdir.mkdir("src").join("main.c").write(""" + tmpdir.mkdir("src").join("main.c").write( + """ #ifndef TMP_MACRO_1 #error "TMP_MACRO_1 should be defined" #endif @@ -187,7 +70,8 @@ env.Append(LIBS=["unknownLib"]) int main() { } -""") +""" + ) result = clirunner.invoke(cmd_run, ["--project-dir", str(tmpdir), "--verbose"]) validate_cliresult(result) @@ -198,16 +82,20 @@ int main() { def test_debug_default_build_flags(clirunner, validate_cliresult, tmpdir): - tmpdir.join("platformio.ini").write(""" + tmpdir.join("platformio.ini").write( + """ [env:native] platform = native build_type = debug -""") +""" + ) - tmpdir.mkdir("src").join("main.c").write(""" + tmpdir.mkdir("src").join("main.c").write( + """ int main() { } -""") +""" + ) result = clirunner.invoke(cmd_run, ["--project-dir", str(tmpdir), "--verbose"]) validate_cliresult(result) @@ -226,17 +114,22 @@ int main() { def test_debug_custom_build_flags(clirunner, validate_cliresult, tmpdir): custom_debug_build_flags = ("-O3", "-g3", "-ggdb3") - tmpdir.join("platformio.ini").write(""" + tmpdir.join("platformio.ini").write( + """ [env:native] platform = native build_type = debug debug_build_flags = %s - """ % " ".join(custom_debug_build_flags)) + """ + % " ".join(custom_debug_build_flags) + ) - tmpdir.mkdir("src").join("main.c").write(""" + tmpdir.mkdir("src").join("main.c").write( + """ int main() { } -""") +""" + ) result = clirunner.invoke(cmd_run, ["--project-dir", str(tmpdir), "--verbose"]) validate_cliresult(result) @@ -255,20 +148,25 @@ int main() { def test_symlinked_libs(clirunner, validate_cliresult, tmp_path: Path): external_pkg_dir = tmp_path / "External" external_pkg_dir.mkdir() - (external_pkg_dir / "External.h").write_text(""" + (external_pkg_dir / "External.h").write_text( + """ #define EXTERNAL 1 -""") - (external_pkg_dir / "library.json").write_text(""" +""" + ) + (external_pkg_dir / "library.json").write_text( + """ { "name": "External", "version": "1.0.0" } -""") +""" + ) project_dir = tmp_path / "project" src_dir = project_dir / "src" src_dir.mkdir(parents=True) - (src_dir / "main.c").write_text(""" + (src_dir / "main.c").write_text( + """ #include # #if !defined(EXTERNAL) @@ -277,12 +175,15 @@ def test_symlinked_libs(clirunner, validate_cliresult, tmp_path: Path): int main() { } -""") - (project_dir / "platformio.ini").write_text(""" +""" + ) + (project_dir / "platformio.ini").write_text( + """ [env:native] platform = native lib_deps = symlink://../External - """) + """ + ) result = clirunner.invoke(cmd_run, ["--project-dir", str(project_dir)]) validate_cliresult(result) @@ -291,7 +192,8 @@ def test_stringification(clirunner, validate_cliresult, tmp_path: Path): project_dir = tmp_path / "project" src_dir = project_dir / "src" src_dir.mkdir(parents=True) - (src_dir / "main.c").write_text(""" + (src_dir / "main.c").write_text( + """ #include int main(void) { printf("MACRO_1=<%s>\\n", MACRO_1); @@ -300,23 +202,28 @@ int main(void) { printf("MACRO_4=<%s>\\n", MACRO_4); return(0); } -""") - (project_dir / "platformio.ini").write_text(""" +""" + ) + (project_dir / "platformio.ini").write_text( + """ [env:native] platform = native extra_scripts = script.py build_flags = '-DMACRO_1="Hello World!"' '-DMACRO_2="Text is \\\\"Quoted\\\\""' - """) - (project_dir / "script.py").write_text(""" + """ + ) + (project_dir / "script.py").write_text( + """ Import("projenv") projenv.Append(CPPDEFINES=[ ("MACRO_3", projenv.StringifyMacro('Hello "World"! Isn\\'t true?')), ("MACRO_4", projenv.StringifyMacro("Special chars: ',(,),[,],:")) ]) - """) + """ + ) result = clirunner.invoke( cmd_run, ["--project-dir", str(project_dir), "-t", "exec"] ) @@ -334,9 +241,11 @@ def test_ldf(clirunner, validate_cliresult, tmp_path: Path): lib_dir = project_dir / "lib" a_lib_dir = lib_dir / "a" a_lib_dir.mkdir(parents=True) - (a_lib_dir / "a.h").write_text(""" + (a_lib_dir / "a.h").write_text( + """ #include -""") +""" + ) # b b_lib_dir = lib_dir / "b" b_lib_dir.mkdir(parents=True) @@ -344,19 +253,25 @@ def test_ldf(clirunner, validate_cliresult, tmp_path: Path): # c c_lib_dir = lib_dir / "c" c_lib_dir.mkdir(parents=True) - (c_lib_dir / "parse_c_by_name.h").write_text(""" + (c_lib_dir / "parse_c_by_name.h").write_text( + """ void some_func(); - """) - (c_lib_dir / "parse_c_by_name.c").write_text(""" + """ + ) + (c_lib_dir / "parse_c_by_name.c").write_text( + """ #include #include void some_func() { } - """) - (c_lib_dir / "some.c").write_text(""" + """ + ) + (c_lib_dir / "some.c").write_text( + """ #include - """) + """ + ) # d d_lib_dir = lib_dir / "d" d_lib_dir.mkdir(parents=True) @@ -365,19 +280,25 @@ void some_func() { # project src_dir = project_dir / "src" src_dir.mkdir(parents=True) - (src_dir / "main.h").write_text(""" + (src_dir / "main.h").write_text( + """ #include #include -""") - (src_dir / "main.c").write_text(""" +""" + ) + (src_dir / "main.c").write_text( + """ #include int main() { } -""") - (project_dir / "platformio.ini").write_text(""" +""" + ) + (project_dir / "platformio.ini").write_text( + """ [env:native] platform = native - """) + """ + ) result = clirunner.invoke(cmd_run, ["--project-dir", str(project_dir)]) validate_cliresult(result) diff --git a/tests/package/test_manager.py b/tests/package/test_manager.py index ae72eeef..88dbf2a9 100644 --- a/tests/package/test_manager.py +++ b/tests/package/test_manager.py @@ -95,13 +95,15 @@ def test_build_legacy_spec(isolated_pio_core, tmpdir_factory): pm = PlatformPackageManager(str(storage_dir)) # test src manifest pkg1_dir = storage_dir.join("pkg-1").mkdir() - pkg1_dir.join(".pio").mkdir().join(".piopkgmanager.json").write(""" + pkg1_dir.join(".pio").mkdir().join(".piopkgmanager.json").write( + """ { "name": "StreamSpy-0.0.1.tar", "url": "https://dl.platformio.org/e8936b7/StreamSpy-0.0.1.tar.gz", "requirements": null } -""") +""" + ) assert pm.build_legacy_spec(str(pkg1_dir)) == PackageSpec( name="StreamSpy-0.0.1.tar", uri="https://dl.platformio.org/e8936b7/StreamSpy-0.0.1.tar.gz", @@ -179,10 +181,12 @@ def test_install_from_uri(isolated_pio_core, tmpdir_factory): # install from registry src_dir = tmp_dir.join("registry-1").mkdir() - src_dir.join("library.properties").write(""" + src_dir.join("library.properties").write( + """ name = wifilib version = 5.2.7 -""") +""" + ) spec = PackageSpec("company/wifilib @ ^5") pkg = lm.install_from_uri("file://%s" % src_dir, spec) assert str(pkg.metadata.version) == "5.2.7" @@ -234,40 +238,6 @@ def test_install_from_registry(isolated_pio_core, tmpdir_factory): tm.install("owner/unknown-package-tool") -def test_install_lib_depndencies(isolated_pio_core, tmpdir_factory): - tmp_dir = tmpdir_factory.mktemp("tmp") - - src_dir = tmp_dir.join("lib-with-deps").mkdir() - root_dir = src_dir.mkdir("root") - root_dir.mkdir("src").join("main.cpp").write("#include ") - root_dir.join("library.json").write(""" -{ - "name": "lib-with-deps", - "version": "2.0.0", - "dependencies": [ - { - "owner": "bblanchon", - "name": "ArduinoJson", - "version": "^6.16.1" - }, - { - "name": "external-repo", - "version": "https://github.com/milesburton/Arduino-Temperature-Control-Library.git#4a0ccc1" - } - ] -} -""") - - lm = LibraryPackageManager(str(tmpdir_factory.mktemp("lib-storage"))) - lm.set_log_level(logging.ERROR) - lm.install("file://%s" % str(src_dir)) - installed = lm.get_installed() - assert len(installed) == 4 - assert set(["external-repo", "ArduinoJson", "lib-with-deps", "OneWire"]) == set( - p.metadata.name for p in installed - ) - - def test_install_force(isolated_pio_core, tmpdir_factory): lm = LibraryPackageManager(str(tmpdir_factory.mktemp("lib-storage"))) lm.set_log_level(logging.ERROR) @@ -287,22 +257,26 @@ def test_install_force(isolated_pio_core, tmpdir_factory): def test_symlink(tmp_path: Path): external_pkg_dir = tmp_path / "External" external_pkg_dir.mkdir() - (external_pkg_dir / "library.json").write_text(""" + (external_pkg_dir / "library.json").write_text( + """ { "name": "External", "version": "1.0.0" } -""") +""" + ) storage_dir = tmp_path / "storage" installed_pkg_dir = storage_dir / "installed" installed_pkg_dir.mkdir(parents=True) - (installed_pkg_dir / "library.json").write_text(""" + (installed_pkg_dir / "library.json").write_text( + """ { "name": "Installed", "version": "1.0.0" } -""") +""" + ) spec = "CustomExternal=symlink://%s" % str(external_pkg_dir) lm = LibraryPackageManager(str(storage_dir)) @@ -343,7 +317,8 @@ def test_scripts(isolated_pio_core, tmp_path: Path): pkg_dir = tmp_path / "foo" scripts_dir = pkg_dir / "scripts" scripts_dir.mkdir(parents=True) - (scripts_dir / "script.py").write_text(""" + (scripts_dir / "script.py").write_text( + """ import sys from pathlib import Path @@ -352,8 +327,10 @@ Path("%s.flag" % action).touch() if action == "preuninstall": Path("../%s.flag" % action).touch() -""") - (pkg_dir / "library.json").write_text(""" +""" + ) + (pkg_dir / "library.json").write_text( + """ { "name": "foo", "version": "1.0.0", @@ -362,7 +339,8 @@ if action == "preuninstall": "preuninstall2": ["scripts/script.py", "preuninstall"] } } -""") +""" + ) storage_dir = tmp_path / "storage" lm = LibraryPackageManager(str(storage_dir)) @@ -378,7 +356,8 @@ def test_install_circular_dependencies(tmp_path: Path): # Foo pkg_dir = storage_dir / "foo" pkg_dir.mkdir(parents=True) - (pkg_dir / "library.json").write_text(""" + (pkg_dir / "library.json").write_text( + """ { "name": "Foo", "version": "1.0.0", @@ -386,11 +365,13 @@ def test_install_circular_dependencies(tmp_path: Path): "Bar": "*" } } -""") +""" + ) # Bar pkg_dir = storage_dir / "bar" pkg_dir.mkdir(parents=True) - (pkg_dir / "library.json").write_text(""" + (pkg_dir / "library.json").write_text( + """ { "name": "Bar", "version": "1.0.0", @@ -398,7 +379,8 @@ def test_install_circular_dependencies(tmp_path: Path): "Foo": "*" } } -""") +""" + ) lm = LibraryPackageManager(str(storage_dir)) lm.set_log_level(logging.ERROR) @@ -407,7 +389,8 @@ def test_install_circular_dependencies(tmp_path: Path): # root library pkg_dir = tmp_path / "root" pkg_dir.mkdir(parents=True) - (pkg_dir / "library.json").write_text(""" + (pkg_dir / "library.json").write_text( + """ { "name": "Root", "version": "1.0.0", @@ -416,7 +399,8 @@ def test_install_circular_dependencies(tmp_path: Path): "Bar": "^1.0.0" } } -""") +""" + ) lm.install("file://%s" % str(pkg_dir)) @@ -425,7 +409,14 @@ def test_get_installed(isolated_pio_core, tmpdir_factory): pm = ToolPackageManager(str(storage_dir)) # VCS package - (storage_dir.join("pkg-vcs").mkdir().join(".git").mkdir().join(".piopm").write(""" + ( + storage_dir.join("pkg-vcs") + .mkdir() + .join(".git") + .mkdir() + .join(".piopm") + .write( + """ { "name": "pkg-via-vcs", "spec": { @@ -438,7 +429,9 @@ def test_get_installed(isolated_pio_core, tmpdir_factory): "type": "tool", "version": "0.0.0+sha.1ea4d5e" } -""")) +""" + ) + ) # package without metadata file ( @@ -451,7 +444,8 @@ def test_get_installed(isolated_pio_core, tmpdir_factory): # package with metadata file foo_dir = storage_dir.join("foo").mkdir() foo_dir.join("package.json").write('{"name": "foo", "version": "3.6.0"}') - foo_dir.join(".piopm").write(""" + foo_dir.join(".piopm").write( + """ { "name": "foo", "spec": { @@ -462,7 +456,8 @@ def test_get_installed(isolated_pio_core, tmpdir_factory): "type": "tool", "version": "3.6.0" } -""") +""" + ) # test "system" storage_dir.join("pkg-incompatible-system").mkdir().join("package.json").write( diff --git a/tests/package/test_manifest.py b/tests/package/test_manifest.py index eed705af..3c58d891 100644 --- a/tests/package/test_manifest.py +++ b/tests/package/test_manifest.py @@ -294,160 +294,6 @@ maintainer=Rocket Scream Electronics assert "keywords" not in data -def test_library_json_schema(): - contents = """ -{ - "name": "ArduinoJson", - "keywords": "JSON, rest, http, web", - "description": "An elegant and efficient JSON library for embedded systems", - "homepage": "https://arduinojson.org", - "repository": { - "type": "git", - "url": "https://github.com/bblanchon/ArduinoJson.git" - }, - "version": "6.12.0", - "authors": { - "name": "Benoit Blanchon", - "url": "https://blog.benoitblanchon.fr" - }, - "downloadUrl": "https://example.com/package.tar.gz", - "exclude": [ - "fuzzing", - "scripts", - "test", - "third-party" - ], - "frameworks": "arduino", - "platforms": "*", - "license": "MIT", - "scripts": { - "postinstall": "script.py" - }, - "examples": [ - { - "name": "JsonConfigFile", - "base": "examples/JsonConfigFile", - "files": ["JsonConfigFile.ino"] - }, - { - "name": "JsonHttpClient", - "base": "examples/JsonHttpClient", - "files": ["JsonHttpClient.ino"] - } - ], - "dependencies": [ - {"name": "deps1", "version": "1.0.0"}, - {"name": "@owner/deps2", "version": "1.0.0", "frameworks": "arduino"}, - {"name": "deps3", "version": "1.0.0", "platforms": ["ststm32", "sifive"]} - ] -} -""" - raw_data = parser.ManifestParserFactory.new( - contents, parser.ManifestFileType.LIBRARY_JSON - ).as_dict() - raw_data["dependencies"] = sorted(raw_data["dependencies"], key=lambda a: a["name"]) - - data = ManifestSchema().load_manifest(raw_data) - - assert data["repository"]["url"] == "https://github.com/bblanchon/ArduinoJson.git" - assert data["examples"][1]["base"] == "examples/JsonHttpClient" - assert data["examples"][1]["files"] == ["JsonHttpClient.ino"] - - assert not jsondiff.diff( - data, - { - "name": "ArduinoJson", - "keywords": ["json", "rest", "http", "web"], - "description": "An elegant and efficient JSON library for embedded systems", - "homepage": "https://arduinojson.org", - "repository": { - "url": "https://github.com/bblanchon/ArduinoJson.git", - "type": "git", - }, - "version": "6.12.0", - "authors": [ - {"name": "Benoit Blanchon", "url": "https://blog.benoitblanchon.fr"} - ], - "downloadUrl": "https://example.com/package.tar.gz", - "export": {"exclude": ["fuzzing", "scripts", "test", "third-party"]}, - "frameworks": ["arduino"], - "platforms": ["*"], - "license": "MIT", - "scripts": {"postinstall": "script.py"}, - "examples": [ - { - "name": "JsonConfigFile", - "base": "examples/JsonConfigFile", - "files": ["JsonConfigFile.ino"], - }, - { - "name": "JsonHttpClient", - "base": "examples/JsonHttpClient", - "files": ["JsonHttpClient.ino"], - }, - ], - "dependencies": [ - {"name": "@owner/deps2", "version": "1.0.0", "frameworks": ["arduino"]}, - {"name": "deps1", "version": "1.0.0"}, - { - "name": "deps3", - "version": "1.0.0", - "platforms": ["ststm32", "sifive"], - }, - ], - }, - ) - - # legacy dependencies format - contents = """ -{ - "name": "DallasTemperature", - "version": "3.8.0", - "dependencies": - { - "name": "OneWire", - "authors": "Paul Stoffregen", - "frameworks": "arduino" - } -} -""" - raw_data = parser.LibraryJsonManifestParser(contents).as_dict() - data = ManifestSchema().load_manifest(raw_data) - assert not jsondiff.diff( - data, - { - "name": "DallasTemperature", - "version": "3.8.0", - "dependencies": [ - { - "name": "OneWire", - "authors": ["Paul Stoffregen"], - "frameworks": ["arduino"], - } - ], - }, - ) - - # test multiple licenses - contents = """ -{ - "name": "MultiLicense", - "version": "1.0.0", - "license": "MIT AND (LGPL-2.1-or-later OR BSD-3-Clause)" -} -""" - raw_data = parser.LibraryJsonManifestParser(contents).as_dict() - data = ManifestSchema().load_manifest(raw_data) - assert not jsondiff.diff( - data, - { - "name": "MultiLicense", - "version": "1.0.0", - "license": "MIT AND (LGPL-2.1-or-later OR BSD-3-Clause)", - }, - ) - - def test_library_properties_schema(): contents = """ name=U8glib @@ -653,65 +499,6 @@ def test_platform_json_schema(): ) -def test_package_json_schema(): - contents = """ -{ - "name": "tool-scons", - "description": "SCons software construction tool", - "keywords": "SCons, build", - "homepage": "http://www.scons.org", - "system": ["linux_armv6l", "linux_armv7l", "linux_armv8l", "LINUX_ARMV7L"], - "version": "3.30101.0" -} -""" - raw_data = parser.ManifestParserFactory.new( - contents, parser.ManifestFileType.PACKAGE_JSON - ).as_dict() - - data = ManifestSchema().load_manifest(raw_data) - - assert not jsondiff.diff( - data, - { - "name": "tool-scons", - "description": "SCons software construction tool", - "keywords": ["scons", "build"], - "homepage": "http://www.scons.org", - "system": ["linux_armv6l", "linux_armv7l", "linux_armv8l"], - "version": "3.30101.0", - }, - ) - - mp = parser.ManifestParserFactory.new( - '{"system": "*"}', parser.ManifestFileType.PACKAGE_JSON - ) - assert "system" not in mp.as_dict() - - mp = parser.ManifestParserFactory.new( - '{"system": "all"}', parser.ManifestFileType.PACKAGE_JSON - ) - assert "system" not in mp.as_dict() - - mp = parser.ManifestParserFactory.new( - '{"system": "darwin_x86_64"}', parser.ManifestFileType.PACKAGE_JSON - ) - assert mp.as_dict()["system"] == ["darwin_x86_64"] - - # shortcut repository syntax (npm-style) - contents = """ -{ - "name": "tool-github", - "version": "1.2.0", - "repository": "github:user/repo" -} -""" - raw_data = parser.ManifestParserFactory.new( - contents, parser.ManifestFileType.PACKAGE_JSON - ).as_dict() - data = ManifestSchema().load_manifest(raw_data) - assert data["repository"]["url"] == "https://github.com/user/repo.git" - - def test_parser_from_dir(tmpdir_factory): pkg_dir = tmpdir_factory.mktemp("package") pkg_dir.join("package.json").write('{"name": "package.json"}') diff --git a/tox.ini b/tox.ini index 61a8811b..792ab924 100644 --- a/tox.ini +++ b/tox.ini @@ -54,21 +54,3 @@ commands = commands = {envpython} scripts/install_devplatforms.py py.test -v --basetemp={envtmpdir} tests/test_examples.py - -[testenv:docs] -deps = - sphinx-rtd-theme==3.0.2 - sphinxcontrib-googleanalytics - sphinx-notfound-page - sphinx-copybutton - restructuredtext-lint -change_dir = docs -commands = - sphinx-build -b html . _build/html - -[testenv:docslinkcheck] -deps = - {[testenv:docs]deps} -change_dir = docs -commands = - sphinx-build -b linkcheck . _build