diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index e566e02cd4..445e6e0eaa 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -7,13 +7,8 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"] - exclude: - - os: macos-latest - python-version: "3.6" - - os: windows-latest - python-version: "3.10" + os: [ubuntu-20.04, windows-latest, macos-latest] + python-version: ["3.6", "3.9", "3.11"] runs-on: ${{ matrix.os }} @@ -23,7 +18,7 @@ jobs: submodules: "recursive" - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 9d652a7d30..ff353c31b8 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -17,7 +17,7 @@ jobs: submodules: "recursive" - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: "3.9" diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index f11b000608..2765b55d55 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -7,13 +7,13 @@ jobs: name: Build Docs runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: "recursive" - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: - python-version: 3.7 + python-version: 3.9 - name: Install dependencies run: | python -m pip install --upgrade pip @@ -40,7 +40,7 @@ jobs: - name: Save artifact if: ${{ github.event_name == 'push' }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: docs path: ./docs.tar.gz @@ -57,7 +57,7 @@ jobs: if: ${{ github.event_name == 'push' }} steps: - name: Download artifact - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: docs - name: Unpack artifact @@ -78,7 +78,7 @@ jobs: fi - name: Checkout latest Docs continue-on-error: true - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: ${{ env.DOCS_REPO }} path: ${{ env.DOCS_DIR }} diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 115817c40b..6bb258e04c 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -20,7 +20,7 @@ jobs: submodules: "recursive" - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: "3.9" diff --git a/.github/workflows/projects.yml b/.github/workflows/projects.yml index 34c3014492..080b8162a1 100644 --- a/.github/workflows/projects.yml +++ b/.github/workflows/projects.yml @@ -32,7 +32,7 @@ jobs: repository: "1technophile/OpenMQTTGateway" folder: "OpenMQTTGateway" config_dir: "OpenMQTTGateway" - env_name: "esp32-m5atom" + env_name: "esp32-m5atom-lite" os: [ubuntu-latest, windows-latest, macos-latest] exclude: - os: windows-latest @@ -45,7 +45,7 @@ jobs: submodules: "recursive" - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: 3.9 @@ -53,7 +53,7 @@ jobs: run: pip install -U . - name: Check out ${{ matrix.project.repository }} - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: "recursive" repository: ${{ matrix.project.repository }} diff --git a/HISTORY.rst b/HISTORY.rst index 1068c138fb..b963df382e 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -2,6 +2,7 @@ Release Notes ============= .. |PIOCONF| replace:: `"platformio.ini" `__ configuration file +.. |LIBRARYJSON| replace:: `library.json `__ .. |LDF| replace:: `LDF `__ .. |INTERPOLATION| replace:: `Interpolation of Values `__ .. |UNITTESTING| replace:: `Unit Testing `__ @@ -13,6 +14,19 @@ PlatformIO Core 6 **A professional collaborative platform for declarative, safety-critical, and test-driven embedded development.** +6.1.6 (2023-01-23) +~~~~~~~~~~~~~~~~~~ + +* Added support for Python 3.11 +* Added a new `name `__ configuration option to customize a project name (`pull #4498 `_) +* Made assets (templates, ``99-platformio-udev.rules``) part of Python's module (`issue #4458 `_) +* Updated `Clang-Tidy `__ check tool to v15.0.5 with new diagnostics and bugfixes +* Removed dependency on the "zeroconf" package and install it only when a user lists mDNS devices (issue with zeroconf's LGPL license) +* Show the real error message instead of "Can not remove temporary directory" when |PIOCONF| is broken (`issue #4480 `_) +* Fixed an issue with an incorrect test summary when a testcase name includes a colon (`issue #4508 `_) +* Fixed an issue when `extends `__ did not override options in the right order (`issue #4462 `_) +* Fixed an issue when `pio pkg list `__ and `pio pkg uninstall `__ commands fail if there are circular dependencies in the |LIBRARYJSON| manifests (`issue #4475 `_) + 6.1.5 (2022-11-01) ~~~~~~~~~~~~~~~~~~ @@ -46,7 +60,7 @@ PlatformIO Core 6 * Export a ``PIO_UNIT_TESTING`` macro to the project source files and dependent libraries in the |UNITTESTING| mode * Improved detection of Windows architecture (`issue #4353 `_) * Warn about unknown `device monitor filters `__ (`issue #4362 `_) -* Fixed a regression bug when `libArchive `__ option declared in the `library.json `__ manifest was ignored (`issue #4351 `_) +* Fixed a regression bug when `libArchive `__ option declared in the |LIBRARYJSON| manifest was ignored (`issue #4351 `_) * Fixed an issue when the `pio pkg publish `__ command didn't work with Python 3.6 (`issue #4352 `_) 6.1.1 (2022-07-11) diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 1aba38f67a..0000000000 --- a/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include LICENSE diff --git a/docs b/docs index f82e7f4266..95c339a711 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit f82e7f42668b0f27963ba21792eb72f2504582de +Subproject commit 95c339a71162dc5bd28090f263e641a563229888 diff --git a/platformio/__init__.py b/platformio/__init__.py index 01be812642..08d95a7985 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (6, 1, 5) +VERSION = (6, 1, 6) __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" @@ -49,7 +49,7 @@ "contrib-pysite": "~2.%d%d.0" % (sys.version_info.major, sys.version_info.minor), "tool-scons": "~4.40400.0", "tool-cppcheck": "~1.270.0", - "tool-clangtidy": "~1.120001.0", + "tool-clangtidy": "~1.150005.0", "tool-pvs-studio": "~7.18.0", } diff --git a/platformio/assets/schema/library.json b/platformio/assets/schema/library.json new file mode 100644 index 0000000000..370cf67f17 --- /dev/null +++ b/platformio/assets/schema/library.json @@ -0,0 +1,487 @@ +{ + "$id": "https://example.com/library.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "library.json schema", + "type": "object", + "properties": { + "name": { + "type": "string", + "maxLength": 50, + "description": "A name of a library.\nMust be unique in the PlatformIO Registry\nShould be slug style for simplicity, consistency, and compatibility. Example: HelloWorld\nCan contain a-z, digits, and dashes (but not start/end with them)\nConsecutive dashes and [:;/,@<>] chars are not allowed.", + "required": true + }, + "version": { + "type": "string", + "maxLength": 20, + "description": "A version of a current library source code. Can contain a-z, digits, dots or dash and should be Semantic Versioning compatible.", + "required": true + }, + "description": { + "type": "string", + "maxLength": 255, + "description": "The field helps users to identify and search for your library with a brief description. Describe the hardware devices (sensors, boards and etc.) which are suitable with it.", + "required": true + }, + "keywords": { + "anyOf": [ + { + "type": "string", + "maxLength": 255 + }, + { + "type": "array", + "items": { + "type": "string", + "maxLength": 255 + } + } + ], + "description": "Used for search by keyword. Helps to make your library easier to discover without people needing to know its name.\nThe keyword should be lowercased, can contain a-z, digits and dash (but not start/end with them). A list from the keywords can be specified with separator , or declared as Array.", + "required": true + }, + "homepage": { + "type": "string", + "maxLength": 255, + "description": "Home page of a library (if is different from repository url).", + "required": false + }, + "repository": { + "type": "object", + "properties": { + "type": { + "enum": [ + "git", + "hg", + "svn" + ], + "description": "only “git”, “hg” or “svn” are supported" + }, + "url": { + "type": "string" + }, + "branch": { + "type": "string", + "description": "if is not specified, default branch will be used. This field will be ignored if tag/release exists with the value of version." + } + }, + "description": "The repository in which the source code can be found.", + "required": false + }, + "authors": { + "anyOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "required": true, + "description": "Full name" + }, + "email": { + "type": "string" + }, + "url": { + "type": "string", + "description": "An author’s contact page" + }, + "maintainer": { + "type": "boolean", + "description": "Specify “maintainer” status" + } + } + }, + { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "required": true, + "description": "Full name" + }, + "email": { + "type": "string" + }, + "url": { + "type": "string", + "description": "An author’s contact page" + }, + "maintainer": { + "type": "boolean", + "description": "Specify “maintainer” status" + } + } + } + } + ], + "description": "An author contact information\nIf authors field is not defined, PlatformIO will try to fetch data from VCS provider (Github, Gitlab, etc) if repository is declared.", + "required": false + }, + "license": { + "type": "string", + "description": "A SPDX license ID or SPDX Expression. You can check the full list of SPDX license IDs (see “Identifier” column).", + "required": false + }, + "frameworks": { + "anyOf": [ + { + "type": "string", + "description": "espidf, freertos, *, etc'" + }, + { + "type": "array", + "items": { + "type": "string", + "description": "espidf, freertos, *, etc'" + } + } + ], + "description": "A list with compatible frameworks. The available framework names are defined in the Frameworks section.\nIf the library is compatible with the all frameworks, then do not declare this field or you use *", + "required": false + }, + "platforms": { + "anyOf": [ + { + "type": "string", + "description": "atmelavr, espressif8266, *, etc'" + }, + { + "type": "array", + "items": { + "type": "string", + "description": "atmelavr, espressif8266, *, etc'" + } + } + ], + "description": "A list with compatible development platforms. The available platform name are defined in Development Platforms section.\nIf the library is compatible with the all platforms, then do not declare this field or use *.\nPlatformIO does not check platforms for compatibility in default mode. See Compatibility Mode for details. If you need a strict checking for compatible platforms for a library, please set libCompatMode to strict.", + "required": false + }, + "headers": { + "anyOf": [ + { + "type": "string", + "description": "MyLibrary.h" + }, + { + "type": "array", + "items": { + "type": "string", + "description": "FooCore.h, FooFeature.h" + } + } + ], + "description": "A list of header files that can be included in a project source files using #include <...> directive.", + "required": false + }, + "examples": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "base": { + "type": "string" + }, + "files": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "description": "A list of example patterns.", + "required": "false" + }, + "dependencies": { + "anyOf": [ + { + "type": "object", + "properties": { + "owner": { + "type": "string", + "description": "an owner name (username) from the PlatformIO Registry" + }, + "name": { + "type": "string", + "description": "library name" + }, + "version": { + "type": "string", + "description": "Version Requirements or Package Specifications" + }, + "frameworks": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "project compatible Frameworks" + }, + "platforms": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": " project compatible Development Platforms" + } + } + }, + { + "type": "array", + "items": { + "type": "object", + "properties": { + "owner": { + "type": "string", + "description": "an owner name (username) from the PlatformIO Registry" + }, + "name": { + "type": "string", + "description": "library name" + }, + "version": { + "type": "string", + "description": "Version Requirements or Package Specifications" + }, + "frameworks": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "project compatible Frameworks" + }, + "platforms": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": " project compatible Development Platforms" + } + } + } + } + ], + "description": "A list of dependent libraries that will be automatically installed.", + "required": false + }, + "export": { + "type": "object", + "properties": { + "include": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Export only files that matched declared patterns.\n* - matches everything\n? - matches any single character\n[seq] - matches any character in seq\n[!seq] - matches any character not in seq" + }, + "exclude": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Exclude the directories and files which match with exclude patterns." + } + }, + "description": "This option is useful if you need to exclude extra data (test code, docs, images, PDFs, etc). It allows one to reduce the size of the final archive.\nTo check which files will be included in the final packages, please use pio pkg pack command.", + "required": false + }, + "scripts": { + "type": "object", + "properties": { + "postinstall": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "runs a script AFTER the package has been installed.\nRun a custom Python script located in the package “scripts” folder AFTER the package is installed. Please note that you don’t need to specify a Python interpreter for Python scripts" + }, + "preuninstall": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "runs a script BEFORE the package is removed.\nRun a custom Bash script BEFORE the package is uninstalled. The script is declared as a list of command arguments and is located at the root of a package" + } + }, + "description": "Execute custom scripts during the special Package Management CLI life cycle events", + "required": false + }, + "build": { + "type": "object", + "properties": { + "flags": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Extra flags to control preprocessing, compilation, assembly, and linking processes. More details build_flags.\nKeep in mind when operating with the -I flag (directories to be searched for header files). The path should be relative to the root directory where the library.json manifest is located." + }, + "unflags": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Remove base/initial flags which were set by development platform. More details build_unflags." + }, + "includeDir": { + "type": "string", + "description": "Custom directory to be searched for header files. A default value is include and means that folder is located at the root of a library.\nThe Library Dependency Finder (LDF) will pick a library automatically only when a project or other dependent libraries include any header file located in includeDir or srcDir.", + "required": false + }, + "srcDir": { + "type": "string", + "description": "Custom location of library source code. A default value is src and means that folder is located in the root of a library.", + "required": "false" + }, + "srcFilter": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Specify which source files should be included/excluded from build process. The path in filter should be relative to the srcDir option of a library.\nSee syntax for build_src_filter.\nPlease note that you can generate source filter “on-the-fly” using extraScript", + "required": false + }, + "extraScript": { + "type": "string", + "description": "Launch extra script before a build process.", + "required": "false" + }, + "libArchive": { + "type": "boolean", + "description": "Create an archive (*.a, static library) from the object files and link it into a firmware (program). This is default behavior of PlatformIO Build System (\"libArchive\": true).\nSetting \"libArchive\": false will instruct PlatformIO Build System to link object files directly (in-line). This could be useful if you need to override weak symbols defined in framework or other libraries.\nYou can disable library archiving globally using lib_archive option in “platformio.ini” (Project Configuration File).", + "required": "false" + }, + "libLDFMode": { + "anyOf": [ + { + "enum": [ + "off" + ], + "description": "“Manual mode”, does not process source files of a project and dependencies. Builds only the libraries that are specified in manifests (library.json, module.json) or using lib_deps option." + }, + { + "enum": [ + "chain" + ], + "description": "[DEFAULT] Parses ALL C/C++ source files of the project and follows only by nested includes (#include ..., chain...) from the libraries. It also parses C, CC, CPP files from libraries which have the same name as included header file. Does not evaluate C/C++ Preprocessor conditional syntax." + }, + { + "enum": [ + "deep" + ], + "description": "Parses ALL C/C++ source files of the project and parses ALL C/C++ source files of the each found dependency (recursively). Does not evaluate C/C++ Preprocessor conditional syntax." + }, + { + "enum": [ + "chain+" + ], + "description": "The same behavior as for the chain but evaluates C/C++ Preprocessor conditional syntax." + }, + { + "enum": [ + "deep+" + ], + "description": "The same behavior as for the deep but evaluates C/C++ Preprocessor conditional syntax." + } + ], + "description": "Specify Library Dependency Finder Mode. See Dependency Finder Mode for details.", + "required": false + }, + "libCompatMode": { + "type": "string", + "description": "Specify Library Compatibility Mode. See Compatibility Mode for details.", + "required": false + }, + "builder": { + "anyOf": [ + { + "enum": [ + "PlatformIOLibBuilder" + ], + "description": "Default Builder" + }, + { + "enum": [ + "ArduinoLibBuilder" + ] + }, + { + "enum": [ + "MbedLibBuilder" + ] + } + ], + "description": "Override default PlatformIOLibBuilder with another builder.", + "required": false + } + }, + "required": false + } + } +} \ No newline at end of file diff --git a/scripts/99-platformio-udev.rules b/platformio/assets/system/99-platformio-udev.rules similarity index 98% rename from scripts/99-platformio-udev.rules rename to platformio/assets/system/99-platformio-udev.rules index 760b574355..a5897f8f10 100644 --- a/scripts/99-platformio-udev.rules +++ b/platformio/assets/system/99-platformio-udev.rules @@ -76,12 +76,15 @@ ATTRS{idVendor}=="28e9", ATTRS{idProduct}=="0189", MODE="0666", ENV{ID_MM_DEVICE # FireBeetle-ESP32 ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7522", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" -#Wio Terminal +# Wio Terminal ATTRS{idVendor}=="2886", ATTRS{idProduct}=="[08]02d", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" # Raspberry Pi Pico ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="[01]*", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" +# AIR32F103 +ATTRS{idVendor}=="0d28", ATTRS{idProduct}=="0204", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + # # Debuggers diff --git a/platformio/project/integration/tpls/atom/.clang_complete.tpl b/platformio/assets/templates/ide-projects/atom/.clang_complete.tpl similarity index 100% rename from platformio/project/integration/tpls/atom/.clang_complete.tpl rename to platformio/assets/templates/ide-projects/atom/.clang_complete.tpl diff --git a/platformio/project/integration/tpls/atom/.gcc-flags.json.tpl b/platformio/assets/templates/ide-projects/atom/.gcc-flags.json.tpl similarity index 100% rename from platformio/project/integration/tpls/atom/.gcc-flags.json.tpl rename to platformio/assets/templates/ide-projects/atom/.gcc-flags.json.tpl diff --git a/platformio/project/integration/tpls/atom/.gitignore.tpl b/platformio/assets/templates/ide-projects/atom/.gitignore.tpl similarity index 100% rename from platformio/project/integration/tpls/atom/.gitignore.tpl rename to platformio/assets/templates/ide-projects/atom/.gitignore.tpl diff --git a/platformio/project/integration/tpls/clion/.gitignore.tpl b/platformio/assets/templates/ide-projects/clion/.gitignore.tpl similarity index 100% rename from platformio/project/integration/tpls/clion/.gitignore.tpl rename to platformio/assets/templates/ide-projects/clion/.gitignore.tpl diff --git a/platformio/project/integration/tpls/clion/CMakeLists.txt.tpl b/platformio/assets/templates/ide-projects/clion/CMakeLists.txt.tpl similarity index 100% rename from platformio/project/integration/tpls/clion/CMakeLists.txt.tpl rename to platformio/assets/templates/ide-projects/clion/CMakeLists.txt.tpl diff --git a/platformio/project/integration/tpls/clion/CMakeListsPrivate.txt.tpl b/platformio/assets/templates/ide-projects/clion/CMakeListsPrivate.txt.tpl similarity index 100% rename from platformio/project/integration/tpls/clion/CMakeListsPrivate.txt.tpl rename to platformio/assets/templates/ide-projects/clion/CMakeListsPrivate.txt.tpl diff --git a/platformio/project/integration/tpls/codeblocks/platformio.cbp.tpl b/platformio/assets/templates/ide-projects/codeblocks/platformio.cbp.tpl similarity index 100% rename from platformio/project/integration/tpls/codeblocks/platformio.cbp.tpl rename to platformio/assets/templates/ide-projects/codeblocks/platformio.cbp.tpl diff --git a/platformio/project/integration/tpls/eclipse/.cproject.tpl b/platformio/assets/templates/ide-projects/eclipse/.cproject.tpl similarity index 100% rename from platformio/project/integration/tpls/eclipse/.cproject.tpl rename to platformio/assets/templates/ide-projects/eclipse/.cproject.tpl diff --git a/platformio/project/integration/tpls/eclipse/.project.tpl b/platformio/assets/templates/ide-projects/eclipse/.project.tpl similarity index 100% rename from platformio/project/integration/tpls/eclipse/.project.tpl rename to platformio/assets/templates/ide-projects/eclipse/.project.tpl diff --git a/platformio/project/integration/tpls/eclipse/.settings/PlatformIO Debugger.launch.tpl b/platformio/assets/templates/ide-projects/eclipse/.settings/PlatformIO Debugger.launch.tpl similarity index 100% rename from platformio/project/integration/tpls/eclipse/.settings/PlatformIO Debugger.launch.tpl rename to platformio/assets/templates/ide-projects/eclipse/.settings/PlatformIO Debugger.launch.tpl diff --git a/platformio/project/integration/tpls/eclipse/.settings/language.settings.xml.tpl b/platformio/assets/templates/ide-projects/eclipse/.settings/language.settings.xml.tpl similarity index 100% rename from platformio/project/integration/tpls/eclipse/.settings/language.settings.xml.tpl rename to platformio/assets/templates/ide-projects/eclipse/.settings/language.settings.xml.tpl diff --git a/platformio/project/integration/tpls/eclipse/.settings/org.eclipse.cdt.core.prefs.tpl b/platformio/assets/templates/ide-projects/eclipse/.settings/org.eclipse.cdt.core.prefs.tpl similarity index 100% rename from platformio/project/integration/tpls/eclipse/.settings/org.eclipse.cdt.core.prefs.tpl rename to platformio/assets/templates/ide-projects/eclipse/.settings/org.eclipse.cdt.core.prefs.tpl diff --git a/platformio/project/integration/tpls/emacs/.ccls.tpl b/platformio/assets/templates/ide-projects/emacs/.ccls.tpl similarity index 100% rename from platformio/project/integration/tpls/emacs/.ccls.tpl rename to platformio/assets/templates/ide-projects/emacs/.ccls.tpl diff --git a/platformio/project/integration/tpls/emacs/.gitignore.tpl b/platformio/assets/templates/ide-projects/emacs/.gitignore.tpl similarity index 100% rename from platformio/project/integration/tpls/emacs/.gitignore.tpl rename to platformio/assets/templates/ide-projects/emacs/.gitignore.tpl diff --git a/platformio/project/integration/tpls/netbeans/nbproject/configurations.xml.tpl b/platformio/assets/templates/ide-projects/netbeans/nbproject/configurations.xml.tpl similarity index 100% rename from platformio/project/integration/tpls/netbeans/nbproject/configurations.xml.tpl rename to platformio/assets/templates/ide-projects/netbeans/nbproject/configurations.xml.tpl diff --git a/platformio/project/integration/tpls/netbeans/nbproject/private/configurations.xml.tpl b/platformio/assets/templates/ide-projects/netbeans/nbproject/private/configurations.xml.tpl similarity index 100% rename from platformio/project/integration/tpls/netbeans/nbproject/private/configurations.xml.tpl rename to platformio/assets/templates/ide-projects/netbeans/nbproject/private/configurations.xml.tpl diff --git a/platformio/project/integration/tpls/netbeans/nbproject/private/launcher.properties.tpl b/platformio/assets/templates/ide-projects/netbeans/nbproject/private/launcher.properties.tpl similarity index 100% rename from platformio/project/integration/tpls/netbeans/nbproject/private/launcher.properties.tpl rename to platformio/assets/templates/ide-projects/netbeans/nbproject/private/launcher.properties.tpl diff --git a/platformio/project/integration/tpls/netbeans/nbproject/private/private.xml.tpl b/platformio/assets/templates/ide-projects/netbeans/nbproject/private/private.xml.tpl similarity index 100% rename from platformio/project/integration/tpls/netbeans/nbproject/private/private.xml.tpl rename to platformio/assets/templates/ide-projects/netbeans/nbproject/private/private.xml.tpl diff --git a/platformio/project/integration/tpls/netbeans/nbproject/project.xml.tpl b/platformio/assets/templates/ide-projects/netbeans/nbproject/project.xml.tpl similarity index 100% rename from platformio/project/integration/tpls/netbeans/nbproject/project.xml.tpl rename to platformio/assets/templates/ide-projects/netbeans/nbproject/project.xml.tpl diff --git a/platformio/project/integration/tpls/qtcreator/.gitignore.tpl b/platformio/assets/templates/ide-projects/qtcreator/.gitignore.tpl similarity index 100% rename from platformio/project/integration/tpls/qtcreator/.gitignore.tpl rename to platformio/assets/templates/ide-projects/qtcreator/.gitignore.tpl diff --git a/platformio/project/integration/tpls/qtcreator/Makefile.tpl b/platformio/assets/templates/ide-projects/qtcreator/Makefile.tpl similarity index 100% rename from platformio/project/integration/tpls/qtcreator/Makefile.tpl rename to platformio/assets/templates/ide-projects/qtcreator/Makefile.tpl diff --git a/platformio/project/integration/tpls/qtcreator/platformio.cflags.tpl b/platformio/assets/templates/ide-projects/qtcreator/platformio.cflags.tpl similarity index 100% rename from platformio/project/integration/tpls/qtcreator/platformio.cflags.tpl rename to platformio/assets/templates/ide-projects/qtcreator/platformio.cflags.tpl diff --git a/platformio/project/integration/tpls/qtcreator/platformio.config.tpl b/platformio/assets/templates/ide-projects/qtcreator/platformio.config.tpl similarity index 100% rename from platformio/project/integration/tpls/qtcreator/platformio.config.tpl rename to platformio/assets/templates/ide-projects/qtcreator/platformio.config.tpl diff --git a/platformio/project/integration/tpls/qtcreator/platformio.creator.tpl b/platformio/assets/templates/ide-projects/qtcreator/platformio.creator.tpl similarity index 100% rename from platformio/project/integration/tpls/qtcreator/platformio.creator.tpl rename to platformio/assets/templates/ide-projects/qtcreator/platformio.creator.tpl diff --git a/platformio/project/integration/tpls/qtcreator/platformio.cxxflags.tpl b/platformio/assets/templates/ide-projects/qtcreator/platformio.cxxflags.tpl similarity index 100% rename from platformio/project/integration/tpls/qtcreator/platformio.cxxflags.tpl rename to platformio/assets/templates/ide-projects/qtcreator/platformio.cxxflags.tpl diff --git a/platformio/project/integration/tpls/qtcreator/platformio.files.tpl b/platformio/assets/templates/ide-projects/qtcreator/platformio.files.tpl similarity index 100% rename from platformio/project/integration/tpls/qtcreator/platformio.files.tpl rename to platformio/assets/templates/ide-projects/qtcreator/platformio.files.tpl diff --git a/platformio/project/integration/tpls/qtcreator/platformio.includes.tpl b/platformio/assets/templates/ide-projects/qtcreator/platformio.includes.tpl similarity index 100% rename from platformio/project/integration/tpls/qtcreator/platformio.includes.tpl rename to platformio/assets/templates/ide-projects/qtcreator/platformio.includes.tpl diff --git a/platformio/project/integration/tpls/sublimetext/.ccls.tpl b/platformio/assets/templates/ide-projects/sublimetext/.ccls.tpl similarity index 100% rename from platformio/project/integration/tpls/sublimetext/.ccls.tpl rename to platformio/assets/templates/ide-projects/sublimetext/.ccls.tpl diff --git a/platformio/project/integration/tpls/sublimetext/platformio.sublime-project.tpl b/platformio/assets/templates/ide-projects/sublimetext/platformio.sublime-project.tpl similarity index 100% rename from platformio/project/integration/tpls/sublimetext/platformio.sublime-project.tpl rename to platformio/assets/templates/ide-projects/sublimetext/platformio.sublime-project.tpl diff --git a/platformio/project/integration/tpls/vim/.ccls.tpl b/platformio/assets/templates/ide-projects/vim/.ccls.tpl similarity index 100% rename from platformio/project/integration/tpls/vim/.ccls.tpl rename to platformio/assets/templates/ide-projects/vim/.ccls.tpl diff --git a/platformio/project/integration/tpls/vim/.gitignore.tpl b/platformio/assets/templates/ide-projects/vim/.gitignore.tpl similarity index 100% rename from platformio/project/integration/tpls/vim/.gitignore.tpl rename to platformio/assets/templates/ide-projects/vim/.gitignore.tpl diff --git a/platformio/project/integration/tpls/visualstudio/platformio.vcxproj.filters.tpl b/platformio/assets/templates/ide-projects/visualstudio/platformio.vcxproj.filters.tpl similarity index 100% rename from platformio/project/integration/tpls/visualstudio/platformio.vcxproj.filters.tpl rename to platformio/assets/templates/ide-projects/visualstudio/platformio.vcxproj.filters.tpl diff --git a/platformio/project/integration/tpls/visualstudio/platformio.vcxproj.tpl b/platformio/assets/templates/ide-projects/visualstudio/platformio.vcxproj.tpl similarity index 100% rename from platformio/project/integration/tpls/visualstudio/platformio.vcxproj.tpl rename to platformio/assets/templates/ide-projects/visualstudio/platformio.vcxproj.tpl diff --git a/platformio/project/integration/tpls/vscode/.gitignore.tpl b/platformio/assets/templates/ide-projects/vscode/.gitignore.tpl similarity index 100% rename from platformio/project/integration/tpls/vscode/.gitignore.tpl rename to platformio/assets/templates/ide-projects/vscode/.gitignore.tpl diff --git a/platformio/project/integration/tpls/vscode/.vscode/c_cpp_properties.json.tpl b/platformio/assets/templates/ide-projects/vscode/.vscode/c_cpp_properties.json.tpl similarity index 100% rename from platformio/project/integration/tpls/vscode/.vscode/c_cpp_properties.json.tpl rename to platformio/assets/templates/ide-projects/vscode/.vscode/c_cpp_properties.json.tpl diff --git a/platformio/project/integration/tpls/vscode/.vscode/extensions.json.tpl b/platformio/assets/templates/ide-projects/vscode/.vscode/extensions.json.tpl similarity index 100% rename from platformio/project/integration/tpls/vscode/.vscode/extensions.json.tpl rename to platformio/assets/templates/ide-projects/vscode/.vscode/extensions.json.tpl diff --git a/platformio/project/integration/tpls/vscode/.vscode/launch.json.tpl b/platformio/assets/templates/ide-projects/vscode/.vscode/launch.json.tpl similarity index 100% rename from platformio/project/integration/tpls/vscode/.vscode/launch.json.tpl rename to platformio/assets/templates/ide-projects/vscode/.vscode/launch.json.tpl diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 3612174394..b56dc2a248 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -157,11 +157,6 @@ os.makedirs(env.subst("$BUILD_CACHE_DIR")) env.CacheDir("$BUILD_CACHE_DIR") -is_clean_all = "cleanall" in COMMAND_LINE_TARGETS -if env.GetOption("clean") or is_clean_all: - env.PioClean(is_clean_all) - env.Exit(0) - if not int(ARGUMENTS.get("PIOVERBOSE", 0)): click.echo("Verbose mode can be enabled via `-v, --verbose` option") @@ -185,6 +180,10 @@ for item in env.GetExtraScripts("pre"): env.SConscript(item, exports="env") +if env.IsCleanTarget(): + env.CleanProject("cleanall" in COMMAND_LINE_TARGETS) + env.Exit(0) + env.SConscript("$BUILD_SCRIPT") if "UPLOAD_FLAGS" in env: diff --git a/platformio/builder/tools/piotarget.py b/platformio/builder/tools/piotarget.py index 51333e4dad..f2dc774d44 100644 --- a/platformio/builder/tools/piotarget.py +++ b/platformio/builder/tools/piotarget.py @@ -16,6 +16,7 @@ from SCons.Action import Action # pylint: disable=import-error from SCons.Script import ARGUMENTS # pylint: disable=import-error +from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error from SCons.Script import AlwaysBuild # pylint: disable=import-error from platformio import compat, fs @@ -27,7 +28,11 @@ def VerboseAction(_, act, actstr): return Action(act, actstr) -def PioClean(env, clean_all=False): +def IsCleanTarget(env): + return env.GetOption("clean") or ("cleanall" in COMMAND_LINE_TARGETS) + + +def CleanProject(env, clean_all=False): def _relpath(path): if compat.IS_WINDOWS: prefix = os.getcwd()[:2].lower() @@ -103,7 +108,8 @@ def exists(_): def generate(env): env.AddMethod(VerboseAction) - env.AddMethod(PioClean) + env.AddMethod(IsCleanTarget) + env.AddMethod(CleanProject) env.AddMethod(AddTarget) env.AddMethod(AddPlatformTarget) env.AddMethod(AddCustomTarget) diff --git a/platformio/compat.py b/platformio/compat.py index 9cf9161e75..17b4cc0aff 100644 --- a/platformio/compat.py +++ b/platformio/compat.py @@ -85,10 +85,7 @@ def get_filesystem_encoding(): def get_locale_encoding(): - try: - return locale.getdefaultlocale()[1] - except ValueError: - return None + return locale.getpreferredencoding() def get_object_members(obj, ignore_private=True): diff --git a/platformio/device/list/util.py b/platformio/device/list/util.py index 2c1d038529..3589ee2666 100644 --- a/platformio/device/list/util.py +++ b/platformio/device/list/util.py @@ -18,8 +18,6 @@ import time from glob import glob -import zeroconf - from platformio import __version__, exception, proc from platformio.compat import IS_MACOS, IS_WINDOWS @@ -84,6 +82,16 @@ def list_logical_devices(): def list_mdns_services(): + try: + import zeroconf # pylint: disable=import-outside-toplevel + except ImportError: + result = proc.exec_command( + [proc.get_pythonexe_path(), "-m", "pip", "install", "zeroconf"] + ) + if result.get("returncode") != 0: + print(result.get("err")) + import zeroconf # pylint: disable=import-outside-toplevel + class mDNSListener: def __init__(self): self._zc = zeroconf.Zeroconf(interfaces=zeroconf.InterfaceChoice.All) diff --git a/platformio/fs.py b/platformio/fs.py index 60111694e9..bd17950b2b 100644 --- a/platformio/fs.py +++ b/platformio/fs.py @@ -50,6 +50,10 @@ def get_source_dir(): return os.path.dirname(curpath) +def get_assets_dir(): + return os.path.join(get_source_dir(), "assets") + + def load_json(file_path): try: with open(file_path, mode="r", encoding="utf8") as f: @@ -99,7 +103,7 @@ def calculate_folder_size(path): def get_platformio_udev_rules_path(): return os.path.abspath( - os.path.join(get_source_dir(), "..", "scripts", "99-platformio-udev.rules") + os.path.join(get_assets_dir(), "system", "99-platformio-udev.rules") ) diff --git a/platformio/home/cli.py b/platformio/home/cli.py index 2d0ba1ce59..55d0959494 100644 --- a/platformio/home/cli.py +++ b/platformio/home/cli.py @@ -18,6 +18,7 @@ from platformio.home.helpers import is_port_used 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") @@ -48,15 +49,17 @@ ), ) 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") + return + # Ensure PIO Home mimetypes are known mimetypes.add_type("text/html", ".html") mimetypes.add_type("text/css", ".css") mimetypes.add_type("application/javascript", ".js") - # hook for `platformio-node-helpers` - if host == "__do_not_start__": - return - home_url = "http://%s:%d%s" % ( host, port, diff --git a/platformio/home/helpers.py b/platformio/home/helpers.py index a777101b6d..0e88bde2c8 100644 --- a/platformio/home/helpers.py +++ b/platformio/home/helpers.py @@ -14,27 +14,11 @@ import socket -from starlette.concurrency import run_in_threadpool - from platformio import util from platformio.compat import IS_WINDOWS -from platformio.http import HTTPSession from platformio.proc import where_is_program -class AsyncSession(HTTPSession): - async def request( # pylint: disable=signature-differs,invalid-overridden-method - self, *args, **kwargs - ): - func = super().request - return await run_in_threadpool(func, *args, **kwargs) - - -@util.memoized(expire="60s") -def requests_session(): - return AsyncSession() - - @util.memoized(expire="60s") def get_core_fullpath(): return where_is_program("platformio" + (".exe" if IS_WINDOWS else "")) diff --git a/platformio/home/rpc/handlers/os.py b/platformio/home/rpc/handlers/os.py index aed6299144..333618b521 100644 --- a/platformio/home/rpc/handlers/os.py +++ b/platformio/home/rpc/handlers/os.py @@ -19,17 +19,25 @@ from functools import cmp_to_key import click +from starlette.concurrency import run_in_threadpool from platformio import fs from platformio.cache import ContentCache from platformio.device.list.util import list_logical_devices -from platformio.home import helpers -from platformio.http import ensure_internet_on +from platformio.http import HTTPSession, ensure_internet_on + + +class HTTPAsyncSession(HTTPSession): + async def request( # pylint: disable=signature-differs,invalid-overridden-method + self, *args, **kwargs + ): + func = super().request + return await run_in_threadpool(func, *args, **kwargs) class OSRPC: @staticmethod - async def fetch_content(uri, data=None, headers=None, cache_valid=None): + async def fetch_content(url, data=None, headers=None, cache_valid=None): if not headers: headers = { "User-Agent": ( @@ -38,7 +46,7 @@ async def fetch_content(uri, data=None, headers=None, cache_valid=None): "Safari/603.3.8" ) } - cache_key = ContentCache.key_from_args(uri, data) if cache_valid else None + cache_key = ContentCache.key_from_args(url, data) if cache_valid else None with ContentCache() as cc: if cache_key: result = cc.get(cache_key) @@ -48,11 +56,11 @@ async def fetch_content(uri, data=None, headers=None, cache_valid=None): # check internet before and resolve issue with 60 seconds timeout ensure_internet_on(raise_exception=True) - session = helpers.requests_session() + session = HTTPAsyncSession() if data: - r = await session.post(uri, data=data, headers=headers) + r = await session.post(url, data=data, headers=headers) else: - r = await session.get(uri, headers=headers) + r = await session.get(url, headers=headers) r.raise_for_status() result = r.text diff --git a/platformio/home/rpc/handlers/registry.py b/platformio/home/rpc/handlers/registry.py new file mode 100644 index 0000000000..a6d5b8bff1 --- /dev/null +++ b/platformio/home/rpc/handlers/registry.py @@ -0,0 +1,29 @@ +# 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. + +from ajsonrpc.core import JSONRPC20DispatchException + +from platformio.registry.client import RegistryClient + + +class RegistryRPC: + @staticmethod + def call_client(method, *args, **kwargs): + try: + client = RegistryClient() + return getattr(client, method)(*args, **kwargs) + except Exception as exc: # pylint: disable=bare-except + raise JSONRPC20DispatchException( + code=4003, message="Registry Call Error", data=str(exc) + ) from exc diff --git a/platformio/home/run.py b/platformio/home/run.py index a5306ad056..25f1081ec3 100644 --- a/platformio/home/run.py +++ b/platformio/home/run.py @@ -33,6 +33,7 @@ from platformio.home.rpc.handlers.os import OSRPC from platformio.home.rpc.handlers.piocore import PIOCoreRPC from platformio.home.rpc.handlers.project import ProjectRPC +from platformio.home.rpc.handlers.registry import RegistryRPC from platformio.home.rpc.server import WebSocketJSONRPCServerFactory from platformio.package.manager.core import get_core_package_dir from platformio.proc import force_exit @@ -72,6 +73,7 @@ def run_server(host, port, no_open, shutdown_timeout, home_url): ws_rpc_factory.add_object_handler(OSRPC(), namespace="os") ws_rpc_factory.add_object_handler(PIOCoreRPC(), namespace="core") ws_rpc_factory.add_object_handler(ProjectRPC(), namespace="project") + ws_rpc_factory.add_object_handler(RegistryRPC(), namespace="registry") path = urlparse(home_url).path routes = [ diff --git a/platformio/package/commands/list.py b/platformio/package/commands/list.py index c92cc1b4a8..9d538b7daa 100644 --- a/platformio/package/commands/list.py +++ b/platformio/package/commands/list.py @@ -84,10 +84,16 @@ def print_dependency_tree(pm, specs=None, filter_specs=None, level=0, verbose=Fa if not candidates: return candidates = sorted(candidates.values(), key=lambda item: item[0].metadata.name) + for index, (pkg, spec) in enumerate(candidates): if filtered_pkgs and not _pkg_tree_contains(pm, pkg, filtered_pkgs): continue - dependencies = pm.get_pkg_dependencies(pkg) + printed_pkgs = pm.memcache_get("__printed_pkgs", []) + if printed_pkgs and pkg.path in printed_pkgs: + continue + printed_pkgs.append(pkg.path) + pm.memcache_set("__printed_pkgs", printed_pkgs) + click.echo( "%s%s %s" % ( @@ -100,6 +106,8 @@ def print_dependency_tree(pm, specs=None, filter_specs=None, level=0, verbose=Fa ), ) ) + + dependencies = pm.get_pkg_dependencies(pkg) if dependencies: print_dependency_tree( pm, diff --git a/platformio/package/download.py b/platformio/package/download.py index 73969dc98a..5045e8565a 100644 --- a/platformio/package/download.py +++ b/platformio/package/download.py @@ -72,7 +72,9 @@ def get_size(self): def start(self, with_progress=True, silent=False): label = "Downloading" file_size = self.get_size() - itercontent = self._http_response.iter_content(chunk_size=io.DEFAULT_BUFFER_SIZE) + itercontent = self._http_response.iter_content( + chunk_size=io.DEFAULT_BUFFER_SIZE + ) try: with open(self._destination, "wb") as fp: if file_size == -1 or not with_progress or silent: diff --git a/platformio/package/manager/_uninstall.py b/platformio/package/manager/_uninstall.py index c845145a51..b374fd0166 100644 --- a/platformio/package/manager/_uninstall.py +++ b/platformio/package/manager/_uninstall.py @@ -35,6 +35,12 @@ def _uninstall(self, spec, skip_dependencies=False): if not pkg or not pkg.metadata: raise UnknownPackageError(spec) + uninstalled_pkgs = self.memcache_get("__uninstalled_pkgs", []) + if uninstalled_pkgs and pkg.path in uninstalled_pkgs: + return pkg + uninstalled_pkgs.append(pkg.path) + self.memcache_set("__uninstalled_pkgs", uninstalled_pkgs) + self.log.info( "Removing %s @ %s" % (click.style(pkg.metadata.name, fg="cyan"), pkg.metadata.version) diff --git a/platformio/package/manifest/schema.py b/platformio/package/manifest/schema.py index 1e5f935aba..937bbf91df 100644 --- a/platformio/package/manifest/schema.py +++ b/platformio/package/manifest/schema.py @@ -276,7 +276,7 @@ def validate_license(self, value): @staticmethod @memoized(expire="1h") def load_spdx_licenses(): - version = "3.18" + version = "3.19" spdx_data_url = ( "https://raw.githubusercontent.com/spdx/license-list-data/" "v%s/json/licenses.json" % version diff --git a/platformio/project/config.py b/platformio/project/config.py index 3443863aa6..ee380bb943 100644 --- a/platformio/project/config.py +++ b/platformio/project/config.py @@ -168,7 +168,7 @@ def walk_options(self, root_section): yield (section, option) if self._parser.has_option(section, "extends"): extends_queue.extend( - self.parse_multi_values(self._parser.get(section, "extends"))[::-1] + self.parse_multi_values(self._parser.get(section, "extends")) ) def options(self, section=None, env=None): @@ -319,7 +319,13 @@ def _re_interpolation_handler(self, parent_section, match): if section == "this": section = parent_section if option == "__env__": - assert parent_section.startswith("env:") + if not parent_section.startswith("env:"): + raise exception.ProjectOptionValueError( + f"`${{this.__env__}}` is called from the `{parent_section}` " + "section that is not valid PlatformIO environment, see", + option, + section, + ) return parent_section[4:] # handle nested calls try: diff --git a/platformio/project/integration/generator.py b/platformio/project/integration/generator.py index 7ffd05e38e..4ea3bbf3f8 100644 --- a/platformio/project/integration/generator.py +++ b/platformio/project/integration/generator.py @@ -15,7 +15,6 @@ import codecs import os import sys -from pathlib import Path import bottle @@ -51,12 +50,17 @@ def get_best_envname(self, board_ids=None): return envname @staticmethod - def get_supported_ides(): + def get_ide_tpls_dir(): + return os.path.join(fs.get_assets_dir(), "templates", "ide-projects") + + @classmethod + def get_supported_ides(cls): + tpls_dir = cls.get_ide_tpls_dir() return sorted( [ - item.name - for item in (Path(__file__).parent / "tpls").iterdir() - if item.is_dir() + name + for name in os.listdir(tpls_dir) + if os.path.isdir(os.path.join(tpls_dir, name)) ] ) @@ -78,7 +82,9 @@ def _load_tplvars(self): tpl_vars = { "config": self.config, "systype": util.get_systype(), - "project_name": os.path.basename(self.project_dir), + "project_name": self.config.get( + "platformio", "name", os.path.basename(self.project_dir) + ), "project_dir": self.project_dir, "original_env_name": self.original_env_name, "env_name": self.env_name, @@ -132,12 +138,12 @@ def get_src_files(self): def get_tpls(self): tpls = [] - tpls_dir = str(Path(__file__).parent / "tpls" / self.ide) - for root, _, files in os.walk(tpls_dir): + ide_tpls_dir = os.path.join(self.get_ide_tpls_dir(), self.ide) + for root, _, files in os.walk(ide_tpls_dir): for f in files: if not f.endswith(".tpl"): continue - _relpath = root.replace(tpls_dir, "") + _relpath = root.replace(ide_tpls_dir, "") if _relpath.startswith(os.sep): _relpath = _relpath[1:] tpls.append((_relpath, os.path.join(root, f))) diff --git a/platformio/project/options.py b/platformio/project/options.py index e1aa82805c..5e200629f4 100644 --- a/platformio/project/options.py +++ b/platformio/project/options.py @@ -133,6 +133,11 @@ def get_default_core_dir(): # # [platformio] # + ConfigPlatformioOption( + group="generic", + name="name", + description="A project name", + ), ConfigPlatformioOption( group="generic", name="description", diff --git a/platformio/public.py b/platformio/public.py index 681ab1264f..49db1b544e 100644 --- a/platformio/public.py +++ b/platformio/public.py @@ -14,12 +14,13 @@ # pylint: disable=unused-import -from platformio.device.list.util import list_serial_ports +from platformio.device.list.util import list_logical_devices, list_serial_ports from platformio.device.monitor.filters.base import DeviceMonitorFilterBase from platformio.fs import to_unix_path from platformio.platform.base import PlatformBase from platformio.project.config import ProjectConfig from platformio.project.helpers import get_project_watch_lib_dirs, load_build_metadata +from platformio.project.options import get_config_options_schema from platformio.test.result import TestCase, TestCaseSource, TestStatus from platformio.test.runners.base import TestRunnerBase from platformio.test.runners.doctest import DoctestTestCaseParser diff --git a/platformio/run/cli.py b/platformio/run/cli.py index adf0153f7c..6c64743156 100644 --- a/platformio/run/cli.py +++ b/platformio/run/cli.py @@ -24,6 +24,7 @@ from platformio import app, exception, fs, util from platformio.device.monitor.command import device_monitor_cmd from platformio.project.config import ProjectConfig +from platformio.project.exception import ProjectError from platformio.project.helpers import find_project_dir_above, load_build_metadata from platformio.run.helpers import clean_build_dir, handle_legacy_libdeps from platformio.run.processor import EnvironmentProcessor @@ -115,6 +116,8 @@ def cli( build_dir = config.get("platformio", "build_dir") try: clean_build_dir(build_dir, config) + except ProjectError as exc: + raise exc except: # pylint: disable=bare-except click.secho( "Can not remove temporary directory `%s`. Please remove " diff --git a/platformio/test/cli.py b/platformio/test/cli.py index 1e456d4de9..d0a6e53a4a 100644 --- a/platformio/test/cli.py +++ b/platformio/test/cli.py @@ -156,9 +156,6 @@ def cli( # pylint: disable=too-many-arguments,too-many-locals,redefined-builtin runner.start(ctx) print_suite_footer(test_suite) - # Reset custom project config - app.set_session_var("custom_project_conf", None) - stdout_report = TestReportFactory.new("stdout", test_result) stdout_report.generate(verbose=verbose or list_tests) @@ -171,6 +168,9 @@ def cli( # pylint: disable=too-many-arguments,too-many-locals,redefined-builtin custom_report = TestReportFactory.new(output_format, test_result) custom_report.generate(output_path=output_path, verbose=True) + # Reset custom project config + app.set_session_var("custom_project_conf", None) + if test_result.is_errored or test_result.get_status_nums(TestStatus.FAILED): raise exception.ReturnErrorCode(1) diff --git a/platformio/test/helpers.py b/platformio/test/helpers.py index 908173d0e6..01650a0b1d 100644 --- a/platformio/test/helpers.py +++ b/platformio/test/helpers.py @@ -35,6 +35,7 @@ def list_test_names(project_config): def list_test_suites(project_config, environments, filters, ignores): result = [] + test_dir = project_config.get("platformio", "test_dir") default_envs = project_config.default_envs() test_names = list_test_names(project_config) for env_name in project_config.envs(): @@ -58,5 +59,16 @@ def list_test_suites(project_config, environments, filters, ignores): test_name != "*" and any(fnmatch(test_name, p) for p in patterns["ignore"]), ] - result.append(TestSuite(env_name, test_name, finished=any(skip_conditions))) + result.append( + TestSuite( + env_name, + test_name, + finished=any(skip_conditions), + test_dir=os.path.abspath( + test_dir + if test_name == "*" + else os.path.join(test_dir, test_name) + ), + ) + ) return result diff --git a/platformio/test/reports/json.py b/platformio/test/reports/json.py index c22fb5870c..791224c70f 100644 --- a/platformio/test/reports/json.py +++ b/platformio/test/reports/json.py @@ -59,6 +59,7 @@ def test_suite_to_json(self, test_suite): result = dict( env_name=test_suite.env_name, test_name=test_suite.test_name, + test_dir=test_suite.test_dir, status=test_suite.status.name, duration=test_suite.duration, timestamp=datetime.datetime.fromtimestamp(test_suite.timestamp).strftime( diff --git a/platformio/test/result.py b/platformio/test/result.py index b2000b2e26..091fa964f2 100644 --- a/platformio/test/result.py +++ b/platformio/test/result.py @@ -93,9 +93,10 @@ def humanize(self): class TestSuite: - def __init__(self, env_name, test_name, finished=False): + def __init__(self, env_name, test_name, finished=False, test_dir=None): self.env_name = env_name self.test_name = test_name + self.test_dir = test_dir self.timestamp = 0 self.duration = 0 self._cases = [] diff --git a/platformio/test/runners/unity.py b/platformio/test/runners/unity.py index a8970cf514..b7d8026be5 100644 --- a/platformio/test/runners/unity.py +++ b/platformio/test/runners/unity.py @@ -29,10 +29,11 @@ class UnityTestRunner(TestRunnerBase): EXTRA_LIB_DEPS = ["throwtheswitch/Unity@^2.5.2"] - # Example: + # Examples: # test/test_foo.cpp:44:test_function_foo:FAIL: Expected 32 Was 33 + # test/group/test_foo/test_main.cpp:5:test::dummy:FAIL: Expression Evaluated To FALSE TESTCASE_PARSE_RE = re.compile( - r"(?P[^:]+):(?P\d+):(?P[^:]+):" + r"(?P[^:]+):(?P\d+):(?P[^\s]+):" r"(?PPASS|IGNORE|FAIL)(:\s*(?P.+)$)?" ) diff --git a/scripts/docspregen.py b/scripts/docspregen.py index a9a96c7b43..f895c25d84 100644 --- a/scripts/docspregen.py +++ b/scripts/docspregen.py @@ -476,13 +476,11 @@ def generate_platform(pkg, rst_dir): ; Latest stable version [env:latest_stable] platform = {name} - board = ... - + {board} ; Custom stable version [env:custom_stable] platform = {name}@x.y.z - board = ... - + {board} Upstream ~~~~~~~~ @@ -490,9 +488,11 @@ def generate_platform(pkg, rst_dir): [env:upstream_develop] platform = {github_url}.git - board = ... -""".format( - name=p.name, title=p.title, github_url=github_url + {board}""".format( + name=p.name, + title=p.title, + github_url=github_url, + board="board = ...\n" if p.is_embedded() else "", ) ) diff --git a/setup.py b/setup.py index a4b8a3c8d0..2e1fa86c0e 100644 --- a/setup.py +++ b/setup.py @@ -39,14 +39,13 @@ "requests==%s" % ("2.27.1" if PY36 else "2.*"), "semantic_version==2.10.*", "tabulate==%s" % ("0.8.10" if PY36 else "0.9.*"), - "zeroconf<1", ] home_requirements = [ "aiofiles==%s" % ("0.8.0" if PY36 else "22.1.*"), "ajsonrpc==1.*", - "starlette==%s" % ("0.19.1" if PY36 else "0.21.*"), - "uvicorn==%s" % ("0.16.0" if PY36 else "0.19.*"), + "starlette==%s" % ("0.19.1" if PY36 else "0.23.*"), + "uvicorn==%s" % ("0.16.0" if PY36 else "0.20.*"), "wsproto==%s" % ("1.0.0" if PY36 else "1.2.*"), ] @@ -61,15 +60,14 @@ license=__license__, install_requires=minimal_requirements + home_requirements, python_requires=">=3.6", - packages=find_packages(exclude=["tests.*", "tests"]) + ["scripts"], + packages=find_packages(include=["platformio", "platformio.*"]), package_data={ "platformio": [ - "project/integration/tpls/*/.*.tpl", - "project/integration/tpls/*/*.tpl", - "project/integration/tpls/*/*/*.tpl", - "project/integration/tpls/*/.*/*.tpl", - ], - "scripts": ["99-platformio-udev.rules"], + "assets/system/99-platformio-udev.rules", + "assets/templates/ide-projects/*/*.tpl", + "assets/templates/ide-projects/*/.*.tpl", # include hidden files + "assets/templates/ide-projects/*/.*/*.tpl", # include hidden folders + ] }, entry_points={ "console_scripts": [ diff --git a/tests/commands/pkg/test_install.py b/tests/commands/pkg/test_install.py index dcbd2d9895..61ccde0da7 100644 --- a/tests/commands/pkg/test_install.py +++ b/tests/commands/pkg/test_install.py @@ -443,7 +443,7 @@ def test_custom_project_libraries( ) assert pkgs_to_specs(lm.get_installed()) == [ PackageSpec("ArduinoJson@5.13.4"), - PackageSpec("Nanopb@0.4.6+4"), + PackageSpec("Nanopb@0.4.7"), ] assert config.get("env:devkit", "lib_deps") == [ "bblanchon/ArduinoJson@^5", diff --git a/tests/project/test_config.py b/tests/project/test_config.py index 964c0e6717..6076a7d6c7 100644 --- a/tests/project/test_config.py +++ b/tests/project/test_config.py @@ -205,9 +205,9 @@ def test_options(config): assert config.options(env="test_extends") == [ "extends", "build_flags", + "monitor_speed", "lib_ldf_mode", "lib_compat_mode", - "monitor_speed", "custom_monitor_speed", "lib_deps", "lib_ignore", @@ -245,9 +245,9 @@ def test_sysenv_options(config): assert config.options(env="test_extends") == [ "extends", "build_flags", + "monitor_speed", "lib_ldf_mode", "lib_compat_mode", - "monitor_speed", "custom_monitor_speed", "lib_deps", "lib_ignore", @@ -427,9 +427,9 @@ def test_items(config): assert config.items(env="test_extends") == [ ("extends", ["strict_settings"]), ("build_flags", ["-D RELEASE"]), + ("monitor_speed", 115200), ("lib_ldf_mode", "chain+"), ("lib_compat_mode", "strict"), - ("monitor_speed", 115200), ("custom_monitor_speed", "115200"), ("lib_deps", ["Lib1", "Lib2"]), ("lib_ignore", ["LibIgnoreCustom"]), @@ -647,3 +647,24 @@ def test_nested_interpolation(tmp_path: Path): config = ProjectConfig(str(project_conf)) testing_command = config.get("env:myenv", "test_testing_command") assert "$" not in " ".join(testing_command) + + +def test_extends_order(tmp_path: Path): + project_conf = tmp_path / "platformio.ini" + project_conf.write_text( + """ +[a] +board = test + +[b] +upload_tool = two + +[c] +upload_tool = three + +[env:native] +extends = a, b, c + """ + ) + config = ProjectConfig(str(project_conf)) + assert config.get("env:native", "upload_tool") == "three" diff --git a/tox.ini b/tox.ini index 8972933e89..0a51741a44 100644 --- a/tox.ini +++ b/tox.ini @@ -19,8 +19,8 @@ known_third_party=OpenSSL, SCons, jsonrpc, twisted, zope [pytest] filterwarnings = error - # SCons - ignore:.*_ImportRedirect.find_spec() + # Bottle + ignore:.*'cgi' is deprecated and slated for removal [testenv] passenv = * @@ -44,19 +44,19 @@ commands = [testenv:testcore] commands = {envpython} --version - py.test -v --basetemp="{envtmpdir}" -k "not skip_ci" tests --ignore tests/test_examples.py + py.test -v --basetemp={envtmpdir} -k "not skip_ci" tests --ignore tests/test_examples.py [testenv:testexamples] commands = {envpython} scripts/install_devplatforms.py - py.test -v --basetemp="{envtmpdir}" tests/test_examples.py + py.test -v --basetemp={envtmpdir} tests/test_examples.py [testenv:docs] deps = sphinx - sphinx_rtd_theme + sphinx-rtd-theme==1.1.1 sphinx-notfound-page - sphinx_copybutton + sphinx-copybutton restructuredtext-lint commands = sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html @@ -64,6 +64,6 @@ commands = [testenv:docslinkcheck] deps = sphinx - sphinx_rtd_theme + sphinx-rtd-theme commands = sphinx-build -W -b linkcheck docs docs/_build/html