From f182a6dcaed44a385273da30c0d3e6d8990cf3b6 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 29 Mar 2019 12:46:24 +0200 Subject: [PATCH 01/45] Bump version to 3.6.7a1 --- platformio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 6b913ff6..0b432099 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 6, 6) +VERSION = (3, 6, "7a1") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" From 7746f7eeee9e01dd353377698d61533c93049c0d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 29 Mar 2019 21:26:45 +0200 Subject: [PATCH 02/45] Project Generator: fixed a VSCode C/C++'s "Cannot find" warning when CPPPATH folder does not exist --- HISTORY.rst | 5 +++++ .../ide/tpls/vscode/.vscode/c_cpp_properties.json.tpl | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index f244ded7..a6543f30 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -4,6 +4,11 @@ Release Notes PlatformIO 3.0 -------------- +3.6.7 (2019-??-??) +~~~~~~~~~~~~~~~~~~ + +* Project Generator: fixed a VSCode C/C++'s "Cannot find" warning when CPPPATH folder does not exist + 3.6.6 (2019-03-29) ~~~~~~~~~~~~~~~~~~ diff --git a/platformio/ide/tpls/vscode/.vscode/c_cpp_properties.json.tpl b/platformio/ide/tpls/vscode/.vscode/c_cpp_properties.json.tpl index 75d77ffd..c91ab548 100644 --- a/platformio/ide/tpls/vscode/.vscode/c_cpp_properties.json.tpl +++ b/platformio/ide/tpls/vscode/.vscode/c_cpp_properties.json.tpl @@ -5,7 +5,7 @@ }, { % import platform -% from os.path import commonprefix, dirname +% from os.path import commonprefix, dirname, isdir % % systype = platform.system().lower() % @@ -15,7 +15,7 @@ % % cleaned_includes = [] % for include in includes: -% if "toolchain-" not in dirname(commonprefix([include, cc_path])): +% if "toolchain-" not in dirname(commonprefix([include, cc_path])) and isdir(include): % cleaned_includes.append(include) % end % end @@ -65,7 +65,7 @@ % if cxx_stds: "cppStandard": "c++{{ cxx_stds[-1] }}", % end - "compilerPath": "{{! _escape(cc_path) }} {{! _escape(cc_m_flags) }}" + "compilerPath": "\"{{! _escape(cc_path) }}\" {{! _escape(cc_m_flags) }}" } ] } \ No newline at end of file From 7d9e10095e2cca481ba4778304fe6da101b2439e Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 30 Mar 2019 13:00:10 +0200 Subject: [PATCH 03/45] Set manifest version of VSCode C/C++ configuration file --- platformio/ide/tpls/vscode/.vscode/c_cpp_properties.json.tpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platformio/ide/tpls/vscode/.vscode/c_cpp_properties.json.tpl b/platformio/ide/tpls/vscode/.vscode/c_cpp_properties.json.tpl index c91ab548..1658bcb4 100644 --- a/platformio/ide/tpls/vscode/.vscode/c_cpp_properties.json.tpl +++ b/platformio/ide/tpls/vscode/.vscode/c_cpp_properties.json.tpl @@ -67,5 +67,6 @@ % end "compilerPath": "\"{{! _escape(cc_path) }}\" {{! _escape(cc_m_flags) }}" } - ] + ], + "version": 4 } \ No newline at end of file From 29cf1c85965e5fb50d263c7ad1a7493663e9f386 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 5 Apr 2019 19:48:04 +0300 Subject: [PATCH 04/45] Fix "ValueError: invalid literal for int() with base 10" for click.get_terminal_size --- platformio/telemetry.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/platformio/telemetry.py b/platformio/telemetry.py index 7394654c..d0f4c468 100644 --- a/platformio/telemetry.py +++ b/platformio/telemetry.py @@ -66,7 +66,11 @@ class MeasurementProtocol(TelemetryBase): self['tid'] = self.TID self['cid'] = app.get_cid() - self['sr'] = "%dx%d" % click.get_terminal_size() + try: + self['sr'] = "%dx%d" % click.get_terminal_size() + except ValueError: + pass + self._prefill_screen_name() self._prefill_appinfo() self._prefill_custom_data() From 4edfb8f6ccad1237f4c67d772189042df1b8e04f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 17 Apr 2019 20:05:51 +0300 Subject: [PATCH 05/45] Cleanup PING_INTERNET_IPS --- platformio/util.py | 1 - 1 file changed, 1 deletion(-) diff --git a/platformio/util.py b/platformio/util.py index 777314f6..c04cd949 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -680,7 +680,6 @@ def get_api_result(url, params=None, data=None, auth=None, cache_valid=None): PING_INTERNET_IPS = [ "192.30.253.113", # github.com - "18.195.111.75", # dl.bintray.com "193.222.52.25" # dl.platformio.org ] From be24c6ab4d802143fa9295a276777d50208af780 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Apr 2019 14:17:22 +0300 Subject: [PATCH 06/45] Fix an issue when invalid "env_default" results into unhandled errors // Resolve #2265 --- HISTORY.rst | 4 ++++ platformio/commands/init.py | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index a6543f30..d34f4555 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -8,6 +8,10 @@ PlatformIO 3.0 ~~~~~~~~~~~~~~~~~~ * Project Generator: fixed a VSCode C/C++'s "Cannot find" warning when CPPPATH folder does not exist +* Fixed an "IndexError: list index out of range" for Arduino sketch preprocessor + (`issue #2268 `_) +* Fixed an issue when invalid "env_default" in `"platformio.ini" (Project Configuration File) `__ results into unhandled errors + (`issue #2265 `_) 3.6.6 (2019-03-29) ~~~~~~~~~~~~~~~~~~ diff --git a/platformio/commands/init.py b/platformio/commands/init.py index e90bc2fd..e7127313 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -23,6 +23,7 @@ import click from platformio import exception, util from platformio.commands.platform import \ platform_install as cli_platform_install +from platformio.commands.run import check_project_envs from platformio.ide.projectgenerator import ProjectGenerator from platformio.managers.platform import PlatformManager @@ -130,10 +131,11 @@ def get_best_envname(project_dir, boards=None): config = util.load_project_config(project_dir) env_default = None if config.has_option("platformio", "env_default"): - env_default = config.get("platformio", - "env_default").split(", ")[0].strip() + env_default = util.parse_conf_multi_values( + config.get("platformio", "env_default")) + check_project_envs(config, env_default) if env_default: - return env_default + return env_default[0] section = None for section in config.sections(): if not section.startswith("env:"): From 40d1bb204c2b2200bc136bcbd915afee20699f2a Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 19 Apr 2019 13:26:25 +0300 Subject: [PATCH 07/45] Docs: New boards by ESP32 dev/platform --- docs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs b/docs index 1532572c..26068f27 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 1532572c6259b98b687ca61abe80b35f8bc00093 +Subproject commit 26068f27c518b7f4b79660a9d4cad6e3db34f60c From 137a5d1c42bc4531ef5456413584588ab9b38141 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 23 Apr 2019 00:49:53 +0300 Subject: [PATCH 08/45] Improve debugging in `debug_load_mode = modified` and fix an issue with useless project rebuilding --- HISTORY.rst | 1 + platformio/builder/tools/piomisc.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 99c41cb5..75810755 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -16,6 +16,7 @@ PlatformIO 3.0 3.6.7 (2019-??-??) ~~~~~~~~~~~~~~~~~~ +* `PIO Unified Debugger `__: improved debugging in ``debug_load_mode = modified`` and fixed an issue with useless project rebuilding * Project Generator: fixed a VSCode C/C++'s "Cannot find" warning when CPPPATH folder does not exist * Fixed an "IndexError: list index out of range" for Arduino sketch preprocessor (`issue #2268 `_) diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 45212415..19a6a2ef 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -296,8 +296,7 @@ def ProcessDebug(env): if not env.subst("$PIODEBUGFLAGS"): env.Replace(PIODEBUGFLAGS=["-Og", "-g3", "-ggdb3"]) env.Append( - PIODEBUGFLAGS=["-D__PLATFORMIO_DEBUG__"], - BUILD_FLAGS=env.get("PIODEBUGFLAGS", [])) + BUILD_FLAGS=list(env['PIODEBUGFLAGS']) + ["-D__PLATFORMIO_DEBUG__"]) unflags = ["-Os"] for level in [0, 1, 2]: for flag in ("O", "g", "ggdb"): From 4d615416f3a1c6adbc6cdda1087ec1e09bcb46ef Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 23 Apr 2019 00:49:53 +0300 Subject: [PATCH 09/45] Improve debugging in `debug_load_mode = modified` and fix an issue with useless project rebuilding --- HISTORY.rst | 1 + platformio/builder/tools/piomisc.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index d34f4555..361b49c5 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -7,6 +7,7 @@ PlatformIO 3.0 3.6.7 (2019-??-??) ~~~~~~~~~~~~~~~~~~ +* `PIO Unified Debugger `__: improved debugging in ``debug_load_mode = modified`` and fixed an issue with useless project rebuilding * Project Generator: fixed a VSCode C/C++'s "Cannot find" warning when CPPPATH folder does not exist * Fixed an "IndexError: list index out of range" for Arduino sketch preprocessor (`issue #2268 `_) diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index c2173bd2..52df8b61 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -296,8 +296,7 @@ def ProcessDebug(env): if not env.subst("$PIODEBUGFLAGS"): env.Replace(PIODEBUGFLAGS=["-Og", "-g3", "-ggdb3"]) env.Append( - PIODEBUGFLAGS=["-D__PLATFORMIO_DEBUG__"], - BUILD_FLAGS=env.get("PIODEBUGFLAGS", [])) + BUILD_FLAGS=list(env['PIODEBUGFLAGS']) + ["-D__PLATFORMIO_DEBUG__"]) unflags = ["-Os"] for level in [0, 1, 2]: for flag in ("O", "g", "ggdb"): From e6a7cc2036d78b1da6a8a57f58204264f10316ed Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 23 Apr 2019 01:05:11 +0300 Subject: [PATCH 10/45] Update core package dependencies --- platformio/managers/core.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/platformio/managers/core.py b/platformio/managers/core.py index 34831b48..ec48ef07 100644 --- a/platformio/managers/core.py +++ b/platformio/managers/core.py @@ -24,9 +24,10 @@ from platformio import __version__, exception, util from platformio.managers.package import PackageManager CORE_PACKAGES = { - "contrib-piohome": "^2.0.0", - "contrib-pysite": "~2.%d%d.0" % (sys.version_info[0], sys.version_info[1]), - "tool-pioplus": "^2.0.0", + "contrib-piohome": "^2.0.1", + "contrib-pysite": + "~2.%d%d.190418" % (sys.version_info[0], sys.version_info[1]), + "tool-pioplus": "^2.1.4", "tool-unity": "~1.20403.0", "tool-scons": "~2.20501.7" } From d3c3491a91baa37f93d8981ff8ffaac23e23fa64 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 23 Apr 2019 01:07:21 +0300 Subject: [PATCH 11/45] Fix links in changelog --- HISTORY.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 75810755..fa11ace5 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -16,7 +16,7 @@ PlatformIO 3.0 3.6.7 (2019-??-??) ~~~~~~~~~~~~~~~~~~ -* `PIO Unified Debugger `__: improved debugging in ``debug_load_mode = modified`` and fixed an issue with useless project rebuilding +* `PIO Unified Debugger `__: improved debugging in ``debug_load_mode = modified`` and fixed an issue with useless project rebuilding * Project Generator: fixed a VSCode C/C++'s "Cannot find" warning when CPPPATH folder does not exist * Fixed an "IndexError: list index out of range" for Arduino sketch preprocessor (`issue #2268 `_) @@ -31,7 +31,7 @@ PlatformIO 3.0 * Fixed an issue when PlatformIO Build System does not pick up "mbed_lib.json" files from libraries (`issue #2164 `_) * Fixed an error with conflicting declaration of a prototype (Arduino sketch preprocessor) -* Fixed "FileExistsError" when `platformio ci `__ command is used in pair with ``--keep-build-dir`` option +* Fixed "FileExistsError" when `platformio ci `__ command is used in pair with ``--keep-build-dir`` option * Fixed an issue with incorrect order of project "include" and "src" paths in ``CPPPATH`` (`issue #1914 `_) @@ -41,7 +41,7 @@ PlatformIO 3.0 * Project Generator: added new targets for CLion IDE "BUILD_VERBOSE" and "MONITOR" (serial port monitor) (`issue #359 `_) * Fixed an issue with slow updating of PlatformIO Core packages on Windows -* Fixed an issue when `platformio ci `__ recompiles project if ``--keep-build-dir`` option is passed +* Fixed an issue when `platformio ci `__ recompiles project if ``--keep-build-dir`` option is passed (`issue #2109 `_) * Fixed an issue when ``$PROJECT_HASH`` template was not expanded for the other directory ``***_dir`` options in `"platformio.ini" (Project Configuration File) `__ (`issue #2170 `_) @@ -89,9 +89,9 @@ PlatformIO 3.0 * Generate an `include `__ and `test `__ directories with a README file when initializing a new project * Support in-line comments for multi-line value (``lib_deps``, ``build_flags``, etc) in `"platformio.ini" (Project Configuration File) `__ -* Added ``$PROJECT_HASH`` template variable for `build_dir `__. One of the use cases is setting a global storage for project artifacts using `PLATFORMIO_BUILD_DIR `__ system environment variable. For example, ``/tmp/pio-build/$PROJECT_HASH`` (Unix) or ``$[sysenv.TEMP}/pio-build/$PROJECT_HASH`` (Windows) +* Added ``$PROJECT_HASH`` template variable for `build_dir `__. One of the use cases is setting a global storage for project artifacts using `PLATFORMIO_BUILD_DIR `__ system environment variable. For example, ``/tmp/pio-build/$PROJECT_HASH`` (Unix) or ``$[sysenv.TEMP}/pio-build/$PROJECT_HASH`` (Windows) * Improved a loading speed of PIO Home "Recent News" -* Improved `PIO Unified Debugger `__ for "mbed" framework and fixed issue with missed local variables +* Improved `PIO Unified Debugger `__ for "mbed" framework and fixed issue with missed local variables * Introduced `"Release" and "Debug" Build Configurations `__ * Build project in "Debug Mode" including debugging information with a new ``debug`` target using `platformio run `__ command or `targets `__ option in ``platformio.ini``. The last option allows avoiding project rebuilding between "Run/Debug" modes. (`issue #1833 `_) @@ -149,7 +149,7 @@ PlatformIO 3.0 build environment (`issue #1665 `_) * Handle "architectures" data from "library.properties" manifest in - `lib_compat_mode = strict `__ + `lib_compat_mode = strict `__ * Added workaround for Python SemVer package's `issue #61 `_ with caret range and pre-releases * Replaced conflicted "env" pattern by "sysenv" for `"platformio.ini" Dynamic Variables" `__ (`issue #1705 `_) @@ -177,7 +177,7 @@ PlatformIO 3.0 (`issue #1612 `_) * Configure a custom path to SVD file using `debug_svd_path `__ option -* Custom project `description `_ +* Custom project `description `_ which will be used by `PlatformIO Home `_ * Updated Unity tool to 2.4.3 * Improved support for Black Magic Probe in "uploader" mode @@ -203,9 +203,9 @@ PlatformIO 3.0 - Multiple themes (Dark & Light) - Ability to specify a name for new project -* Control `PIO Unified Debugger `__ +* Control `PIO Unified Debugger `__ and its firmware loading mode using - `debug_load_mode `__ option + `debug_load_mode `__ option * Added aliases (off, light, strict) for `LDF Compatibility Mode `__ * Search for a library using PIO Library Registry ID ``id:X`` (e.g. ``pio lib search id:13``) From 20f28383a0abec7c0ed9f066cf62054866aa11b0 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 23 Apr 2019 01:07:21 +0300 Subject: [PATCH 12/45] Fix links in changelog --- HISTORY.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 361b49c5..17628a17 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -7,7 +7,7 @@ PlatformIO 3.0 3.6.7 (2019-??-??) ~~~~~~~~~~~~~~~~~~ -* `PIO Unified Debugger `__: improved debugging in ``debug_load_mode = modified`` and fixed an issue with useless project rebuilding +* `PIO Unified Debugger `__: improved debugging in ``debug_load_mode = modified`` and fixed an issue with useless project rebuilding * Project Generator: fixed a VSCode C/C++'s "Cannot find" warning when CPPPATH folder does not exist * Fixed an "IndexError: list index out of range" for Arduino sketch preprocessor (`issue #2268 `_) @@ -22,7 +22,7 @@ PlatformIO 3.0 * Fixed an issue when PlatformIO Build System does not pick up "mbed_lib.json" files from libraries (`issue #2164 `_) * Fixed an error with conflicting declaration of a prototype (Arduino sketch preprocessor) -* Fixed "FileExistsError" when `platformio ci `__ command is used in pair with ``--keep-build-dir`` option +* Fixed "FileExistsError" when `platformio ci `__ command is used in pair with ``--keep-build-dir`` option * Fixed an issue with incorrect order of project "include" and "src" paths in ``CPPPATH`` (`issue #1914 `_) @@ -32,7 +32,7 @@ PlatformIO 3.0 * Project Generator: added new targets for CLion IDE "BUILD_VERBOSE" and "MONITOR" (serial port monitor) (`issue #359 `_) * Fixed an issue with slow updating of PlatformIO Core packages on Windows -* Fixed an issue when `platformio ci `__ recompiles project if ``--keep-build-dir`` option is passed +* Fixed an issue when `platformio ci `__ recompiles project if ``--keep-build-dir`` option is passed (`issue #2109 `_) * Fixed an issue when ``$PROJECT_HASH`` template was not expanded for the other directory ``***_dir`` options in `"platformio.ini" (Project Configuration File) `__ (`issue #2170 `_) @@ -80,9 +80,9 @@ PlatformIO 3.0 * Generate an `include `__ and `test `__ directories with a README file when initializing a new project * Support in-line comments for multi-line value (``lib_deps``, ``build_flags``, etc) in `"platformio.ini" (Project Configuration File) `__ -* Added ``$PROJECT_HASH`` template variable for `build_dir `__. One of the use cases is setting a global storage for project artifacts using `PLATFORMIO_BUILD_DIR `__ system environment variable. For example, ``/tmp/pio-build/$PROJECT_HASH`` (Unix) or ``$[sysenv.TEMP}/pio-build/$PROJECT_HASH`` (Windows) +* Added ``$PROJECT_HASH`` template variable for `build_dir `__. One of the use cases is setting a global storage for project artifacts using `PLATFORMIO_BUILD_DIR `__ system environment variable. For example, ``/tmp/pio-build/$PROJECT_HASH`` (Unix) or ``$[sysenv.TEMP}/pio-build/$PROJECT_HASH`` (Windows) * Improved a loading speed of PIO Home "Recent News" -* Improved `PIO Unified Debugger `__ for "mbed" framework and fixed issue with missed local variables +* Improved `PIO Unified Debugger `__ for "mbed" framework and fixed issue with missed local variables * Introduced `"Release" and "Debug" Build Configurations `__ * Build project in "Debug Mode" including debugging information with a new ``debug`` target using `platformio run `__ command or `targets `__ option in ``platformio.ini``. The last option allows avoiding project rebuilding between "Run/Debug" modes. (`issue #1833 `_) @@ -140,7 +140,7 @@ PlatformIO 3.0 build environment (`issue #1665 `_) * Handle "architectures" data from "library.properties" manifest in - `lib_compat_mode = strict `__ + `lib_compat_mode = strict `__ * Added workaround for Python SemVer package's `issue #61 `_ with caret range and pre-releases * Replaced conflicted "env" pattern by "sysenv" for `"platformio.ini" Dynamic Variables" `__ (`issue #1705 `_) @@ -168,7 +168,7 @@ PlatformIO 3.0 (`issue #1612 `_) * Configure a custom path to SVD file using `debug_svd_path `__ option -* Custom project `description `_ +* Custom project `description `_ which will be used by `PlatformIO Home `_ * Updated Unity tool to 2.4.3 * Improved support for Black Magic Probe in "uploader" mode @@ -194,9 +194,9 @@ PlatformIO 3.0 - Multiple themes (Dark & Light) - Ability to specify a name for new project -* Control `PIO Unified Debugger `__ +* Control `PIO Unified Debugger `__ and its firmware loading mode using - `debug_load_mode `__ option + `debug_load_mode `__ option * Added aliases (off, light, strict) for `LDF Compatibility Mode `__ * Search for a library using PIO Library Registry ID ``id:X`` (e.g. ``pio lib search id:13``) From a59efc2fc03af8d67588c7273e83a6be0a2e73a7 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 23 Apr 2019 12:29:16 +0300 Subject: [PATCH 13/45] Update history with upcoming 3.6.7 release --- HISTORY.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index fa11ace5..48ef369c 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -13,7 +13,7 @@ PlatformIO 4.0 PlatformIO 3.0 -------------- -3.6.7 (2019-??-??) +3.6.7 (2019-04-23) ~~~~~~~~~~~~~~~~~~ * `PIO Unified Debugger `__: improved debugging in ``debug_load_mode = modified`` and fixed an issue with useless project rebuilding From d49d91269df966ad7edc549c8a9b8aabeb7609d9 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 23 Apr 2019 12:29:16 +0300 Subject: [PATCH 14/45] Update history with upcoming 3.6.7 release --- HISTORY.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index 17628a17..2c61d00d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -4,7 +4,7 @@ Release Notes PlatformIO 3.0 -------------- -3.6.7 (2019-??-??) +3.6.7 (2019-04-23) ~~~~~~~~~~~~~~~~~~ * `PIO Unified Debugger `__: improved debugging in ``debug_load_mode = modified`` and fixed an issue with useless project rebuilding From ee420cc35eec885c07589cc13fef44cb96c3dcde Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 23 Apr 2019 12:31:58 +0300 Subject: [PATCH 15/45] Bump version to 3.6.7 --- docs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs b/docs index 3a6c69a1..0c29f967 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 3a6c69a1ae227479321de75184aa8678104fc37f +Subproject commit 0c29f9671f44b5221e7cac15e93ebb40f9db88c1 From 9ca53c57f49a2d138cffe2c8720b320244e065ee Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 23 Apr 2019 12:32:18 +0300 Subject: [PATCH 16/45] Bump version to 3.6.7 --- platformio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 0b432099..d1d58c48 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 6, "7a1") +VERSION = (3, 6, 7) __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" From 9bdc85fd52ec1c45a88f25fb5d42cbf6ee1aa5dd Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 23 Apr 2019 12:49:36 +0300 Subject: [PATCH 17/45] Bump version to 4.0.0a8 --- platformio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 584acb8b..c1f0846d 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -VERSION = (4, 0, "0a7") +VERSION = (4, 0, "0a8") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" From e9df6166eeaf22544cd886409a1f8c9f73900492 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 24 Apr 2019 00:07:27 +0300 Subject: [PATCH 18/45] Update SCons to 3.0.5 --- platformio/managers/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/managers/core.py b/platformio/managers/core.py index 2f55aec4..05822f7a 100644 --- a/platformio/managers/core.py +++ b/platformio/managers/core.py @@ -29,7 +29,7 @@ CORE_PACKAGES = { "~2.%d%d.190418" % (sys.version_info[0], sys.version_info[1]), "tool-pioplus": "^2.1.4", "tool-unity": "~1.20403.0", - "tool-scons": "~2.20501.7" if util.PY2 else "~3.30003.0" + "tool-scons": "~2.20501.7" if util.PY2 else "~3.30005.0" } PIOPLUS_AUTO_UPDATES_MAX = 100 From ba6d120cf4966eddc40da68feb69369d05818e79 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 24 Apr 2019 00:14:53 +0300 Subject: [PATCH 19/45] Docs: Sync Atmel AVR dev/platform --- docs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs b/docs index 0c29f967..30a7a537 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 0c29f9671f44b5221e7cac15e93ebb40f9db88c1 +Subproject commit 30a7a53749867bea57fe4978fa27ac9e69e9d60a From eab2fd91fd4ae3bca108bc90025187802c4d87b9 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 25 Apr 2019 12:49:22 +0300 Subject: [PATCH 20/45] Lowercase SHA sum for package manager --- platformio/downloader.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/platformio/downloader.py b/platformio/downloader.py index d8b2fd24..0b0ef5df 100644 --- a/platformio/downloader.py +++ b/platformio/downloader.py @@ -100,7 +100,7 @@ class FileDownloader(object): raise FDSizeMismatch(_dlsize, self._fname, self.get_size()) if not sha1: - return + return None dlsha1 = None try: @@ -113,11 +113,12 @@ class FileDownloader(object): dlsha1 = result['out'] except (OSError, ValueError): pass - - if dlsha1: - dlsha1 = dlsha1[1:41] if dlsha1.startswith("\\") else dlsha1[:40] - if sha1 != dlsha1: - raise FDSHASumMismatch(dlsha1, self._fname, sha1) + if not dlsha1: + return None + dlsha1 = dlsha1[1:41] if dlsha1.startswith("\\") else dlsha1[:40] + if sha1.lower() != dlsha1.lower(): + raise FDSHASumMismatch(dlsha1, self._fname, sha1) + return True def _preserve_filemtime(self, lmdate): timedata = parsedate_tz(lmdate) From 48c1aeae035ab5afad9811ec621018b4059a8991 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 3 May 2019 13:11:03 +0300 Subject: [PATCH 21/45] Fix "systemd-udevd" warnings in 99-platformio-udev.rules // Resolve #2442 --- HISTORY.rst | 6 + scripts/99-platformio-udev.rules | 202 +++++++++++++++---------------- 2 files changed, 107 insertions(+), 101 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 48ef369c..96025861 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -13,6 +13,12 @@ PlatformIO 4.0 PlatformIO 3.0 -------------- +3.6.8 (2019-??-??) +~~~~~~~~~~~~~~~~~~ + +* Fixed "systemd-udevd" warnings in `99-platformio-udev.rules `__ + (`issue #2442 `_) + 3.6.7 (2019-04-23) ~~~~~~~~~~~~~~~~~~ diff --git a/scripts/99-platformio-udev.rules b/scripts/99-platformio-udev.rules index 99755db1..f3249682 100644 --- a/scripts/99-platformio-udev.rules +++ b/scripts/99-platformio-udev.rules @@ -84,176 +84,176 @@ SUBSYSTEM=="tty", ATTRS{interface}=="Black Magic GDB Server" SUBSYSTEM=="tty", ATTRS{interface}=="Black Magic UART Port" # opendous and estick -ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204f", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204f", MODE="0666" # Original FT232/FT245 VID:PID -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="0666" # Original FT2232 VID:PID -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="0666" # Original FT4232 VID:PID -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="0666" # Original FT232H VID:PID -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="0666" # DISTORTEC JTAG-lock-pick Tiny 2 -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8220", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8220", MODE="0666" # TUMPA, TUMPA Lite -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a98", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a99", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a98", MODE="0666" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a99", MODE="0666" # XDS100v2 -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d0", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d0", MODE="0666" # Xverve Signalyzer Tool (DT-USB-ST), Signalyzer LITE (DT-USB-SLITE) -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca1", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="0666" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca1", MODE="0666" # TI/Luminary Stellaris Evaluation Board FTDI (several) -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd9", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd9", MODE="0666" # TI/Luminary Stellaris In-Circuit Debug Interface FTDI (ICDI) Board -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcda", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcda", MODE="0666" # egnite Turtelizer 2 -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bdc8", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bdc8", MODE="0666" # Section5 ICEbear -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c140", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c140", MODE="0666" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="0666" # Amontec JTAGkey and JTAGkey-tiny -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="0666" # TI ICDI -ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="0666" # STLink v1 -ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3744", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3744", MODE="0666" # STLink v2 -ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE="0666" # STLink v2-1 -ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", MODE="0666" # Hilscher NXHX Boards -ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="0666" # Hitex STR9-comStick -ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002c", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002c", MODE="0666" # Hitex STM32-PerformanceStick -ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="0666" # Altera USB Blaster -ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6001", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6001", MODE="0666" # Amontec JTAGkey-HiSpeed -ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="0666" # SEGGER J-Link -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0101", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0102", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0103", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0104", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0105", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0107", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0108", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1010", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1011", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1012", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1013", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1014", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1015", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1016", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1017", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1018", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0101", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0102", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0103", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0104", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0105", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0107", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0108", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1010", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1011", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1012", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1013", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1014", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1015", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1016", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1017", MODE="0666" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1018", MODE="0666" # Raisonance RLink -ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="0666" # Debug Board for Neo1973 -ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="0666" # Olimex ARM-USB-OCD -ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="0666" # Olimex ARM-USB-OCD-TINY -ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0004", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0004", MODE="0666" # Olimex ARM-JTAG-EW -ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="001e", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="001e", MODE="0666" # Olimex ARM-USB-OCD-TINY-H -ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="0666" # Olimex ARM-USB-OCD-H -ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002b", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002b", MODE="0666" # USBprog with OpenOCD firmware -ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="0666" # TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board -ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="0666" # Marvell Sheevaplug -ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="0666" # Keil Software, Inc. ULink -ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2710", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2710", MODE="0666" # CMSIS-DAP compatible adapters -ATTRS{product}=="*CMSIS-DAP*", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{product}=="*CMSIS-DAP*", MODE="0666" #SEGGER J-LIK -ATTR{idProduct}=="1001", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1002", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1003", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1004", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1005", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1006", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1007", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1008", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1009", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="100a", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="100b", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="100c", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="100d", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="100e", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="100f", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1010", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1011", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1012", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1013", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1014", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1015", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1016", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1017", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1018", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1019", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="101a", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="101b", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="101c", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="101d", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="101e", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="101f", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1020", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1021", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1022", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1023", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1024", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1025", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1026", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1027", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1028", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="1029", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="102a", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="102b", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="102c", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="102d", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="102e", ATTR{idVendor}=="1366", MODE="666" -ATTR{idProduct}=="102f", ATTR{idVendor}=="1366", MODE="666" +ATTR{idProduct}=="1001", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1002", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1003", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1004", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1005", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1006", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1007", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1008", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1009", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="100a", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="100b", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="100c", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="100d", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="100e", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="100f", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1010", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1011", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1012", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1013", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1014", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1015", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1016", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1017", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1018", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1019", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="101a", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="101b", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="101c", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="101d", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="101e", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="101f", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1020", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1021", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1022", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1023", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1024", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1025", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1026", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1027", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1028", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="1029", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="102a", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="102b", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="102c", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="102d", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="102e", ATTR{idVendor}=="1366", MODE="0666" +ATTR{idProduct}=="102f", ATTR{idVendor}=="1366", MODE="0666" From 41ff1b0188d19c7faa116265b7cb1b31521e1536 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 3 May 2019 16:56:44 +0300 Subject: [PATCH 22/45] Support for Kendryte K210 // Resolve #2233 --- README.rst | 6 ++++++ docs | 2 +- examples | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 76e1665c..ee1f6896 100644 --- a/README.rst +++ b/README.rst @@ -78,6 +78,7 @@ Registry Development Platforms --------------------- +* `Aceinna IMU `_ * `Atmel AVR `_ * `Atmel SAM `_ * `Espressif 32 `_ @@ -86,6 +87,7 @@ Development Platforms * `Infineon XMC `_ * `Intel ARC32 `_ * `Intel MCS-51 (8051) `_ +* `Kendryte K210 `_ * `Lattice iCE40 `_ * `Maxim 32 `_ * `Microchip PIC32 `_ @@ -93,6 +95,7 @@ Development Platforms * `Nordic nRF52 `_ * `NXP LPC `_ * `RISC-V `_ +* `RISC-V GAP `_ * `Samsung ARTIK `_ * `Silicon Labs EFM32 `_ * `ST STM32 `_ @@ -112,8 +115,11 @@ Frameworks * `ESP-IDF `_ * `ESP8266 Non-OS SDK `_ * `ESP8266 RTOS SDK `_ +* `Freedom E SDK `_ +* `Kendryte Standalone SDK `_ * `libOpenCM3 `_ * `mbed `_ +* `PULP OS `_ * `Pumbaa `_ * `Simba `_ * `SPL `_ diff --git a/docs b/docs index 30a7a537..4350844c 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 30a7a53749867bea57fe4978fa27ac9e69e9d60a +Subproject commit 4350844cafefed1787db7d360710ada8d892df31 diff --git a/examples b/examples index 9c16f551..46bac491 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 9c16f551d72e37aa4c2f28555487e2fb23408b5d +Subproject commit 46bac491dc59bfdc3baf8edafe091cd8b30b0d10 From 8e55c9e4d07a2b9a86bf3a5d9d3015b6d19514fe Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 3 May 2019 21:03:36 +0300 Subject: [PATCH 23/45] Include external configuration files with "extra_configs" option // Resolve #1590 --- .pylintrc | 2 +- HISTORY.rst | 4 +- docs | 2 +- platformio/commands/run.py | 2 +- platformio/exception.py | 2 +- platformio/project/__init__.py | 13 ++++ platformio/project/config.py | 106 +++++++++++++++++++++++++++++++++ platformio/util.py | 62 ++----------------- tests/test_projectconf.py | 74 +++++++++++++++++++++++ 9 files changed, 205 insertions(+), 62 deletions(-) create mode 100644 platformio/project/__init__.py create mode 100644 platformio/project/config.py create mode 100644 tests/test_projectconf.py diff --git a/.pylintrc b/.pylintrc index 09569a4f..bbaef24a 100644 --- a/.pylintrc +++ b/.pylintrc @@ -20,4 +20,4 @@ confidence= # --disable=W" # disable=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating -disable=locally-disabled,missing-docstring,invalid-name,too-few-public-methods,redefined-variable-type,import-error,similarities,unsupported-membership-test,unsubscriptable-object,ungrouped-imports,cyclic-import,superfluous-parens,useless-object-inheritance,useless-import-alias +disable=fixme,locally-disabled,missing-docstring,invalid-name,too-few-public-methods,redefined-variable-type,import-error,similarities,unsupported-membership-test,unsubscriptable-object,ungrouped-imports,cyclic-import,superfluous-parens,useless-object-inheritance,useless-import-alias diff --git a/HISTORY.rst b/HISTORY.rst index 96025861..bd899a08 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -7,8 +7,10 @@ PlatformIO 4.0 4.0.0 (2019-??-??) ~~~~~~~~~~~~~~~~~~ -* Added Python 3.5+ support +* Python 3 support (`issue #895 `_) +* Include external configuration files with "extra_configs" option + (`issue #1590 `_) PlatformIO 3.0 -------------- diff --git a/docs b/docs index 4350844c..9a51b847 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 4350844cafefed1787db7d360710ada8d892df31 +Subproject commit 9a51b847424c85444f4b9c38efad9d83f72353be diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 7cac3eca..b480ae2a 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -130,7 +130,7 @@ class EnvironmentProcessor(object): KNOWN_PLATFORMIO_OPTIONS = [ "description", "env_default", "home_dir", "lib_dir", "libdeps_dir", "include_dir", "src_dir", "build_dir", "data_dir", "test_dir", - "boards_dir", "lib_extra_dirs" + "boards_dir", "lib_extra_dirs", "extra_configs" ] KNOWN_ENV_OPTIONS = [ diff --git a/platformio/exception.py b/platformio/exception.py index 7829b648..92ffd6c5 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -207,7 +207,7 @@ class InvalidLibConfURL(PlatformioException): class InvalidProjectConf(PlatformioException): - MESSAGE = "Invalid `platformio.ini`, project configuration file: '{0}'" + MESSAGE = ("Invalid '{0}' (project configuration file): '{1}'") class BuildScriptNotFound(PlatformioException): diff --git a/platformio/project/__init__.py b/platformio/project/__init__.py new file mode 100644 index 00000000..b0514903 --- /dev/null +++ b/platformio/project/__init__.py @@ -0,0 +1,13 @@ +# 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. diff --git a/platformio/project/config.py b/platformio/project/config.py new file mode 100644 index 00000000..9883ffb7 --- /dev/null +++ b/platformio/project/config.py @@ -0,0 +1,106 @@ +# 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 glob +import os +import re + +import click + +from platformio import exception + +try: + import ConfigParser as ConfigParser +except ImportError: + import configparser as ConfigParser + + +class ProjectConfig(object): + + VARTPL_RE = re.compile(r"\$\{([^\.\}]+)\.([^\}]+)\}") + + _parser = None + _parsed = [] + + @staticmethod + def parse_multi_values(items): + result = [] + if not items: + return result + inline_comment_re = re.compile(r"\s+;.*$") + for item in items.split("\n" if "\n" in items else ", "): + item = item.strip() + # comment + if not item or item.startswith((";", "#")): + continue + if ";" in item: + item = inline_comment_re.sub("", item).strip() + result.append(item) + return result + + def __init__(self, path): + self.path = path + self._parsed = [] + self._parser = ConfigParser.ConfigParser() + self.read(path) + + def read(self, path): + if path in self._parsed: + return + self._parsed.append(path) + try: + self._parser.read(path) + except ConfigParser.Error as e: + raise exception.InvalidProjectConf(path, str(e)) + + # load extra configs + if (not self._parser.has_section("platformio") + or not self._parser.has_option("platformio", "extra_configs")): + return + extra_configs = self.parse_multi_values( + self.get("platformio", "extra_configs")) + for pattern in extra_configs: + for item in glob.glob(pattern): + self.read(item) + + def __getattr__(self, name): + return getattr(self._parser, name) + + def items(self, section): + items = [] + for option in self._parser.options(section): + items.append((option, self._parser.get(section, option))) + return items + + def get(self, section, option): + try: + value = self._parser.get(section, option) + except ConfigParser.Error as e: + raise exception.InvalidProjectConf(self.path, str(e)) + if "${" not in value or "}" not in value: + return value + return self.VARTPL_RE.sub(self._re_sub_handler, value) + + def _re_sub_handler(self, match): + section, option = match.group(1), match.group(2) + if section in ("env", + "sysenv") and not self._parser.has_section(section): + if section == "env": + click.secho( + "Warning! Access to system environment variable via " + "`${{env.{0}}}` is deprecated. Please use " + "`${{sysenv.{0}}}` instead".format(option), + fg="yellow") + return os.getenv(option) + return self._parser.get(section, option) diff --git a/platformio/util.py b/platformio/util.py index dd280ba2..1adcd936 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -33,52 +33,17 @@ import click import requests from platformio import __apiurl__, __version__, exception +from platformio.project.config import ProjectConfig # pylint: disable=too-many-ancestors PY2 = sys.version_info[0] == 2 if PY2: - import ConfigParser as ConfigParser string_types = basestring # pylint: disable=undefined-variable else: - import configparser as ConfigParser string_types = str -class ProjectConfig(ConfigParser.ConfigParser): - - VARTPL_RE = re.compile(r"\$\{([^\.\}]+)\.([^\}]+)\}") - - def items(self, section, **_): # pylint: disable=arguments-differ - items = [] - for option in ConfigParser.ConfigParser.options(self, section): - items.append((option, self.get(section, option))) - return items - - def get( # pylint: disable=arguments-differ - self, section, option, **kwargs): - try: - value = ConfigParser.ConfigParser.get(self, section, option, - **kwargs) - except ConfigParser.Error as e: - raise exception.InvalidProjectConf(str(e)) - if "${" not in value or "}" not in value: - return value - return self.VARTPL_RE.sub(self._re_sub_handler, value) - - def _re_sub_handler(self, match): - section, option = match.group(1), match.group(2) - if section in ("env", "sysenv") and not self.has_section(section): - if section == "env": - click.secho( - "Warning! Access to system environment variable via " - "`${{env.{0}}}` is deprecated. Please use " - "`${{sysenv.{0}}}` instead".format(option), - fg="yellow") - return os.getenv(option) - return self.get(section, option) - - class AsyncPipe(Thread): def __init__(self, outcallback=None): @@ -347,34 +312,17 @@ def get_projectdata_dir(): "data")) -def load_project_config(path=None): +def load_project_config(path=None): # FIXME: if not path or isdir(path): path = join(path or get_project_dir(), "platformio.ini") if not isfile(path): raise exception.NotPlatformIOProject( dirname(path) if path.endswith("platformio.ini") else path) - cp = ProjectConfig() - try: - cp.read(path) - except ConfigParser.Error as e: - raise exception.InvalidProjectConf(str(e)) - return cp + return ProjectConfig(path) -def parse_conf_multi_values(items): - result = [] - if not items: - return result - inline_comment_re = re.compile(r"\s+;.*$") - for item in items.split("\n" if "\n" in items else ", "): - item = item.strip() - # comment - if not item or item.startswith((";", "#")): - continue - if ";" in item: - item = inline_comment_re.sub("", item).strip() - result.append(item) - return result +def parse_conf_multi_values(items): # FIXME: + return ProjectConfig.parse_multi_values(items) def change_filemtime(path, mtime): diff --git a/tests/test_projectconf.py b/tests/test_projectconf.py new file mode 100644 index 00000000..ba10d1c4 --- /dev/null +++ b/tests/test_projectconf.py @@ -0,0 +1,74 @@ +# 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 platformio.project.config import ProjectConfig + +BASE_CONFIG = """ +[platformio] +extra_configs = + extra_envs.ini + extra_debug.ini + +[common] +debug_flags = -D RELEASE +lib_flags = -lc -lm + +[env:esp-wrover-kit] +platform = espressif32 +framework = espidf +board = esp-wrover-kit +build_flags = ${common.debug_flags} +""" + +EXTRA_ENVS_CONFIG = """ +[env:esp32dev] +platform = espressif32 +framework = espidf +board = esp32dev +build_flags = ${common.lib_flags} ${common.debug_flags} + +[env:lolin32] +platform = espressif32 +framework = espidf +board = lolin32 +build_flags = ${common.debug_flags} +""" + +EXTRA_DEBUG_CONFIG = """ +# Override base "common.debug_flags" +[common] +debug_flags = -D DEBUG=1 + +[env:lolin32] +build_flags = -Og +""" + + +def test_parser(tmpdir): + tmpdir.join("platformio.ini").write(BASE_CONFIG) + tmpdir.join("extra_envs.ini").write(EXTRA_ENVS_CONFIG) + tmpdir.join("extra_debug.ini").write(EXTRA_DEBUG_CONFIG) + + config = None + with tmpdir.as_cwd(): + config = ProjectConfig(tmpdir.join("platformio.ini").strpath) + assert config + + assert config.sections() == [ + "platformio", "common", "env:esp-wrover-kit", "env:esp32dev", + "env:lolin32" + ] + assert config.get("common", "debug_flags") == "-D DEBUG=1" + assert config.get("env:esp32dev", "build_flags") == "-lc -lm -D DEBUG=1" + assert config.get("env:lolin32", "build_flags") == "-Og" From 2c0e0b26194ff60f24772d399102811fb9cabef6 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 3 May 2019 21:14:08 +0300 Subject: [PATCH 24/45] Bump version to 4.0.0a9 --- platformio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index c1f0846d..dbc2bf6e 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -VERSION = (4, 0, "0a8") +VERSION = (4, 0, "0a9") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" From 7f607b742fd98ba591fb384f2d1471fb0da13f89 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 4 May 2019 12:23:23 +0300 Subject: [PATCH 25/45] Fix issue when handling dynamic variables --- platformio/project/config.py | 6 +++--- tests/test_projectconf.py | 23 +++++++++++++++++++++-- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/platformio/project/config.py b/platformio/project/config.py index 9883ffb7..61e22473 100644 --- a/platformio/project/config.py +++ b/platformio/project/config.py @@ -80,7 +80,7 @@ class ProjectConfig(object): def items(self, section): items = [] for option in self._parser.options(section): - items.append((option, self._parser.get(section, option))) + items.append((option, self.get(section, option))) return items def get(self, section, option): @@ -95,7 +95,7 @@ class ProjectConfig(object): def _re_sub_handler(self, match): section, option = match.group(1), match.group(2) if section in ("env", - "sysenv") and not self._parser.has_section(section): + "sysenv") and not self.has_section(section): if section == "env": click.secho( "Warning! Access to system environment variable via " @@ -103,4 +103,4 @@ class ProjectConfig(object): "`${{sysenv.{0}}}` instead".format(option), fg="yellow") return os.getenv(option) - return self._parser.get(section, option) + return self.get(section, option) diff --git a/tests/test_projectconf.py b/tests/test_projectconf.py index ba10d1c4..f47ae9af 100644 --- a/tests/test_projectconf.py +++ b/tests/test_projectconf.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os from platformio.project.config import ProjectConfig BASE_CONFIG = """ @@ -23,12 +24,13 @@ extra_configs = [common] debug_flags = -D RELEASE lib_flags = -lc -lm +extra_flags = ${sysenv.__PIO_TEST_CNF_EXTRA_FLAGS} [env:esp-wrover-kit] platform = espressif32 framework = espidf board = esp-wrover-kit -build_flags = ${common.debug_flags} +build_flags = ${common.debug_flags} ${common.extra_flags} """ EXTRA_ENVS_CONFIG = """ @@ -42,7 +44,7 @@ build_flags = ${common.lib_flags} ${common.debug_flags} platform = espressif32 framework = espidf board = lolin32 -build_flags = ${common.debug_flags} +build_flags = ${common.debug_flags} ${common.extra_flags} """ EXTRA_DEBUG_CONFIG = """ @@ -65,10 +67,27 @@ def test_parser(tmpdir): config = ProjectConfig(tmpdir.join("platformio.ini").strpath) assert config + # sections assert config.sections() == [ "platformio", "common", "env:esp-wrover-kit", "env:esp32dev", "env:lolin32" ] + + # sysenv + assert config.get("common", "extra_flags") == "" + os.environ["__PIO_TEST_CNF_EXTRA_FLAGS"] = "-L /usr/local/lib" + assert config.get("common", "extra_flags") == "-L /usr/local/lib" + + # get assert config.get("common", "debug_flags") == "-D DEBUG=1" assert config.get("env:esp32dev", "build_flags") == "-lc -lm -D DEBUG=1" assert config.get("env:lolin32", "build_flags") == "-Og" + assert config.get("env:esp-wrover-kit", + "build_flags") == ("-D DEBUG=1 -L /usr/local/lib") + + # items + assert config.items("env:esp32dev") == [("platform", "espressif32"), + ("framework", "espidf"), + ("board", "esp32dev"), + ("build_flags", + "-lc -lm -D DEBUG=1")] From e4dca378743563de22a654c828468a058963de4a Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 4 May 2019 12:23:51 +0300 Subject: [PATCH 26/45] Bump version to 4.0.0a10 --- platformio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index dbc2bf6e..6d00c736 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -VERSION = (4, 0, "0a9") +VERSION = (4, 0, "0a10") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" From 94e580bf4ecd8b3019aa86987526e893d5b82c2f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 4 May 2019 13:36:27 +0300 Subject: [PATCH 27/45] Override default source and include directories for a library via "library.json" manifest using "includeDir" and "srcDir" fields --- HISTORY.rst | 5 +++-- docs | 2 +- platformio/builder/tools/piolib.py | 12 ++++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index bd899a08..0ce2bb74 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -9,8 +9,9 @@ PlatformIO 4.0 * Python 3 support (`issue #895 `_) -* Include external configuration files with "extra_configs" option +* Include external configuration files with `extra_configs `__ option (`issue #1590 `_) +* Override default source and include directories for a library via `library.json `__ manifest using ``includeDir`` and ``srcDir`` fields PlatformIO 3.0 -------------- @@ -18,7 +19,7 @@ PlatformIO 3.0 3.6.8 (2019-??-??) ~~~~~~~~~~~~~~~~~~ -* Fixed "systemd-udevd" warnings in `99-platformio-udev.rules `__ +* Fixed "systemd-udevd" warnings in `99-platformio-udev.rules `__ (`issue #2442 `_) 3.6.7 (2019-04-23) diff --git a/docs b/docs index 9a51b847..570187b4 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 9a51b847424c85444f4b9c38efad9d83f72353be +Subproject commit 570187b4afdf8295880cd37177596e023df4d117 diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 221df7e8..54961eb0 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -719,6 +719,18 @@ class PlatformIOLibBuilder(LibBuilderBase): def _is_arduino_manifest(self): return isfile(join(self.path, "library.properties")) + @property + def include_dir(self): + if "includeDir" in self._manifest.get("build", {}): + return self._manifest.get("build").get("includeDir") + return LibBuilderBase.include_dir.fget(self) + + @property + def src_dir(self): + if "srcDir" in self._manifest.get("build", {}): + return self._manifest.get("build").get("srcDir") + return LibBuilderBase.src_dir.fget(self) + @property def src_filter(self): if "srcFilter" in self._manifest.get("build", {}): From 95b9ae9f2400a8b411bccea1cec960a259d29af0 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 6 May 2019 13:38:48 +0300 Subject: [PATCH 28/45] Docs: Sync Atmel SAM boards --- docs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs b/docs index 570187b4..e7d578dc 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 570187b4afdf8295880cd37177596e023df4d117 +Subproject commit e7d578dc24082763478179ccec3b9a4220dd783b From 4fdd51e19094583758e9e1963ef97fd59c0d4dd1 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 7 May 2019 13:26:10 +0300 Subject: [PATCH 29/45] Docs: Sync MCS51 boards --- docs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs b/docs index e7d578dc..5df8f4b0 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit e7d578dc24082763478179ccec3b9a4220dd783b +Subproject commit 5df8f4b066cebfa41e46db058936b2aa8298a70b From 1b4f94590708b6269f4ba7f9bd205dafde2eb4bc Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 7 May 2019 15:59:09 +0300 Subject: [PATCH 30/45] Remove support for renamed dev/platforms --- platformio/commands/run.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/platformio/commands/run.py b/platformio/commands/run.py index b480ae2a..817df353 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -168,8 +168,6 @@ class EnvironmentProcessor(object): "board_flash_mode": "board_build.flash_mode" } - RENAMED_PLATFORMS = {"espressif": "espressif8266"} - def __init__( self, # pylint: disable=R0913 cmd_ctx, @@ -231,14 +229,6 @@ class EnvironmentProcessor(object): "`%s` instead." % (k, self.RENAMED_OPTIONS[k]), fg="yellow") k = self.RENAMED_OPTIONS[k] - # process renamed platforms - if k == "platform" and v in self.RENAMED_PLATFORMS: - click.secho( - "Warning! Platform `%s` is deprecated and will be " - "removed in the next release! Please use " - "`%s` instead." % (v, self.RENAMED_PLATFORMS[v]), - fg="yellow") - v = self.RENAMED_PLATFORMS[v] # warn about unknown options unknown_conditions = [ From c235974eb63253f2a501fa4289bc2ac25bbd8f96 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 7 May 2019 17:51:50 +0300 Subject: [PATCH 31/45] Switch to the new ProjectConfig API --- platformio/commands/ci.py | 5 +- platformio/commands/device.py | 38 ++---- platformio/commands/init.py | 22 ++-- platformio/commands/run.py | 99 ++------------ platformio/exception.py | 167 ++++++++++++++---------- platformio/ide/projectgenerator.py | 14 +- platformio/project/config.py | 199 +++++++++++++++++++++++++++-- platformio/telemetry.py | 9 +- platformio/util.py | 7 +- tests/conftest.py | 6 +- tests/test_projectconf.py | 11 +- 11 files changed, 354 insertions(+), 223 deletions(-) diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index e1b60087..18845592 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -25,6 +25,7 @@ from platformio.commands.init import cli as cmd_init from platformio.commands.init import validate_boards from platformio.commands.run import cli as cmd_run from platformio.exception import CIBuildEnvsEmpty +from platformio.project.config import ProjectConfig def validate_path(ctx, param, value): # pylint: disable=unused-argument @@ -161,8 +162,8 @@ def _exclude_contents(dst_dir, patterns): def _copy_project_conf(build_dir, project_conf): - config = util.load_project_config(project_conf) + config = ProjectConfig(project_conf, parse_extra=False) if config.has_section("platformio"): config.remove_section("platformio") - with open(join(build_dir, "platformio.ini"), "w") as fp: + with open(join(build_dir, "platformio.ini"), "wb") as fp: config.write(fp) diff --git a/platformio/commands/device.py b/platformio/commands/device.py index 0a8ea38f..42bd4f6c 100644 --- a/platformio/commands/device.py +++ b/platformio/commands/device.py @@ -15,11 +15,13 @@ import json import sys from os import getcwd +from os.path import join import click from serial.tools import miniterm from platformio import exception, util +from platformio.project.config import ProjectConfig @click.group(short_help="Monitor device or list existing") @@ -161,11 +163,10 @@ def device_list( # pylint: disable=too-many-branches help="Load configuration from `platformio.ini` and specified environment") def device_monitor(**kwargs): # pylint: disable=too-many-branches try: - project_options = get_project_options(kwargs['project_dir'], + monitor_options = get_project_options(kwargs['project_dir'], kwargs['environment']) - monitor_options = {k: v for k, v in project_options or []} if monitor_options: - for k in ("port", "baud", "speed", "rts", "dtr"): + for k in ("port", "speed", "rts", "dtr"): k2 = "monitor_%s" % k if k == "speed": k = "baud" @@ -205,24 +206,13 @@ def device_monitor(**kwargs): # pylint: disable=too-many-branches raise exception.MinitermException(e) -def get_project_options(project_dir, environment): - config = util.load_project_config(project_dir) - if not config.sections(): - return None - - known_envs = [s[4:] for s in config.sections() if s.startswith("env:")] - if environment: - if environment in known_envs: - return config.items("env:%s" % environment) - raise exception.UnknownEnvNames(environment, ", ".join(known_envs)) - - if not known_envs: - return None - - if config.has_option("platformio", "env_default"): - env_default = config.get("platformio", - "env_default").split(", ")[0].strip() - if env_default and env_default in known_envs: - return config.items("env:%s" % env_default) - - return config.items("env:%s" % known_envs[0]) +def get_project_options(project_dir, environment=None): + config = ProjectConfig.get_instance(join(project_dir, "platformio.ini")) + config.validate(envs=[environment] if environment else None) + if not environment: + default_envs = config.default_envs() + if default_envs: + environment = default_envs[0] + else: + environment = config.envs()[0] + return {k: v for k, v in config.items(env=environment)} diff --git a/platformio/commands/init.py b/platformio/commands/init.py index e7127313..db45ddfc 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -23,9 +23,9 @@ import click from platformio import exception, util from platformio.commands.platform import \ platform_install as cli_platform_install -from platformio.commands.run import check_project_envs from platformio.ide.projectgenerator import ProjectGenerator from platformio.managers.platform import PlatformManager +from platformio.project.config import ProjectConfig def validate_boards(ctx, param, value): # pylint: disable=W0613 @@ -128,14 +128,11 @@ def cli( def get_best_envname(project_dir, boards=None): - config = util.load_project_config(project_dir) - env_default = None - if config.has_option("platformio", "env_default"): - env_default = util.parse_conf_multi_values( - config.get("platformio", "env_default")) - check_project_envs(config, env_default) - if env_default: - return env_default[0] + config = ProjectConfig(join(project_dir, "platformio.ini")) + config.validate() + default_envs = config.default_envs() + if default_envs: + return default_envs[0] section = None for section in config.sections(): if not section.startswith("env:"): @@ -369,7 +366,8 @@ def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix, used_boards = [] used_platforms = [] - config = util.load_project_config(project_dir) + config_path = join(project_dir, "platformio.ini") + config = util.load_project_config(config_path) for section in config.sections(): cond = [ section.startswith("env:"), @@ -409,10 +407,12 @@ def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix, if not content: return - with open(join(project_dir, "platformio.ini"), "a") as f: + with open(config_path, "a") as f: content.append("") f.write("\n".join(content)) + ProjectConfig.reset_instances() + def _install_dependent_platforms(ctx, platforms): installed_platforms = [ diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 817df353..baff6a54 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -26,6 +26,7 @@ from platformio.commands.platform import \ platform_install as cmd_platform_install from platformio.managers.lib import LibraryManager, is_builtin_lib from platformio.managers.platform import PlatformFactory +from platformio.project.config import ProjectConfig # pylint: disable=too-many-arguments,too-many-locals,too-many-branches @@ -54,9 +55,6 @@ def cli(ctx, environment, target, upload_port, project_dir, silent, verbose, if isfile(project_dir): project_dir = util.find_project_dir_above(project_dir) - if not util.is_platformio_project(project_dir): - raise exception.NotPlatformIOProject(project_dir) - with util.cd(project_dir): # clean obsolete build dir if not disable_auto_clean: @@ -69,25 +67,17 @@ def cli(ctx, environment, target, upload_port, project_dir, silent, verbose, util.get_projectbuild_dir(force=True), fg="yellow") - config = util.load_project_config() - env_default = None - if config.has_option("platformio", "env_default"): - env_default = util.parse_conf_multi_values( - config.get("platformio", "env_default")) - - check_project_defopts(config) - check_project_envs(config, environment or env_default) + config = ProjectConfig.get_instance( + join(project_dir, "platformio.ini")) + config.validate() results = [] start_time = time() - for section in config.sections(): - if not section.startswith("env:"): - continue - - envname = section[4:] + default_envs = config.default_envs() + for envname in config.envs(): skipenv = any([ environment and envname not in environment, not environment - and env_default and envname not in env_default + and default_envs and envname not in default_envs ]) if skipenv: results.append((envname, None)) @@ -97,7 +87,7 @@ def cli(ctx, environment, target, upload_port, project_dir, silent, verbose, click.echo() options = {} - for k, v in config.items(section): + for k, v in config.items(env=envname): options[k] = v if "piotest" not in options and "piotest" in ctx.meta: options['piotest'] = ctx.meta['piotest'] @@ -127,26 +117,6 @@ class EnvironmentProcessor(object): DEFAULT_DUMP_OPTIONS = ("platform", "framework", "board") - KNOWN_PLATFORMIO_OPTIONS = [ - "description", "env_default", "home_dir", "lib_dir", "libdeps_dir", - "include_dir", "src_dir", "build_dir", "data_dir", "test_dir", - "boards_dir", "lib_extra_dirs", "extra_configs" - ] - - KNOWN_ENV_OPTIONS = [ - "platform", "framework", "board", "build_flags", "src_build_flags", - "build_unflags", "src_filter", "extra_scripts", "targets", - "upload_port", "upload_protocol", "upload_speed", "upload_flags", - "upload_resetmethod", "lib_deps", "lib_ignore", "lib_extra_dirs", - "lib_ldf_mode", "lib_compat_mode", "lib_archive", "piotest", - "test_transport", "test_filter", "test_ignore", "test_port", - "test_speed", "test_build_project_src", "debug_tool", "debug_port", - "debug_init_cmds", "debug_extra_cmds", "debug_server", - "debug_init_break", "debug_load_cmd", "debug_load_mode", - "debug_svd_path", "monitor_port", "monitor_speed", "monitor_rts", - "monitor_dtr" - ] - IGNORE_BUILD_OPTIONS = [ "test_transport", "test_filter", "test_ignore", "test_port", "test_speed", "debug_port", "debug_init_cmds", "debug_extra_cmds", @@ -157,17 +127,6 @@ class EnvironmentProcessor(object): REMAPED_OPTIONS = {"framework": "pioframework", "platform": "pioplatform"} - RENAMED_OPTIONS = { - "lib_use": "lib_deps", - "lib_force": "lib_deps", - "extra_script": "extra_scripts", - "monitor_baud": "monitor_speed", - "board_mcu": "board_build.mcu", - "board_f_cpu": "board_build.f_cpu", - "board_f_flash": "board_build.f_flash", - "board_flash_mode": "board_build.flash_mode" - } - def __init__( self, # pylint: disable=R0913 cmd_ctx, @@ -201,7 +160,6 @@ class EnvironmentProcessor(object): self.name, fg="cyan", bold=True), "; ".join(env_dump))) click.secho("-" * terminal_width, bold=True) - self.options = self._validate_options(self.options) result = self._run() is_error = result['returncode'] != 0 @@ -218,31 +176,6 @@ class EnvironmentProcessor(object): return not is_error - def _validate_options(self, options): - result = {} - for k, v in options.items(): - # process obsolete options - if k in self.RENAMED_OPTIONS: - click.secho( - "Warning! `%s` option is deprecated and will be " - "removed in the next release! Please use " - "`%s` instead." % (k, self.RENAMED_OPTIONS[k]), - fg="yellow") - k = self.RENAMED_OPTIONS[k] - - # warn about unknown options - unknown_conditions = [ - k not in self.KNOWN_ENV_OPTIONS, not k.startswith("custom_"), - not k.startswith("board_") - ] - if all(unknown_conditions): - click.secho( - "Detected non-PlatformIO `%s` option in `[env:%s]` section" - % (k, self.name), - fg="yellow") - result[k] = v - return result - def get_build_variables(self): variables = {"pioenv": self.name} if self.upload_port: @@ -381,21 +314,7 @@ def print_summary(results, start_time): is_error=not successed) -def check_project_defopts(config): - if not config.has_section("platformio"): - return True - unknown = set(k for k, _ in config.items("platformio")) - set( - EnvironmentProcessor.KNOWN_PLATFORMIO_OPTIONS) - if not unknown: - return True - click.secho( - "Warning! Ignore unknown `%s` option in `[platformio]` section" % - ", ".join(unknown), - fg="yellow") - return False - - -def check_project_envs(config, environments=None): +def check_project_envs(config, environments=None): # FIXME: Remove if not config.sections(): raise exception.ProjectEnvsNotAvailable() diff --git a/platformio/exception.py b/platformio/exception.py index 92ffd6c5..26131a5d 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -42,11 +42,16 @@ class UserSideException(PlatformioException): pass -class AbortedByUser(PlatformioException): +class AbortedByUser(UserSideException): MESSAGE = "Aborted by user" +# +# Development Platform +# + + class UnknownPlatform(PlatformioException): MESSAGE = "Unknown development platform '{0}'" @@ -85,54 +90,75 @@ class UnknownFramework(PlatformioException): MESSAGE = "Unknown framework '{0}'" -class UnknownPackage(PlatformioException): +# Package Manager + + +class PlatformIOPackageException(PlatformioException): + pass + + +class UnknownPackage(PlatformIOPackageException): MESSAGE = "Detected unknown package '{0}'" -class MissingPackageManifest(PlatformioException): +class MissingPackageManifest(PlatformIOPackageException): MESSAGE = "Could not find one of '{0}' manifest files in the package" -class UndefinedPackageVersion(PlatformioException): +class UndefinedPackageVersion(PlatformIOPackageException): MESSAGE = ("Could not find a version that satisfies the requirement '{0}'" " for your system '{1}'") -class PackageInstallError(PlatformioException): +class PackageInstallError(PlatformIOPackageException): MESSAGE = ("Could not install '{0}' with version requirements '{1}' " "for your system '{2}'.\n\n" "Please try this solution -> http://bit.ly/faq-package-manager") -class ExtractArchiveItemError(PlatformioException): +class ExtractArchiveItemError(PlatformIOPackageException): MESSAGE = ( "Could not extract `{0}` to `{1}`. Try to disable antivirus " "tool or check this solution -> http://bit.ly/faq-package-manager") -class FDUnrecognizedStatusCode(PlatformioException): +class UnsupportedArchiveType(PlatformIOPackageException): + + MESSAGE = "Can not unpack file '{0}'" + + +class FDUnrecognizedStatusCode(PlatformIOPackageException): MESSAGE = "Got an unrecognized status code '{0}' when downloaded {1}" -class FDSizeMismatch(PlatformioException): +class FDSizeMismatch(PlatformIOPackageException): MESSAGE = ("The size ({0:d} bytes) of downloaded file '{1}' " "is not equal to remote size ({2:d} bytes)") -class FDSHASumMismatch(PlatformioException): +class FDSHASumMismatch(PlatformIOPackageException): MESSAGE = ("The 'sha1' sum '{0}' of downloaded file '{1}' " "is not equal to remote '{2}'") -class NotPlatformIOProject(PlatformioException): +# +# Project +# + + +class PlatformIOProjectException(PlatformioException): + pass + + +class NotPlatformIOProject(PlatformIOProjectException): MESSAGE = ( "Not a PlatformIO project. `platformio.ini` file has not been " @@ -140,26 +166,82 @@ class NotPlatformIOProject(PlatformioException): "please use `platformio init` command") -class UndefinedEnvPlatform(PlatformioException): +class InvalidProjectConf(PlatformIOProjectException): + + MESSAGE = ("Invalid '{0}' (project configuration file): '{1}'") + + +class UndefinedEnvPlatform(PlatformIOProjectException): MESSAGE = "Please specify platform for '{0}' environment" -class UnsupportedArchiveType(PlatformioException): - - MESSAGE = "Can not unpack file '{0}'" - - -class ProjectEnvsNotAvailable(PlatformioException): +class ProjectEnvsNotAvailable(PlatformIOProjectException): MESSAGE = "Please setup environments in `platformio.ini` file" -class UnknownEnvNames(PlatformioException): +class UnknownEnvNames(PlatformIOProjectException): # FIXME: UnknownProjectEnvs MESSAGE = "Unknown environment names '{0}'. Valid names are '{1}'" +# +# Library +# + + +class LibNotFound(PlatformioException): + + MESSAGE = ("Library `{0}` has not been found in PlatformIO Registry.\n" + "You can ignore this message, if `{0}` is a built-in library " + "(included in framework, SDK). E.g., SPI, Wire, etc.") + + +class NotGlobalLibDir(UserSideException): + + MESSAGE = ( + "The `{0}` is not a PlatformIO project.\n\n" + "To manage libraries in global storage `{1}`,\n" + "please use `platformio lib --global {2}` or specify custom storage " + "`platformio lib --storage-dir /path/to/storage/ {2}`.\n" + "Check `platformio lib --help` for details.") + + +class InvalidLibConfURL(PlatformioException): + + MESSAGE = "Invalid library config URL '{0}'" + + +# +# UDEV Rules +# + + +class InvalidUdevRules(PlatformioException): + pass + + +class MissedUdevRules(InvalidUdevRules): + + MESSAGE = ( + "Warning! Please install `99-platformio-udev.rules`. \nMode details: " + "https://docs.platformio.org/en/latest/faq.html#platformio-udev-rules") + + +class OutdatedUdevRules(InvalidUdevRules): + + MESSAGE = ( + "Warning! Your `{0}` are outdated. Please update or reinstall them." + "\n Mode details: https://docs.platformio.org" + "/en/latest/faq.html#platformio-udev-rules") + + +# +# Misc +# + + class GetSerialPortsError(PlatformioException): MESSAGE = "No implementation for your platform ('{0}') available" @@ -175,7 +257,7 @@ class APIRequestError(PlatformioException): MESSAGE = "[API] {0}" -class InternetIsOffline(PlatformioException): +class InternetIsOffline(UserSideException): MESSAGE = ( "You are not connected to the Internet.\n" @@ -183,33 +265,6 @@ class InternetIsOffline(PlatformioException): "to install all dependencies and toolchains.") -class LibNotFound(PlatformioException): - - MESSAGE = ("Library `{0}` has not been found in PlatformIO Registry.\n" - "You can ignore this message, if `{0}` is a built-in library " - "(included in framework, SDK). E.g., SPI, Wire, etc.") - - -class NotGlobalLibDir(PlatformioException): - - MESSAGE = ( - "The `{0}` is not a PlatformIO project.\n\n" - "To manage libraries in global storage `{1}`,\n" - "please use `platformio lib --global {2}` or specify custom storage " - "`platformio lib --storage-dir /path/to/storage/ {2}`.\n" - "Check `platformio lib --help` for details.") - - -class InvalidLibConfURL(PlatformioException): - - MESSAGE = "Invalid library config URL '{0}'" - - -class InvalidProjectConf(PlatformioException): - - MESSAGE = ("Invalid '{0}' (project configuration file): '{1}'") - - class BuildScriptNotFound(PlatformioException): MESSAGE = "Invalid path '{0}' to build script" @@ -237,25 +292,6 @@ class CIBuildEnvsEmpty(PlatformioException): "predefined environments using `--project-conf` option") -class InvalidUdevRules(PlatformioException): - pass - - -class MissedUdevRules(InvalidUdevRules): - - MESSAGE = ( - "Warning! Please install `99-platformio-udev.rules`. \nMode details: " - "https://docs.platformio.org/en/latest/faq.html#platformio-udev-rules") - - -class OutdatedUdevRules(InvalidUdevRules): - - MESSAGE = ( - "Warning! Your `{0}` are outdated. Please update or reinstall them." - "\n Mode details: https://docs.platformio.org" - "/en/latest/faq.html#platformio-udev-rules") - - class UpgradeError(PlatformioException): MESSAGE = """{0} @@ -290,5 +326,4 @@ class DebugSupportError(PlatformioException): class DebugInvalidOptions(PlatformioException): - pass diff --git a/platformio/ide/projectgenerator.py b/platformio/ide/projectgenerator.py index cd48ca61..26774a70 100644 --- a/platformio/ide/projectgenerator.py +++ b/platformio/ide/projectgenerator.py @@ -23,6 +23,7 @@ from click.testing import CliRunner from platformio import exception, util from platformio.commands.run import cli as cmd_run +from platformio.project.config import ProjectConfig class ProjectGenerator(object): @@ -44,14 +45,13 @@ class ProjectGenerator(object): @util.memoized() def get_project_env(self): data = {} - config = util.load_project_config(self.project_dir) - for section in config.sections(): - if not section.startswith("env:"): + config = ProjectConfig.get_instance( + join(self.project_dir, "platformio.ini")) + for env in config.envs(): + if self.env_name != env: continue - if self.env_name != section[4:]: - continue - data = {"env_name": section[4:]} - for k, v in config.items(section): + data = {"env_name": self.env_name} + for k, v in config.items(env=env): data[k] = v return data diff --git a/platformio/project/config.py b/platformio/project/config.py index 61e22473..f827020c 100644 --- a/platformio/project/config.py +++ b/platformio/project/config.py @@ -15,6 +15,7 @@ import glob import os import re +from os.path import isfile import click @@ -25,11 +26,99 @@ try: except ImportError: import configparser as ConfigParser +KNOWN_PLATFORMIO_OPTIONS = [ + "description", + "env_default", + "extra_configs", + + # Dirs + "home_dir", + "lib_dir", + "libdeps_dir", + "include_dir", + "src_dir", + "build_dir", + "data_dir", + "test_dir", + "boards_dir", + "lib_extra_dirs" +] + +KNOWN_ENV_OPTIONS = [ + # Generic + "platform", + "framework", + "board", + "targets", + + # Build + "build_flags", + "src_build_flags", + "build_unflags", + "src_filter", + + # Upload + "upload_port", + "upload_protocol", + "upload_speed", + "upload_flags", + "upload_resetmethod", + + # Monitor + "monitor_port", + "monitor_speed", + "monitor_rts", + "monitor_dtr", + + # Library + "lib_deps", + "lib_ignore", + "lib_extra_dirs", + "lib_ldf_mode", + "lib_compat_mode", + "lib_archive", + + # Test + "piotest", + "test_filter", + "test_ignore", + "test_port", + "test_speed", + "test_transport", + "test_build_project_src", + + # Debug + "debug_tool", + "debug_init_break", + "debug_init_cmds", + "debug_extra_cmds", + "debug_load_cmd", + "debug_load_mode", + "debug_server", + "debug_port", + "debug_svd_path", + + # Other + "extra_scripts" +] + +RENAMED_OPTIONS = { + "lib_use": "lib_deps", + "lib_force": "lib_deps", + "extra_script": "extra_scripts", + "monitor_baud": "monitor_speed", + "board_mcu": "board_build.mcu", + "board_f_cpu": "board_build.f_cpu", + "board_f_flash": "board_build.f_flash", + "board_flash_mode": "board_build.flash_mode" +} + class ProjectConfig(object): VARTPL_RE = re.compile(r"\$\{([^\.\}]+)\.([^\}]+)\}") + _instances = {} _parser = None _parsed = [] @@ -49,13 +138,30 @@ class ProjectConfig(object): result.append(item) return result - def __init__(self, path): + @staticmethod + def get_instance(path): + if not isfile(path): + raise exception.NotPlatformIOProject(path) + if path not in ProjectConfig._instances: + ProjectConfig._instances[path] = ProjectConfig(path) + return ProjectConfig._instances[path] + + @staticmethod + def reset_instances(): + ProjectConfig._instances = {} + + def __init__(self, path, parse_extra=True): + if not isfile(path): + raise exception.NotPlatformIOProject(path) self.path = path self._parsed = [] self._parser = ConfigParser.ConfigParser() - self.read(path) + self.read(path, parse_extra) - def read(self, path): + def __getattr__(self, name): + return getattr(self._parser, name) + + def read(self, path, parse_extra=True): if path in self._parsed: return self._parsed.append(path) @@ -64,6 +170,9 @@ class ProjectConfig(object): except ConfigParser.Error as e: raise exception.InvalidProjectConf(path, str(e)) + if not parse_extra: + return + # load extra configs if (not self._parser.has_section("platformio") or not self._parser.has_option("platformio", "extra_configs")): @@ -74,14 +183,18 @@ class ProjectConfig(object): for item in glob.glob(pattern): self.read(item) - def __getattr__(self, name): - return getattr(self._parser, name) + def options(self, section=None, env=None): + assert section or env + if not section: + section = "env:" + env + return self._parser.options(section) - def items(self, section): - items = [] - for option in self._parser.options(section): - items.append((option, self.get(section, option))) - return items + def items(self, section=None, env=None): + assert section or env + if not section: + section = "env:" + env + return [(option, self.get(section, option)) + for option in self.options(section)] def get(self, section, option): try: @@ -95,7 +208,7 @@ class ProjectConfig(object): def _re_sub_handler(self, match): section, option = match.group(1), match.group(2) if section in ("env", - "sysenv") and not self.has_section(section): + "sysenv") and not self._parser.has_section(section): if section == "env": click.secho( "Warning! Access to system environment variable via " @@ -104,3 +217,67 @@ class ProjectConfig(object): fg="yellow") return os.getenv(option) return self.get(section, option) + + def envs(self): + return [s[4:] for s in self._parser.sections() if s.startswith("env:")] + + def default_envs(self): + if not self._parser.has_option("platformio", "env_default"): + return [] + return self.parse_multi_values(self.get("platformio", "env_default")) + + def validate(self, envs=None): + # check envs + known = set(self.envs()) + if not known: + raise exception.ProjectEnvsNotAvailable() + + unknown = set((envs or []) + self.default_envs()) - known + if unknown: + raise exception.UnknownEnvNames(", ".join(unknown), + ", ".join(known)) + return self.validate_options() + + def validate_options(self): + warnings = set() + # check [platformio] section + if self._parser.has_section("platformio"): + unknown = set(k for k, _ in self.items("platformio")) - set( + KNOWN_PLATFORMIO_OPTIONS) + if unknown: + warnings.add( + "Ignore unknown `%s` options in `[platformio]` section" % + ", ".join(unknown)) + + # check [env:*] sections + for section in self._parser.sections(): + if not section.startswith("env:"): + continue + for option in self._parser.options(section): + # obsolete + if option in RENAMED_OPTIONS: + warnings.add( + "`%s` option in `[%s]` section is deprecated and will " + "be removed in the next release! Please use `%s` " + "instead" % (option, section, RENAMED_OPTIONS[option])) + # rename on-the-fly + self._parser.set(section, RENAMED_OPTIONS[option], + self._parser.get(section, option)) + self._parser.remove_option(section, option) + continue + + # unknown + unknown_conditions = [ + option not in KNOWN_ENV_OPTIONS, + not option.startswith("custom_"), + not option.startswith("board_") + ] # yapf: disable + if all(unknown_conditions): + warnings.add( + "Detected non-PlatformIO `%s` option in `[%s]` section" + % (option, section)) + + for warning in warnings: + click.secho("Warning! %s" % warning, fg="yellow") + + return True diff --git a/platformio/telemetry.py b/platformio/telemetry.py index 3f9937cf..12e4a034 100644 --- a/platformio/telemetry.py +++ b/platformio/telemetry.py @@ -342,12 +342,9 @@ def on_exception(e): return text.strip() skip_conditions = [ - isinstance(e, cls) - for cls in (IOError, exception.ReturnErrorCode, - exception.AbortedByUser, exception.NotGlobalLibDir, - exception.InternetIsOffline, - exception.NotPlatformIOProject, - exception.UserSideException) + isinstance(e, cls) for cls in (IOError, exception.ReturnErrorCode, + exception.UserSideException, + exception.PlatformIOProjectException) ] try: skip_conditions.append("[API] Account: " in str(e)) diff --git a/platformio/util.py b/platformio/util.py index 1adcd936..85a55dc6 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -180,7 +180,8 @@ def get_project_optional_dir(name, default=None): paths = os.getenv(var_name) else: try: - config = load_project_config() + config = ProjectConfig.get_instance( + join(get_project_dir(), "platformio.ini")) if (config.has_section("platformio") and config.has_option("platformio", name)): paths = config.get("platformio", name) @@ -312,7 +313,7 @@ def get_projectdata_dir(): "data")) -def load_project_config(path=None): # FIXME: +def load_project_config(path=None): # FIXME: Remove if not path or isdir(path): path = join(path or get_project_dir(), "platformio.ini") if not isfile(path): @@ -321,7 +322,7 @@ def load_project_config(path=None): # FIXME: return ProjectConfig(path) -def parse_conf_multi_values(items): # FIXME: +def parse_conf_multi_values(items): # FIXME: Remove return ProjectConfig.parse_multi_values(items) diff --git a/tests/conftest.py b/tests/conftest.py index 02d16069..d53d92e8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -24,8 +24,10 @@ from platformio import util def validate_cliresult(): def decorator(result): - assert result.exit_code == 0, result.output - assert not result.exception, result.output + assert result.exit_code == 0, "{} => {}".format( + result.exception, result.output) + assert not result.exception, "{} => {}".format(result.exception, + result.output) return decorator diff --git a/tests/test_projectconf.py b/tests/test_projectconf.py index f47ae9af..f6228b88 100644 --- a/tests/test_projectconf.py +++ b/tests/test_projectconf.py @@ -13,10 +13,12 @@ # limitations under the License. import os + from platformio.project.config import ProjectConfig BASE_CONFIG = """ [platformio] +env_default = esp32dev, lolin32 extra_configs = extra_envs.ini extra_debug.ini @@ -86,8 +88,15 @@ def test_parser(tmpdir): "build_flags") == ("-D DEBUG=1 -L /usr/local/lib") # items - assert config.items("env:esp32dev") == [("platform", "espressif32"), + assert config.items("common") == [("debug_flags", "-D DEBUG=1"), + ("lib_flags", "-lc -lm"), + ("extra_flags", "-L /usr/local/lib")] + assert config.items(env="esp32dev") == [("platform", "espressif32"), ("framework", "espidf"), ("board", "esp32dev"), ("build_flags", "-lc -lm -D DEBUG=1")] + + # envs + assert config.envs() == ["esp-wrover-kit", "esp32dev", "lolin32"] + assert config.default_envs() == ["esp32dev", "lolin32"] From 6cd4484be919dfee2333e1c96b35dee39f60ffa3 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 7 May 2019 19:57:24 +0300 Subject: [PATCH 32/45] Init new project using new ProjectConfig API --- platformio/commands/ci.py | 3 +-- platformio/commands/init.py | 42 +++++++++++++---------------------- platformio/project/config.py | 37 +++++++++++++++++++++++------- platformio/projectconftpl.ini | 9 -------- platformio/util.py | 14 +++++------- setup.py | 1 - 6 files changed, 51 insertions(+), 55 deletions(-) delete mode 100644 platformio/projectconftpl.ini diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index 18845592..f9e93ace 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -165,5 +165,4 @@ def _copy_project_conf(build_dir, project_conf): config = ProjectConfig(project_conf, parse_extra=False) if config.has_section("platformio"): config.remove_section("platformio") - with open(join(build_dir, "platformio.ini"), "wb") as fp: - config.write(fp) + config.save(join(build_dir, "platformio.ini")) diff --git a/platformio/commands/init.py b/platformio/commands/init.py index db45ddfc..f08a52c2 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -16,7 +16,6 @@ from os import getcwd, makedirs from os.path import isdir, isfile, join -from shutil import copyfile import click @@ -89,7 +88,8 @@ def cli( "platformio.ini", fg="cyan")) is_new_project = not util.is_platformio_project(project_dir) - init_base_project(project_dir) + if is_new_project: + init_base_project(project_dir) if board: fill_project_envs(ctx, project_dir, board, project_option, env_prefix, @@ -144,13 +144,7 @@ def get_best_envname(project_dir, boards=None): def init_base_project(project_dir): - if util.is_platformio_project(project_dir): - return - - copyfile( - join(util.get_source_dir(), "projectconftpl.ini"), - join(project_dir, "platformio.ini")) - + ProjectConfig(join(project_dir, "platformio.ini")).save() with util.cd(project_dir): dir_to_readme = [ (util.get_projectsrc_dir(), None), @@ -362,12 +356,9 @@ def init_cvs_ignore(project_dir): def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix, force_download): - content = [] + config = ProjectConfig( + join(project_dir, "platformio.ini"), parse_extra=False) used_boards = [] - used_platforms = [] - - config_path = join(project_dir, "platformio.ini") - config = util.load_project_config(config_path) for section in config.sections(): cond = [ section.startswith("env:"), @@ -377,12 +368,15 @@ def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix, used_boards.append(config.get(section, "board")) pm = PlatformManager() + used_platforms = [] + modified = False for id_ in board_ids: board_config = pm.board_config(id_) used_platforms.append(board_config['platform']) if id_ in used_boards: continue used_boards.append(id_) + modified = True envopts = {"platform": board_config['platform'], "board": id_} # find default framework for board @@ -396,22 +390,18 @@ def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix, _name, _value = item.split("=", 1) envopts[_name.strip()] = _value.strip() - content.append("") - content.append("[env:%s%s]" % (env_prefix, id_)) - for name, value in envopts.items(): - content.append("%s = %s" % (name, value)) + section = "env:%s%s" % (env_prefix, id_) + config.add_section(section) + + for option, value in envopts.items(): + config.set(section, option, value) if force_download and used_platforms: _install_dependent_platforms(ctx, used_platforms) - if not content: - return - - with open(config_path, "a") as f: - content.append("") - f.write("\n".join(content)) - - ProjectConfig.reset_instances() + if modified: + config.save() + config.reset_instances() def _install_dependent_platforms(ctx, platforms): diff --git a/platformio/project/config.py b/platformio/project/config.py index f827020c..46a99425 100644 --- a/platformio/project/config.py +++ b/platformio/project/config.py @@ -26,6 +26,18 @@ try: except ImportError: import configparser as ConfigParser +CONFIG_HEADER = """ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html +""" + KNOWN_PLATFORMIO_OPTIONS = [ "description", "env_default", @@ -118,6 +130,7 @@ class ProjectConfig(object): VARTPL_RE = re.compile(r"\$\{([^\.\}]+)\.([^\}]+)\}") + expand_interpolations = True _instances = {} _parser = None _parsed = [] @@ -140,8 +153,6 @@ class ProjectConfig(object): @staticmethod def get_instance(path): - if not isfile(path): - raise exception.NotPlatformIOProject(path) if path not in ProjectConfig._instances: ProjectConfig._instances[path] = ProjectConfig(path) return ProjectConfig._instances[path] @@ -150,13 +161,13 @@ class ProjectConfig(object): def reset_instances(): ProjectConfig._instances = {} - def __init__(self, path, parse_extra=True): - if not isfile(path): - raise exception.NotPlatformIOProject(path) + def __init__(self, path, parse_extra=True, expand_interpolations=True): self.path = path + self.expand_interpolations = expand_interpolations self._parsed = [] self._parser = ConfigParser.ConfigParser() - self.read(path, parse_extra) + if isfile(path): + self.read(path, parse_extra) def __getattr__(self, name): return getattr(self._parser, name) @@ -197,6 +208,8 @@ class ProjectConfig(object): for option in self.options(section)] def get(self, section, option): + if not self.expand_interpolations: + return self._parser.get(section, option) try: value = self._parser.get(section, option) except ConfigParser.Error as e: @@ -227,6 +240,8 @@ class ProjectConfig(object): return self.parse_multi_values(self.get("platformio", "env_default")) def validate(self, envs=None): + if not isfile(self.path): + raise exception.NotPlatformIOProject(self.path) # check envs known = set(self.envs()) if not known: @@ -246,7 +261,7 @@ class ProjectConfig(object): KNOWN_PLATFORMIO_OPTIONS) if unknown: warnings.add( - "Ignore unknown `%s` options in `[platformio]` section" % + "Ignore unknown `%s` options in section `[platformio]`" % ", ".join(unknown)) # check [env:*] sections @@ -257,7 +272,7 @@ class ProjectConfig(object): # obsolete if option in RENAMED_OPTIONS: warnings.add( - "`%s` option in `[%s]` section is deprecated and will " + "`%s` option in section `[%s]` is deprecated and will " "be removed in the next release! Please use `%s` " "instead" % (option, section, RENAMED_OPTIONS[option])) # rename on-the-fly @@ -281,3 +296,9 @@ class ProjectConfig(object): click.secho("Warning! %s" % warning, fg="yellow") return True + + def save(self, path=None): + with open(path or self.path, "wb") as fp: + fp.write(CONFIG_HEADER.strip()) + fp.write("\n\n") + self._parser.write(fp) diff --git a/platformio/projectconftpl.ini b/platformio/projectconftpl.ini deleted file mode 100644 index ebc510b2..00000000 --- a/platformio/projectconftpl.ini +++ /dev/null @@ -1,9 +0,0 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; https://docs.platformio.org/page/projectconf.html diff --git a/platformio/util.py b/platformio/util.py index 85a55dc6..8df17ec9 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -179,15 +179,11 @@ def get_project_optional_dir(name, default=None): if var_name in os.environ: paths = os.getenv(var_name) else: - try: - config = ProjectConfig.get_instance( - join(get_project_dir(), "platformio.ini")) - if (config.has_section("platformio") - and config.has_option("platformio", name)): - paths = config.get("platformio", name) - except exception.NotPlatformIOProject: - pass - + config = ProjectConfig.get_instance( + join(get_project_dir(), "platformio.ini")) + if (config.has_section("platformio") + and config.has_option("platformio", name)): + paths = config.get("platformio", name) if not paths: return default diff --git a/setup.py b/setup.py index 747d6cc2..667a2842 100644 --- a/setup.py +++ b/setup.py @@ -41,7 +41,6 @@ setup( packages=find_packages() + ["scripts"], package_data={ "platformio": [ - "projectconftpl.ini", "ide/tpls/*/.*.tpl", "ide/tpls/*/*.tpl", "ide/tpls/*/*/*.tpl", From 7ddd22209f99ff2e8429c966596910d0a43ebc3a Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 7 May 2019 21:16:42 +0300 Subject: [PATCH 33/45] Enable PyLint "import-error" --- .pylintrc | 2 +- platformio/builder/main.py | 11 ++++++++--- platformio/builder/tools/pioide.py | 2 +- platformio/builder/tools/piolib.py | 6 ++++-- platformio/builder/tools/piomisc.py | 4 ++-- platformio/builder/tools/pioplatform.py | 2 +- platformio/builder/tools/pioupload.py | 2 +- platformio/builder/tools/platformio.py | 9 ++++++--- 8 files changed, 24 insertions(+), 14 deletions(-) diff --git a/.pylintrc b/.pylintrc index bbaef24a..82c3fb7a 100644 --- a/.pylintrc +++ b/.pylintrc @@ -20,4 +20,4 @@ confidence= # --disable=W" # disable=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating -disable=fixme,locally-disabled,missing-docstring,invalid-name,too-few-public-methods,redefined-variable-type,import-error,similarities,unsupported-membership-test,unsubscriptable-object,ungrouped-imports,cyclic-import,superfluous-parens,useless-object-inheritance,useless-import-alias +disable=missing-docstring,invalid-name,too-few-public-methods,redefined-variable-type,similarities,unsupported-membership-test,unsubscriptable-object,ungrouped-imports,cyclic-import,superfluous-parens,useless-object-inheritance,useless-import-alias,fixme diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 2afb2289..2d070104 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -19,9 +19,14 @@ from os import environ from os.path import expanduser, join from time import time -from SCons.Script import (ARGUMENTS, COMMAND_LINE_TARGETS, DEFAULT_TARGETS, - AllowSubstExceptions, AlwaysBuild, Default, - DefaultEnvironment, Variables) +from SCons.Script import ARGUMENTS # pylint: disable=import-error +from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error +from SCons.Script import DEFAULT_TARGETS # pylint: disable=import-error +from SCons.Script import AllowSubstExceptions # pylint: disable=import-error +from SCons.Script import AlwaysBuild # pylint: disable=import-error +from SCons.Script import Default # pylint: disable=import-error +from SCons.Script import DefaultEnvironment # pylint: disable=import-error +from SCons.Script import Variables # pylint: disable=import-error from platformio import util diff --git a/platformio/builder/tools/pioide.py b/platformio/builder/tools/pioide.py index 0e6bf31a..db496741 100644 --- a/platformio/builder/tools/pioide.py +++ b/platformio/builder/tools/pioide.py @@ -18,7 +18,7 @@ from glob import glob from os import environ from os.path import abspath, isfile, join -from SCons.Defaults import processDefines +from SCons.Defaults import processDefines # pylint: disable=import-error from platformio import util from platformio.managers.core import get_core_package_dir diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 54961eb0..0651eddd 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -26,8 +26,10 @@ from glob import glob from os.path import (basename, commonprefix, dirname, isdir, isfile, join, realpath, sep) -import SCons.Scanner -from SCons.Script import ARGUMENTS, COMMAND_LINE_TARGETS, DefaultEnvironment +import SCons.Scanner # 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 DefaultEnvironment # pylint: disable=import-error from platformio import exception, util from platformio.builder.tools import platformio as piotool diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 19a6a2ef..01a797ea 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -21,8 +21,8 @@ from os import environ, remove, walk from os.path import basename, isdir, isfile, join, realpath, relpath, sep from tempfile import mkstemp -from SCons.Action import Action -from SCons.Script import ARGUMENTS +from SCons.Action import Action # pylint: disable=import-error +from SCons.Script import ARGUMENTS # pylint: disable=import-error from platformio import util from platformio.managers.core import get_core_package_dir diff --git a/platformio/builder/tools/pioplatform.py b/platformio/builder/tools/pioplatform.py index 358aee7d..6427b33c 100644 --- a/platformio/builder/tools/pioplatform.py +++ b/platformio/builder/tools/pioplatform.py @@ -18,7 +18,7 @@ import base64 import sys from os.path import isdir, isfile, join -from SCons.Script import COMMAND_LINE_TARGETS +from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error from platformio import exception, util from platformio.managers.platform import PlatformFactory diff --git a/platformio/builder/tools/pioupload.py b/platformio/builder/tools/pioupload.py index f9628085..0d5a55ea 100644 --- a/platformio/builder/tools/pioupload.py +++ b/platformio/builder/tools/pioupload.py @@ -22,7 +22,7 @@ from os.path import isfile, join from shutil import copyfile from time import sleep -from SCons.Script import ARGUMENTS +from SCons.Script import ARGUMENTS # pylint: disable=import-error from serial import Serial, SerialException from platformio import exception, util diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 2a539e10..41f32700 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -20,9 +20,12 @@ from glob import glob from os import sep, walk from os.path import basename, dirname, isdir, join, realpath -from SCons import Builder, Util -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, - DefaultEnvironment, Export, SConscript) +from SCons import Builder, Util # 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 SCons.Script import DefaultEnvironment # pylint: disable=import-error +from SCons.Script import Export # pylint: disable=import-error +from SCons.Script import SConscript # pylint: disable=import-error from platformio.util import glob_escape, pioversion_to_intstr, string_types From 07a2a49d931105809db4297e97ad421dd586c082 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 7 May 2019 22:13:21 +0300 Subject: [PATCH 34/45] Refactor project helpers --- platformio/builder/main.py | 24 ++--- platformio/builder/tools/piolib.py | 4 +- platformio/commands/device.py | 2 +- platformio/commands/init.py | 44 +++++---- platformio/commands/lib.py | 26 +++--- platformio/commands/run.py | 45 +++------- platformio/exception.py | 7 -- platformio/ide/projectgenerator.py | 15 ++-- platformio/managers/platform.py | 3 +- platformio/project/config.py | 16 ++-- platformio/project/helpers.py | 139 +++++++++++++++++++++++++++++ platformio/util.py | 109 ++-------------------- tests/commands/test_init.py | 2 +- 13 files changed, 236 insertions(+), 200 deletions(-) create mode 100644 platformio/project/helpers.py diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 2d070104..c656da0b 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -29,6 +29,10 @@ from SCons.Script import DefaultEnvironment # pylint: disable=import-error from SCons.Script import Variables # pylint: disable=import-error from platformio import util +from platformio.project.helpers import ( + get_project_dir, get_project_optional_dir, get_projectbuild_dir, + get_projectdata_dir, get_projectinclude_dir, get_projectlib_dir, + get_projectlibdeps_dir, get_projectsrc_dir, get_projecttest_dir) AllowSubstExceptions(NameError) @@ -101,19 +105,19 @@ DEFAULT_ENV_OPTIONS = dict( ENV=environ, UNIX_TIME=int(time()), PIOHOME_DIR=util.get_home_dir(), - PROJECT_DIR=util.get_project_dir(), - PROJECTINCLUDE_DIR=util.get_projectinclude_dir(), - PROJECTSRC_DIR=util.get_projectsrc_dir(), - PROJECTTEST_DIR=util.get_projecttest_dir(), - PROJECTDATA_DIR=util.get_projectdata_dir(), - PROJECTBUILD_DIR=util.get_projectbuild_dir(), + PROJECT_DIR=get_project_dir(), + PROJECTINCLUDE_DIR=get_projectinclude_dir(), + PROJECTSRC_DIR=get_projectsrc_dir(), + PROJECTTEST_DIR=get_projecttest_dir(), + PROJECTDATA_DIR=get_projectdata_dir(), + PROJECTBUILD_DIR=get_projectbuild_dir(), BUILD_DIR=join("$PROJECTBUILD_DIR", "$PIOENV"), BUILDSRC_DIR=join("$BUILD_DIR", "src"), BUILDTEST_DIR=join("$BUILD_DIR", "test"), LIBPATH=["$BUILD_DIR"], LIBSOURCE_DIRS=[ - util.get_projectlib_dir(), - util.get_projectlibdeps_dir(), + get_projectlib_dir(), + get_projectlibdeps_dir(), join("$PIOHOME_DIR", "lib") ], PROGNAME="program", @@ -156,10 +160,10 @@ for var in ("BUILD_FLAGS", "SRC_BUILD_FLAGS", "SRC_FILTER", "EXTRA_SCRIPTS", env.Append(**{var: util.parse_conf_multi_values(environ.get(k))}) # Configure extra library source directories for LDF -if util.get_project_optional_dir("lib_extra_dirs"): +if get_project_optional_dir("lib_extra_dirs"): env.Prepend( LIBSOURCE_DIRS=util.parse_conf_multi_values( - util.get_project_optional_dir("lib_extra_dirs"))) + get_project_optional_dir("lib_extra_dirs"))) env.Prepend(LIBSOURCE_DIRS=env.get("LIB_EXTRA_DIRS", [])) env['LIBSOURCE_DIRS'] = [ expanduser(d) if d.startswith("~") else d for d in env['LIBSOURCE_DIRS'] diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 0651eddd..e1a0b50b 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -46,8 +46,8 @@ class LibBuilderFactory(object): clsname = "PlatformIOLibBuilder" else: used_frameworks = LibBuilderFactory.get_used_frameworks(env, path) - common_frameworks = ( - set(env.get("PIOFRAMEWORK", [])) & set(used_frameworks)) + common_frameworks = (set(env.get("PIOFRAMEWORK", [])) + & set(used_frameworks)) if common_frameworks: clsname = "%sLibBuilder" % list(common_frameworks)[0].title() elif used_frameworks: diff --git a/platformio/commands/device.py b/platformio/commands/device.py index 42bd4f6c..e75660ea 100644 --- a/platformio/commands/device.py +++ b/platformio/commands/device.py @@ -215,4 +215,4 @@ def get_project_options(project_dir, environment=None): environment = default_envs[0] else: environment = config.envs()[0] - return {k: v for k, v in config.items(env=environment)} + return config.items(env=environment, as_dict=True) diff --git a/platformio/commands/init.py b/platformio/commands/init.py index f08a52c2..70f8a8e4 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -25,6 +25,9 @@ from platformio.commands.platform import \ from platformio.ide.projectgenerator import ProjectGenerator from platformio.managers.platform import PlatformManager from platformio.project.config import ProjectConfig +from platformio.project.helpers import ( + get_projectinclude_dir, get_projectlib_dir, get_projectsrc_dir, + get_projecttest_dir, is_platformio_project) def validate_boards(ctx, param, value): # pylint: disable=W0613 @@ -87,7 +90,7 @@ def cli( click.echo("%s - Project Configuration File" % click.style( "platformio.ini", fg="cyan")) - is_new_project = not util.is_platformio_project(project_dir) + is_new_project = not is_platformio_project(project_dir) if is_new_project: init_base_project(project_dir) @@ -96,10 +99,8 @@ def cli( ide is not None) if ide: - env_name = get_best_envname(project_dir, board) - if not env_name: - raise exception.BoardNotDefined() - pg = ProjectGenerator(project_dir, ide, env_name) + pg = ProjectGenerator(project_dir, ide, + get_best_envname(project_dir, board)) pg.generate() if is_new_project: @@ -130,27 +131,34 @@ def cli( def get_best_envname(project_dir, boards=None): config = ProjectConfig(join(project_dir, "platformio.ini")) config.validate() + + envname = None default_envs = config.default_envs() if default_envs: - return default_envs[0] - section = None - for section in config.sections(): - if not section.startswith("env:"): - continue - elif config.has_option(section, "board") and (not boards or config.get( - section, "board") in boards): - break - return section[4:] if section else None + envname = default_envs[0] + if not boards: + return envname + + for env in config.envs(): + if not boards: + return env + if not envname: + envname = env + items = config.items(env=env, as_dict=True) + if "board" in items and items.get("board") in boards: + return env + + return envname def init_base_project(project_dir): ProjectConfig(join(project_dir, "platformio.ini")).save() with util.cd(project_dir): dir_to_readme = [ - (util.get_projectsrc_dir(), None), - (util.get_projectinclude_dir(), init_include_readme), - (util.get_projectlib_dir(), init_lib_readme), - (util.get_projecttest_dir(), init_test_readme), + (get_projectsrc_dir(), None), + (get_projectinclude_dir(), init_include_readme), + (get_projectlib_dir(), init_lib_readme), + (get_projecttest_dir(), init_test_readme), ] for (path, cb) in dir_to_readme: if isdir(path): diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index 2f09cd9c..7caf1271 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -22,7 +22,8 @@ import click from platformio import exception, util from platformio.managers.lib import LibraryManager, get_builtin_libs -from platformio.util import get_api_result +from platformio.project.helpers import ( + get_project_dir, get_projectlibdeps_dir, is_platformio_project) try: from urllib.parse import quote @@ -58,8 +59,8 @@ def cli(ctx, **options): if not storage_dir: if options['global']: storage_dir = join(util.get_home_dir(), "lib") - elif util.is_platformio_project(): - storage_dir = util.get_projectlibdeps_dir() + elif is_platformio_project(): + storage_dir = get_projectlibdeps_dir() elif util.is_ci(): storage_dir = join(util.get_home_dir(), "lib") click.secho( @@ -67,12 +68,12 @@ def cli(ctx, **options): "Please use `platformio lib --global %s` command to remove " "this warning." % ctx.invoked_subcommand, fg="yellow") - elif util.is_platformio_project(storage_dir): + elif is_platformio_project(storage_dir): with util.cd(storage_dir): - storage_dir = util.get_projectlibdeps_dir() + storage_dir = get_projectlibdeps_dir() - if not storage_dir and not util.is_platformio_project(): - raise exception.NotGlobalLibDir(util.get_project_dir(), + if not storage_dir and not is_platformio_project(): + raise exception.NotGlobalLibDir(get_project_dir(), join(util.get_home_dir(), "lib"), ctx.invoked_subcommand) @@ -211,7 +212,7 @@ def lib_search(query, json_output, page, noninteractive, **filters): for value in values: query.append('%s:"%s"' % (key, value)) - result = get_api_result( + result = util.get_api_result( "/v2/lib/search", dict(query=" ".join(query), page=page), cache_valid="1d") @@ -258,7 +259,7 @@ def lib_search(query, json_output, page, noninteractive, **filters): time.sleep(5) elif not click.confirm("Show next libraries?"): break - result = get_api_result( + result = util.get_api_result( "/v2/lib/search", { "query": " ".join(query), "page": int(result['page']) + 1 @@ -317,7 +318,7 @@ def lib_show(library, json_output): }, silent=json_output, interactive=not json_output) - lib = get_api_result("/lib/info/%d" % lib_id, cache_valid="1d") + lib = util.get_api_result("/lib/info/%d" % lib_id, cache_valid="1d") if json_output: return click.echo(json.dumps(lib)) @@ -393,7 +394,8 @@ def lib_register(config_url): and not config_url.startswith("https://")): raise exception.InvalidLibConfURL(config_url) - result = get_api_result("/lib/register", data=dict(config_url=config_url)) + result = util.get_api_result( + "/lib/register", data=dict(config_url=config_url)) if "message" in result and result['message']: click.secho( result['message'], @@ -404,7 +406,7 @@ def lib_register(config_url): @cli.command("stats", short_help="Library Registry Statistics") @click.option("--json-output", is_flag=True) def lib_stats(json_output): - result = get_api_result("/lib/stats", cache_valid="1h") + result = util.get_api_result("/lib/stats", cache_valid="1h") if json_output: return click.echo(json.dumps(result)) diff --git a/platformio/commands/run.py b/platformio/commands/run.py index baff6a54..17f088da 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -12,14 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -from hashlib import sha1 -from os import getcwd, makedirs, walk +from os import getcwd, makedirs from os.path import getmtime, isdir, isfile, join from time import time import click -from platformio import __version__, exception, telemetry, util +from platformio import exception, telemetry, util from platformio.commands.device import device_monitor as cmd_device_monitor from platformio.commands.lib import lib_install as cmd_lib_install from platformio.commands.platform import \ @@ -27,6 +26,9 @@ from platformio.commands.platform import \ from platformio.managers.lib import LibraryManager, is_builtin_lib from platformio.managers.platform import PlatformFactory from platformio.project.config import ProjectConfig +from platformio.project.helpers import ( + calculate_project_hash, find_project_dir_above, get_project_dir, + get_projectbuild_dir, get_projectlibdeps_dir) # pylint: disable=too-many-arguments,too-many-locals,too-many-branches @@ -53,18 +55,18 @@ def cli(ctx, environment, target, upload_port, project_dir, silent, verbose, disable_auto_clean): # find project directory on upper level if isfile(project_dir): - project_dir = util.find_project_dir_above(project_dir) + project_dir = find_project_dir_above(project_dir) with util.cd(project_dir): # clean obsolete build dir if not disable_auto_clean: try: - _clean_build_dir(util.get_projectbuild_dir()) + _clean_build_dir(get_projectbuild_dir()) except: # pylint: disable=bare-except click.secho( "Can not remove temporary directory `%s`. Please remove " "it manually to avoid build issues" % - util.get_projectbuild_dir(force=True), + get_projectbuild_dir(force=True), fg="yellow") config = ProjectConfig.get_instance( @@ -86,9 +88,7 @@ def cli(ctx, environment, target, upload_port, project_dir, silent, verbose, if not silent and results: click.echo() - options = {} - for k, v in config.items(env=envname): - options[k] = v + options = config.items(env=envname, as_dict=True) if "piotest" not in options and "piotest" in ctx.meta: options['piotest'] = ctx.meta['piotest'] @@ -239,7 +239,7 @@ class EnvironmentProcessor(object): def _autoinstall_libdeps(ctx, libraries, verbose=False): if not libraries: return - storage_dir = util.get_projectlibdeps_dir() + storage_dir = get_projectlibdeps_dir() ctx.obj = LibraryManager(storage_dir) if verbose: click.echo("Library Storage: " + storage_dir) @@ -258,9 +258,8 @@ def _clean_build_dir(build_dir): proj_hash = calculate_project_hash() # if project's config is modified - if (isdir(build_dir) - and getmtime(join(util.get_project_dir(), - "platformio.ini")) > getmtime(build_dir)): + if (isdir(build_dir) and getmtime( + join(get_project_dir(), "platformio.ini")) > getmtime(build_dir)): util.rmtree_(build_dir) # check project structure @@ -323,23 +322,3 @@ def check_project_envs(config, environments=None): # FIXME: Remove if unknown: raise exception.UnknownEnvNames(", ".join(unknown), ", ".join(known)) return True - - -def calculate_project_hash(): - check_suffixes = (".c", ".cc", ".cpp", ".h", ".hpp", ".s", ".S") - chunks = [__version__] - for d in (util.get_projectsrc_dir(), util.get_projectlib_dir()): - if not isdir(d): - continue - for root, _, files in walk(d): - for f in files: - path = join(root, f) - if path.endswith(check_suffixes): - chunks.append(path) - chunks_to_str = ",".join(sorted(chunks)) - if "windows" in util.get_systype(): - # Fix issue with useless project rebuilding for case insensitive FS. - # A case of disk drive can differ... - chunks_to_str = chunks_to_str.lower() - return sha1( - chunks_to_str if util.PY2 else chunks_to_str.encode()).hexdigest() diff --git a/platformio/exception.py b/platformio/exception.py index 26131a5d..4c4af06f 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -68,13 +68,6 @@ class PlatformNotInstalledYet(PlatformioException): "Use `platformio platform install {0}` command") -class BoardNotDefined(PlatformioException): - - MESSAGE = ( - "You need to specify board ID using `-b` or `--board` option. " - "Supported boards list is available via `platformio boards` command") - - class UnknownBoard(PlatformioException): MESSAGE = "Unknown board ID '{0}'" diff --git a/platformio/ide/projectgenerator.py b/platformio/ide/projectgenerator.py index 26774a70..9cbf3028 100644 --- a/platformio/ide/projectgenerator.py +++ b/platformio/ide/projectgenerator.py @@ -24,6 +24,8 @@ from click.testing import CliRunner from platformio import exception, util from platformio.commands.run import cli as cmd_run from platformio.project.config import ProjectConfig +from platformio.project.helpers import ( + get_projectlib_dir, get_projectlibdeps_dir, get_projectsrc_dir) class ProjectGenerator(object): @@ -50,9 +52,8 @@ class ProjectGenerator(object): for env in config.envs(): if self.env_name != env: continue - data = {"env_name": self.env_name} - for k, v in config.items(env=env): - data[k] = v + data = config.items(env=env, as_dict=True) + data['env_name'] = self.env_name return data def get_project_build_data(self): @@ -89,7 +90,7 @@ class ProjectGenerator(object): def get_src_files(self): result = [] with util.cd(self.project_dir): - for root, _, files in os.walk(util.get_projectsrc_dir()): + for root, _, files in os.walk(get_projectsrc_dir()): for f in files: result.append(relpath(join(root, f))) return result @@ -141,9 +142,9 @@ class ProjectGenerator(object): "src_files": self.get_src_files(), "user_home_dir": abspath(expanduser("~")), "project_dir": self.project_dir, - "project_src_dir": util.get_projectsrc_dir(), - "project_lib_dir": util.get_projectlib_dir(), - "project_libdeps_dir": util.get_projectlibdeps_dir(), + "project_src_dir": get_projectsrc_dir(), + "project_lib_dir": get_projectlib_dir(), + "project_libdeps_dir": get_projectlibdeps_dir(), "systype": util.get_systype(), "platformio_path": self._fix_os_path( sys.argv[0] if isfile(sys.argv[0]) diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 851011a9..bfcda3f2 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -25,6 +25,7 @@ import semantic_version from platformio import __version__, app, exception, util from platformio.managers.core import get_core_package_dir from platformio.managers.package import BasePkgManager, PackageManager +from platformio.project.helpers import get_projectboards_dir try: from urllib.parse import quote @@ -566,7 +567,7 @@ class PlatformBase( # pylint: disable=too-many-public-methods self._BOARDS_CACHE[board_id] = config bdirs = [ - util.get_projectboards_dir(), + get_projectboards_dir(), join(util.get_home_dir(), "boards"), join(self.get_dir(), "boards"), ] diff --git a/platformio/project/config.py b/platformio/project/config.py index 46a99425..737ea89a 100644 --- a/platformio/project/config.py +++ b/platformio/project/config.py @@ -26,8 +26,7 @@ try: except ImportError: import configparser as ConfigParser -CONFIG_HEADER = """ -; PlatformIO Project Configuration File +CONFIG_HEADER = """;PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags @@ -36,6 +35,7 @@ CONFIG_HEADER = """ ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html + """ KNOWN_PLATFORMIO_OPTIONS = [ @@ -200,10 +200,15 @@ class ProjectConfig(object): section = "env:" + env return self._parser.options(section) - def items(self, section=None, env=None): + def items(self, section=None, env=None, as_dict=False): assert section or env if not section: section = "env:" + env + if as_dict: + return { + option: self.get(section, option) + for option in self.options(section) + } return [(option, self.get(section, option)) for option in self.options(section)] @@ -298,7 +303,6 @@ class ProjectConfig(object): return True def save(self, path=None): - with open(path or self.path, "wb") as fp: - fp.write(CONFIG_HEADER.strip()) - fp.write("\n\n") + with open(path or self.path, "w") as fp: + fp.write(CONFIG_HEADER) self._parser.write(fp) diff --git a/platformio/project/helpers.py b/platformio/project/helpers.py new file mode 100644 index 00000000..d7c19595 --- /dev/null +++ b/platformio/project/helpers.py @@ -0,0 +1,139 @@ +# 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 os +import sys +from hashlib import sha1 +from os import walk +from os.path import abspath, dirname, expanduser, isdir, isfile, join + +from platformio import __version__ +from platformio.project.config import ProjectConfig + +PY2 = sys.version_info[0] == 2 + + +def get_project_dir(): + return os.getcwd() + + +def is_platformio_project(project_dir=None): + if not project_dir: + project_dir = get_project_dir() + return isfile(join(project_dir, "platformio.ini")) + + +def find_project_dir_above(path): + if isfile(path): + path = dirname(path) + if is_platformio_project(path): + return path + if isdir(dirname(path)): + return find_project_dir_above(dirname(path)) + return None + + +def get_project_optional_dir(name, default=None): + paths = None + var_name = "PLATFORMIO_%s" % name.upper() + if var_name in os.environ: + paths = os.getenv(var_name) + else: + config = ProjectConfig.get_instance( + join(get_project_dir(), "platformio.ini")) + if (config.has_section("platformio") + and config.has_option("platformio", name)): + paths = config.get("platformio", name) + if not paths: + return default + + items = [] + for item in paths.split(", "): + if item.startswith("~"): + item = expanduser(item) + items.append(abspath(item)) + paths = ", ".join(items) + + while "$PROJECT_HASH" in paths: + project_dir = get_project_dir() + paths = paths.replace( + "$PROJECT_HASH", + sha1(project_dir if PY2 else project_dir.encode()).hexdigest() + [:10]) + + return paths + + +def get_projectlib_dir(): + return get_project_optional_dir("lib_dir", join(get_project_dir(), "lib")) + + +def get_projectlibdeps_dir(): + return get_project_optional_dir("libdeps_dir", + join(get_project_dir(), ".piolibdeps")) + + +def get_projectsrc_dir(): + return get_project_optional_dir("src_dir", join(get_project_dir(), "src")) + + +def get_projectinclude_dir(): + return get_project_optional_dir("include_dir", + join(get_project_dir(), "include")) + + +def get_projecttest_dir(): + return get_project_optional_dir("test_dir", join(get_project_dir(), + "test")) + + +def get_projectboards_dir(): + return get_project_optional_dir("boards_dir", + join(get_project_dir(), "boards")) + + +def get_projectbuild_dir(force=False): + path = get_project_optional_dir("build_dir", + join(get_project_dir(), ".pioenvs")) + try: + if not isdir(path): + os.makedirs(path) + except Exception as e: # pylint: disable=broad-except + if not force: + raise Exception(e) + return path + + +def get_projectdata_dir(): + return get_project_optional_dir("data_dir", join(get_project_dir(), + "data")) + + +def calculate_project_hash(): + check_suffixes = (".c", ".cc", ".cpp", ".h", ".hpp", ".s", ".S") + chunks = [__version__] + for d in (get_projectsrc_dir(), get_projectlib_dir()): + if not isdir(d): + continue + for root, _, files in walk(d): + for f in files: + path = join(root, f) + if path.endswith(check_suffixes): + chunks.append(path) + chunks_to_str = ",".join(sorted(chunks)) + if sys.platform == "win32": + # Fix issue with useless project rebuilding for case insensitive FS. + # A case of disk drive can differ... + chunks_to_str = chunks_to_str.lower() + return sha1(chunks_to_str if PY2 else chunks_to_str.encode()).hexdigest() diff --git a/platformio/util.py b/platformio/util.py index 8df17ec9..a68d7607 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +# pylint: disable=too-many-ancestors + import json import os import platform @@ -23,7 +25,6 @@ import sys import time from functools import wraps from glob import glob -from hashlib import sha1 from os.path import (abspath, basename, dirname, expanduser, isdir, isfile, join, normpath, splitdrive) from shutil import rmtree @@ -34,8 +35,12 @@ import requests from platformio import __apiurl__, __version__, exception from platformio.project.config import ProjectConfig +from platformio.project.helpers import ( # pylint: disable=unused-import + get_project_dir, get_project_optional_dir, get_projectboards_dir, + get_projectbuild_dir, get_projectlib_dir, get_projectsrc_dir, + get_projecttest_dir, is_platformio_project) -# pylint: disable=too-many-ancestors +# FIXME: check platformio.project.helpers imports PY2 = sys.version_info[0] == 2 if PY2: @@ -173,37 +178,6 @@ def pioversion_to_intstr(): return [int(i) for i in vermatch.group(1).split(".")[:3]] -def get_project_optional_dir(name, default=None): - paths = None - var_name = "PLATFORMIO_%s" % name.upper() - if var_name in os.environ: - paths = os.getenv(var_name) - else: - config = ProjectConfig.get_instance( - join(get_project_dir(), "platformio.ini")) - if (config.has_section("platformio") - and config.has_option("platformio", name)): - paths = config.get("platformio", name) - if not paths: - return default - - items = [] - for item in paths.split(", "): - if item.startswith("~"): - item = expanduser(item) - items.append(abspath(item)) - paths = ", ".join(items) - - while "$PROJECT_HASH" in paths: - project_dir = get_project_dir() - paths = paths.replace( - "$PROJECT_HASH", - sha1(project_dir if PY2 else project_dir.encode()).hexdigest() - [:10]) - - return paths - - def get_home_dir(): home_dir = get_project_optional_dir("home_dir", join(expanduser("~"), ".platformio")) @@ -240,75 +214,6 @@ def get_source_dir(): return dirname(curpath) -def get_project_dir(): - return os.getcwd() - - -def find_project_dir_above(path): - if isfile(path): - path = dirname(path) - if is_platformio_project(path): - return path - if isdir(dirname(path)): - return find_project_dir_above(dirname(path)) - return None - - -def is_platformio_project(project_dir=None): - if not project_dir: - project_dir = get_project_dir() - return isfile(join(project_dir, "platformio.ini")) - - -def get_projectlib_dir(): - return get_project_optional_dir("lib_dir", join(get_project_dir(), "lib")) - - -def get_projectlibdeps_dir(): - return get_project_optional_dir("libdeps_dir", - join(get_project_dir(), ".piolibdeps")) - - -def get_projectsrc_dir(): - return get_project_optional_dir("src_dir", join(get_project_dir(), "src")) - - -def get_projectinclude_dir(): - return get_project_optional_dir("include_dir", - join(get_project_dir(), "include")) - - -def get_projecttest_dir(): - return get_project_optional_dir("test_dir", join(get_project_dir(), - "test")) - - -def get_projectboards_dir(): - return get_project_optional_dir("boards_dir", - join(get_project_dir(), "boards")) - - -def get_projectbuild_dir(force=False): - path = get_project_optional_dir("build_dir", - join(get_project_dir(), ".pioenvs")) - try: - if not isdir(path): - os.makedirs(path) - except Exception as e: # pylint: disable=broad-except - if not force: - raise Exception(e) - return path - - -# compatibility with PIO Core+ -get_projectpioenvs_dir = get_projectbuild_dir - - -def get_projectdata_dir(): - return get_project_optional_dir("data_dir", join(get_project_dir(), - "data")) - - def load_project_config(path=None): # FIXME: Remove if not path or isdir(path): path = join(path or get_project_dir(), "platformio.ini") diff --git a/tests/commands/test_init.py b/tests/commands/test_init.py index eecb25f3..1d7d699e 100644 --- a/tests/commands/test_init.py +++ b/tests/commands/test_init.py @@ -58,7 +58,7 @@ def test_init_ide_without_board(clirunner, tmpdir): with tmpdir.as_cwd(): result = clirunner.invoke(cmd_init, ["--ide", "atom"]) assert result.exit_code == -1 - assert isinstance(result.exception, exception.BoardNotDefined) + assert isinstance(result.exception, exception.ProjectEnvsNotAvailable) def test_init_ide_atom(clirunner, validate_cliresult, tmpdir): From 45d4b926787be6c894d7666df8533ff1cec2f535 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 7 May 2019 23:00:01 +0300 Subject: [PATCH 35/45] Export get_projectdata_dir for util, fix riscv_gap dev/platform --- platformio/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio/util.py b/platformio/util.py index a68d7607..49739c14 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -37,8 +37,8 @@ from platformio import __apiurl__, __version__, exception from platformio.project.config import ProjectConfig from platformio.project.helpers import ( # pylint: disable=unused-import get_project_dir, get_project_optional_dir, get_projectboards_dir, - get_projectbuild_dir, get_projectlib_dir, get_projectsrc_dir, - get_projecttest_dir, is_platformio_project) + get_projectbuild_dir, get_projectdata_dir, get_projectlib_dir, + get_projectsrc_dir, get_projecttest_dir, is_platformio_project) # FIXME: check platformio.project.helpers imports From 947e31ca8d41bcbe7b8b0fd112b2fedc127d3b33 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 7 May 2019 23:51:46 +0300 Subject: [PATCH 36/45] Fix some PyLint errors --- .pylintrc | 33 +++++++++++---------------------- platformio/commands/upgrade.py | 3 +-- platformio/exception.py | 2 -- platformio/managers/lib.py | 2 +- platformio/util.py | 4 +--- 5 files changed, 14 insertions(+), 30 deletions(-) diff --git a/.pylintrc b/.pylintrc index 82c3fb7a..180a05b8 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,23 +1,12 @@ [MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time. See also the "--disable" option for examples. -#enable= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -# disable=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating - -disable=missing-docstring,invalid-name,too-few-public-methods,redefined-variable-type,similarities,unsupported-membership-test,unsubscriptable-object,ungrouped-imports,cyclic-import,superfluous-parens,useless-object-inheritance,useless-import-alias,fixme +disable= + missing-docstring, + ungrouped-imports, + invalid-name, + cyclic-import, + duplicate-code, + superfluous-parens, + too-few-public-methods, + useless-object-inheritance, + useless-import-alias, + fixme diff --git a/platformio/commands/upgrade.py b/platformio/commands/upgrade.py index ec4fe864..c47ff8dc 100644 --- a/platformio/commands/upgrade.py +++ b/platformio/commands/upgrade.py @@ -43,11 +43,10 @@ def cli(dev): get_pip_package(to_develop)], ["platformio", "--version"]) cmd = None - r = None + r = {} try: for cmd in cmds: cmd = [util.get_pythonexe_path(), "-m"] + cmd - r = None r = util.exec_command(cmd) # try pip with disabled cache diff --git a/platformio/exception.py b/platformio/exception.py index 4c4af06f..bba8955a 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=not-an-iterable - class PlatformioException(Exception): diff --git a/platformio/managers/lib.py b/platformio/managers/lib.py index 3ca89d49..4cbb34a7 100644 --- a/platformio/managers/lib.py +++ b/platformio/managers/lib.py @@ -164,7 +164,7 @@ class LibraryManager(BasePkgManager): semver_spec = self.parse_semver_spec( requirements) if requirements else None - item = None + item = {} for v in versions: semver_new = self.parse_semver_version(v['name']) diff --git a/platformio/util.py b/platformio/util.py index 49739c14..8055cc4d 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=too-many-ancestors - import json import os import platform @@ -464,7 +462,7 @@ def _get_api_result( auth=None): from platformio.app import get_setting - result = None + result = {} r = None verify_ssl = sys.version_info >= (2, 7, 9) From 693304590c918a66e2c3facf49b3e02eb61e5b3d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 8 May 2019 12:41:11 +0300 Subject: [PATCH 37/45] Fix PyLint "not-an-iterable" error --- platformio/exception.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platformio/exception.py b/platformio/exception.py index bba8955a..6f1dd4cf 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -19,7 +19,9 @@ class PlatformioException(Exception): def __str__(self): # pragma: no cover if self.MESSAGE: - return self.MESSAGE.format(*self.args) + return self.MESSAGE.format( + *self.args # pylint: disable=not-an-iterable + ) return super(PlatformioException, self).__str__() From 4f98a3fd42e4f0e5ec9dcc9c9ce3f6ae1c2b247f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 8 May 2019 20:19:39 +0300 Subject: [PATCH 38/45] Share common (global) options between declared build environments using "[env]" section // Resolve #1643 Resolve #790 --- HISTORY.rst | 2 + docs | 2 +- platformio/exception.py | 5 +- platformio/project/config.py | 39 +++++++++++---- tests/test_projectconf.py | 92 +++++++++++++++++++++--------------- 5 files changed, 87 insertions(+), 53 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 0ce2bb74..6991bb7d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -9,6 +9,8 @@ PlatformIO 4.0 * Python 3 support (`issue #895 `_) +* Share common (global) options between declared build environments using ``[env]`` section in `"platformio.ini" (Project Configuration File) `__ + (`issue #1643 `_) * Include external configuration files with `extra_configs `__ option (`issue #1590 `_) * Override default source and include directories for a library via `library.json `__ manifest using ``includeDir`` and ``srcDir`` fields diff --git a/docs b/docs index 5df8f4b0..45a3b5a3 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 5df8f4b066cebfa41e46db058936b2aa8298a70b +Subproject commit 45a3b5a365b9ee651087192f0a42dc876b3afeb8 diff --git a/platformio/exception.py b/platformio/exception.py index 6f1dd4cf..a7713b99 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -19,9 +19,8 @@ class PlatformioException(Exception): def __str__(self): # pragma: no cover if self.MESSAGE: - return self.MESSAGE.format( - *self.args # pylint: disable=not-an-iterable - ) + return self.MESSAGE.format(*self.args # pylint: disable=not-an-iterable + ) return super(PlatformioException, self).__str__() diff --git a/platformio/project/config.py b/platformio/project/config.py index 737ea89a..757ecd0a 100644 --- a/platformio/project/config.py +++ b/platformio/project/config.py @@ -13,6 +13,7 @@ # limitations under the License. import glob +import json import os import re from os.path import isfile @@ -198,7 +199,22 @@ class ProjectConfig(object): assert section or env if not section: section = "env:" + env - return self._parser.options(section) + options = self._parser.options(section) + + # handle global options from [env] + if ((env or section.startswith("env:")) + and self._parser.has_section("env")): + for option in self._parser.options("env"): + if option not in options: + options.append(option) + + return options + + def has_option(self, section, option): + if self._parser.has_option(section, option): + return True + return (section.startswith("env:") and self._parser.has_section("env") + and self._parser.has_option("env", option)) def items(self, section=None, env=None, as_dict=False): assert section or env @@ -215,24 +231,21 @@ class ProjectConfig(object): def get(self, section, option): if not self.expand_interpolations: return self._parser.get(section, option) + try: value = self._parser.get(section, option) + except ConfigParser.NoOptionError: + value = self._parser.get("env", option) except ConfigParser.Error as e: raise exception.InvalidProjectConf(self.path, str(e)) + if "${" not in value or "}" not in value: return value return self.VARTPL_RE.sub(self._re_sub_handler, value) def _re_sub_handler(self, match): section, option = match.group(1), match.group(2) - if section in ("env", - "sysenv") and not self._parser.has_section(section): - if section == "env": - click.secho( - "Warning! Access to system environment variable via " - "`${{env.{0}}}` is deprecated. Please use " - "`${{sysenv.{0}}}` instead".format(option), - fg="yellow") + if section == "sysenv": return os.getenv(option) return self.get(section, option) @@ -271,7 +284,7 @@ class ProjectConfig(object): # check [env:*] sections for section in self._parser.sections(): - if not section.startswith("env:"): + if section != "env" and not section.startswith("env:"): continue for option in self._parser.options(section): # obsolete @@ -302,6 +315,12 @@ class ProjectConfig(object): return True + def to_json(self): + result = {} + for section in self.sections(): + result[section] = self.items(section, as_dict=True) + return json.dumps(result) + def save(self, path=None): with open(path or self.path, "w") as fp: fp.write(CONFIG_HEADER) diff --git a/tests/test_projectconf.py b/tests/test_projectconf.py index f6228b88..d58ee0ce 100644 --- a/tests/test_projectconf.py +++ b/tests/test_projectconf.py @@ -18,43 +18,42 @@ from platformio.project.config import ProjectConfig BASE_CONFIG = """ [platformio] -env_default = esp32dev, lolin32 +env_default = base, extra_2 extra_configs = extra_envs.ini extra_debug.ini -[common] +# global options per [env:*] +[env] +monitor_speed = 115200 +lib_deps = Lib1, Lib2 +lib_ignore = ${custom.lib_ignore} + +[custom] debug_flags = -D RELEASE lib_flags = -lc -lm extra_flags = ${sysenv.__PIO_TEST_CNF_EXTRA_FLAGS} +lib_ignore = LibIgnoreCustom -[env:esp-wrover-kit] -platform = espressif32 -framework = espidf -board = esp-wrover-kit -build_flags = ${common.debug_flags} ${common.extra_flags} +[env:base] +build_flags = ${custom.debug_flags} ${custom.extra_flags} """ EXTRA_ENVS_CONFIG = """ -[env:esp32dev] -platform = espressif32 -framework = espidf -board = esp32dev -build_flags = ${common.lib_flags} ${common.debug_flags} +[env:extra_1] +build_flags = ${custom.lib_flags} ${custom.debug_flags} -[env:lolin32] -platform = espressif32 -framework = espidf -board = lolin32 -build_flags = ${common.debug_flags} ${common.extra_flags} +[env:extra_2] +build_flags = ${custom.debug_flags} ${custom.extra_flags} +lib_ignore = ${env.lib_ignore}, Lib3 """ EXTRA_DEBUG_CONFIG = """ -# Override base "common.debug_flags" -[common] +# Override original "custom.debug_flags" +[custom] debug_flags = -D DEBUG=1 -[env:lolin32] +[env:extra_2] build_flags = -Og """ @@ -71,32 +70,47 @@ def test_parser(tmpdir): # sections assert config.sections() == [ - "platformio", "common", "env:esp-wrover-kit", "env:esp32dev", - "env:lolin32" + "platformio", "env", "custom", "env:base", "env:extra_1", "env:extra_2" ] + # envs + assert config.envs() == ["base", "extra_1", "extra_2"] + assert config.default_envs() == ["base", "extra_2"] + + # options + assert config.options(env="base") == [ + "build_flags", "monitor_speed", "lib_deps", "lib_ignore" + ] + + # has_option + assert config.has_option("env:base", "monitor_speed") + assert not config.has_option("custom", "monitor_speed") + # sysenv - assert config.get("common", "extra_flags") == "" + assert config.get("custom", "extra_flags") == "" os.environ["__PIO_TEST_CNF_EXTRA_FLAGS"] = "-L /usr/local/lib" - assert config.get("common", "extra_flags") == "-L /usr/local/lib" + assert config.get("custom", "extra_flags") == "-L /usr/local/lib" # get - assert config.get("common", "debug_flags") == "-D DEBUG=1" - assert config.get("env:esp32dev", "build_flags") == "-lc -lm -D DEBUG=1" - assert config.get("env:lolin32", "build_flags") == "-Og" - assert config.get("env:esp-wrover-kit", + assert config.get("custom", "debug_flags") == "-D DEBUG=1" + assert config.get("env:extra_1", "build_flags") == "-lc -lm -D DEBUG=1" + assert config.get("env:extra_2", "build_flags") == "-Og" + assert config.get("env:extra_2", "monitor_speed") == "115200" + assert config.get("env:base", "build_flags") == ("-D DEBUG=1 -L /usr/local/lib") # items - assert config.items("common") == [("debug_flags", "-D DEBUG=1"), + assert config.items("custom") == [("debug_flags", "-D DEBUG=1"), ("lib_flags", "-lc -lm"), - ("extra_flags", "-L /usr/local/lib")] - assert config.items(env="esp32dev") == [("platform", "espressif32"), - ("framework", "espidf"), - ("board", "esp32dev"), - ("build_flags", - "-lc -lm -D DEBUG=1")] - - # envs - assert config.envs() == ["esp-wrover-kit", "esp32dev", "lolin32"] - assert config.default_envs() == ["esp32dev", "lolin32"] + ("extra_flags", "-L /usr/local/lib"), + ("lib_ignore", "LibIgnoreCustom")] + assert config.items(env="extra_1") == [("build_flags", + "-lc -lm -D DEBUG=1"), + ("monitor_speed", "115200"), + ("lib_deps", "Lib1, Lib2"), + ("lib_ignore", "LibIgnoreCustom")] + assert config.items(env="extra_2") == [("build_flags", "-Og"), + ("lib_ignore", + "LibIgnoreCustom, Lib3"), + ("monitor_speed", "115200"), + ("lib_deps", "Lib1, Lib2")] From f63fe1699b9dae403242bf6799fa1324fffcc202 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 8 May 2019 20:20:56 +0300 Subject: [PATCH 39/45] Bump version to 4.0.0a11 --- platformio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 6d00c736..2ce1d9e4 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -VERSION = (4, 0, "0a10") +VERSION = (4, 0, "0a11") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" From 7687a0a929d8a60fa30f43d9e7bf0d53b4ff4aa6 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 8 May 2019 21:02:23 +0300 Subject: [PATCH 40/45] Fix PyLint "not-an-iterable" error --- platformio/exception.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platformio/exception.py b/platformio/exception.py index a7713b99..ac7288cf 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -19,8 +19,9 @@ class PlatformioException(Exception): def __str__(self): # pragma: no cover if self.MESSAGE: - return self.MESSAGE.format(*self.args # pylint: disable=not-an-iterable - ) + # pylint: disable=not-an-iterable + return self.MESSAGE.format(*self.args) + return super(PlatformioException, self).__str__() From 62b80c396bc2eb669430acb41b55f9fecb8a4283 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 9 May 2019 00:51:28 +0300 Subject: [PATCH 41/45] Added support for the latest Python "Click" package (CLI Builder) // Resolve #349 --- HISTORY.rst | 2 ++ platformio/__main__.py | 38 +------------------------- platformio/commands/__init__.py | 48 +++++++++++++++++++++++++++++++++ platformio/commands/lib.py | 3 ++- platformio/maintenance.py | 20 +++++++------- platformio/managers/core.py | 2 +- platformio/telemetry.py | 9 ++++--- setup.py | 2 +- tests/commands/test_init.py | 2 +- tests/commands/test_lib.py | 3 +++ tests/commands/test_platform.py | 4 +-- 11 files changed, 75 insertions(+), 58 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 6991bb7d..77c93c52 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -14,6 +14,8 @@ PlatformIO 4.0 * Include external configuration files with `extra_configs `__ option (`issue #1590 `_) * Override default source and include directories for a library via `library.json `__ manifest using ``includeDir`` and ``srcDir`` fields +* Added support for the latest Python "Click" package (CLI Builder) + (`issue #349 `_) PlatformIO 3.0 -------------- diff --git a/platformio/__main__.py b/platformio/__main__.py index 61db78de..9138fe3c 100644 --- a/platformio/__main__.py +++ b/platformio/__main__.py @@ -14,49 +14,13 @@ import os import sys -from os.path import join from platform import system from traceback import format_exc import click from platformio import __version__, exception, maintenance -from platformio.util import get_source_dir - - -class PlatformioCLI(click.MultiCommand): # pylint: disable=R0904 - - def list_commands(self, ctx): - cmds = [] - for filename in os.listdir(join(get_source_dir(), "commands")): - if filename.startswith("__init__"): - continue - if filename.endswith(".py"): - cmds.append(filename[:-3]) - cmds.sort() - return cmds - - def get_command(self, ctx, cmd_name): - mod = None - try: - mod = __import__("platformio.commands." + cmd_name, None, None, - ["cli"]) - except ImportError: - try: - return self._handle_obsolate_command(cmd_name) - except AttributeError: - raise click.UsageError('No such command "%s"' % cmd_name, ctx) - return mod.cli - - @staticmethod - def _handle_obsolate_command(name): - if name == "platforms": - from platformio.commands import platform - return platform.cli - if name == "serialports": - from platformio.commands import device - return device.cli - raise AttributeError() +from platformio.commands import PlatformioCLI @click.command( diff --git a/platformio/commands/__init__.py b/platformio/commands/__init__.py index b0514903..48dd394e 100644 --- a/platformio/commands/__init__.py +++ b/platformio/commands/__init__.py @@ -11,3 +11,51 @@ # 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 os +from os.path import dirname, join + +import click + + +class PlatformioCLI(click.MultiCommand): + + leftover_args = [] + + def invoke(self, ctx): + PlatformioCLI.leftover_args = ctx.args + if hasattr(ctx, "protected_args"): + PlatformioCLI.leftover_args = ctx.protected_args + ctx.args + return super(PlatformioCLI, self).invoke(ctx) + + def list_commands(self, ctx): + cmds = [] + for filename in os.listdir(join(dirname(__file__), "commands")): + if filename.startswith("__init__"): + continue + if filename.endswith(".py"): + cmds.append(filename[:-3]) + cmds.sort() + return cmds + + def get_command(self, ctx, cmd_name): + mod = None + try: + mod = __import__("platformio.commands." + cmd_name, None, None, + ["cli"]) + except ImportError: + try: + return self._handle_obsolate_command(cmd_name) + except AttributeError: + raise click.UsageError('No such command "%s"' % cmd_name, ctx) + return mod.cli + + @staticmethod + def _handle_obsolate_command(name): + if name == "platforms": + from platformio.commands import platform + return platform.cli + if name == "serialports": + from platformio.commands import device + return device.cli + raise AttributeError() diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index 7caf1271..c52350b1 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -21,6 +21,7 @@ from os.path import isdir, join import click from platformio import exception, util +from platformio.commands import PlatformioCLI from platformio.managers.lib import LibraryManager, get_builtin_libs from platformio.project.helpers import ( get_project_dir, get_projectlibdeps_dir, is_platformio_project) @@ -78,7 +79,7 @@ def cli(ctx, **options): ctx.invoked_subcommand) ctx.obj = LibraryManager(storage_dir) - if "--json-output" not in ctx.args: + if "--json-output" not in PlatformioCLI.leftover_args: click.echo("Library Storage: " + storage_dir) diff --git a/platformio/maintenance.py b/platformio/maintenance.py index 47105a5b..8841b7f5 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -22,6 +22,7 @@ import click import semantic_version from platformio import __version__, app, exception, telemetry, util +from platformio.commands import PlatformioCLI from platformio.commands.lib import lib_update as cmd_lib_update from platformio.commands.platform import \ platform_install as cmd_platform_install @@ -40,12 +41,12 @@ def on_platformio_start(ctx, force, caller): set_caller(caller) telemetry.on_command() - if not in_silence(ctx): + if not in_silence(): after_upgrade(ctx) -def on_platformio_end(ctx, result): # pylint: disable=W0613 - if in_silence(ctx): +def on_platformio_end(ctx, result): # pylint: disable=unused-argument + if in_silence(): return try: @@ -64,14 +65,11 @@ def on_platformio_exception(e): telemetry.on_exception(e) -def in_silence(ctx=None): - ctx = ctx or app.get_session_var("command_ctx") - if not ctx: - return True - return ctx.args and any([ - ctx.args[0] == "debug" and "--interpreter" in " ".join(ctx.args), - ctx.args[0] == "upgrade", "--json-output" in ctx.args, - "--version" in ctx.args +def in_silence(): + args = PlatformioCLI.leftover_args + return args and any([ + args[0] == "debug" and "--interpreter" in " ".join(args), + args[0] == "upgrade", "--json-output" in args, "--version" in args ]) diff --git a/platformio/managers/core.py b/platformio/managers/core.py index 05822f7a..be9e3a1d 100644 --- a/platformio/managers/core.py +++ b/platformio/managers/core.py @@ -27,7 +27,7 @@ CORE_PACKAGES = { "contrib-piohome": "^2.0.1", "contrib-pysite": "~2.%d%d.190418" % (sys.version_info[0], sys.version_info[1]), - "tool-pioplus": "^2.1.4", + "tool-pioplus": "^2.1.5", "tool-unity": "~1.20403.0", "tool-scons": "~2.20501.7" if util.PY2 else "~3.30005.0" } diff --git a/platformio/telemetry.py b/platformio/telemetry.py index 12e4a034..987d5899 100644 --- a/platformio/telemetry.py +++ b/platformio/telemetry.py @@ -27,6 +27,7 @@ import click import requests from platformio import __version__, app, exception, util +from platformio.commands import PlatformioCLI try: import queue @@ -133,10 +134,10 @@ class MeasurementProtocol(TelemetryBase): return _arg return None - if not app.get_session_var("command_ctx"): - return - ctx_args = app.get_session_var("command_ctx").args - args = [str(s).lower() for s in ctx_args if not str(s).startswith("-")] + args = [ + str(arg).lower() for arg in PlatformioCLI.leftover_args + if not str(arg).startswith("-") + ] if not args: return cmd_path = args[:1] diff --git a/setup.py b/setup.py index 667a2842..eb667d72 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ from platformio import (__author__, __description__, __email__, __license__, install_requires = [ "bottle<0.13", - "click>=5,<6", + "click>=5,<8", "colorama", "pyserial>=3,<4,!=3.3", "requests>=2.4.0,<3", diff --git a/tests/commands/test_init.py b/tests/commands/test_init.py index 1d7d699e..4e8eac09 100644 --- a/tests/commands/test_init.py +++ b/tests/commands/test_init.py @@ -57,7 +57,7 @@ def test_init_duplicated_boards(clirunner, validate_cliresult, tmpdir): def test_init_ide_without_board(clirunner, tmpdir): with tmpdir.as_cwd(): result = clirunner.invoke(cmd_init, ["--ide", "atom"]) - assert result.exit_code == -1 + assert result.exit_code != 0 assert isinstance(result.exception, exception.ProjectEnvsNotAvailable) diff --git a/tests/commands/test_lib.py b/tests/commands/test_lib.py index b67cec39..47e5a709 100644 --- a/tests/commands/test_lib.py +++ b/tests/commands/test_lib.py @@ -16,8 +16,11 @@ import json import re from platformio import exception +from platformio.commands import PlatformioCLI from platformio.commands.lib import cli as cmd_lib +PlatformioCLI.leftover_args = ["--json-output"] # hook for click + def test_search(clirunner, validate_cliresult): result = clirunner.invoke(cmd_lib, ["search", "DHT22"]) diff --git a/tests/commands/test_platform.py b/tests/commands/test_platform.py index d327ef37..72941574 100644 --- a/tests/commands/test_platform.py +++ b/tests/commands/test_platform.py @@ -38,14 +38,14 @@ def test_search_raw_output(clirunner, validate_cliresult): def test_install_unknown_version(clirunner): result = clirunner.invoke(cli_platform.platform_install, ["atmelavr@99.99.99"]) - assert result.exit_code == -1 + assert result.exit_code != 0 assert isinstance(result.exception, exception.UndefinedPackageVersion) def test_install_unknown_from_registry(clirunner): result = clirunner.invoke(cli_platform.platform_install, ["unknown-platform"]) - assert result.exit_code == -1 + assert result.exit_code != 0 assert isinstance(result.exception, exception.UnknownPackage) From 71f606912a8dc28196f567c524c09783a7fcb6c3 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 9 May 2019 14:14:19 +0300 Subject: [PATCH 42/45] Implement ProjectConfig.getlist() --- platformio/project/config.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/platformio/project/config.py b/platformio/project/config.py index 757ecd0a..d2e77bb7 100644 --- a/platformio/project/config.py +++ b/platformio/project/config.py @@ -189,8 +189,7 @@ class ProjectConfig(object): if (not self._parser.has_section("platformio") or not self._parser.has_option("platformio", "extra_configs")): return - extra_configs = self.parse_multi_values( - self.get("platformio", "extra_configs")) + extra_configs = self.getlist("platformio", "extra_configs") for pattern in extra_configs: for item in glob.glob(pattern): self.read(item) @@ -249,13 +248,16 @@ class ProjectConfig(object): return os.getenv(option) return self.get(section, option) + def getlist(self, section, option): + return self.parse_multi_values(self.get(section, option)) + def envs(self): return [s[4:] for s in self._parser.sections() if s.startswith("env:")] def default_envs(self): if not self._parser.has_option("platformio", "env_default"): return [] - return self.parse_multi_values(self.get("platformio", "env_default")) + return self.getlist("platformio", "env_default") def validate(self, envs=None): if not isfile(self.path): From 32d317d3cb9d6ab3a07f65ed4e0e6bd75f2a14f9 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 9 May 2019 18:39:27 +0300 Subject: [PATCH 43/45] Fix PlatformIO CLI --- platformio/commands/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio/commands/__init__.py b/platformio/commands/__init__.py index 48dd394e..83c88e11 100644 --- a/platformio/commands/__init__.py +++ b/platformio/commands/__init__.py @@ -13,7 +13,7 @@ # limitations under the License. import os -from os.path import dirname, join +from os.path import dirname import click @@ -30,7 +30,7 @@ class PlatformioCLI(click.MultiCommand): def list_commands(self, ctx): cmds = [] - for filename in os.listdir(join(dirname(__file__), "commands")): + for filename in os.listdir(dirname(__file__)): if filename.startswith("__init__"): continue if filename.endswith(".py"): From 2b5ac57fd02e5e20f738f9060456542f69eeff95 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 9 May 2019 18:40:19 +0300 Subject: [PATCH 44/45] Bump version to 4.0.0a12 --- platformio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 2ce1d9e4..232433f9 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -VERSION = (4, 0, "0a11") +VERSION = (4, 0, "0a12") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" From c79b3ff7f19284be29977e07c1c6aade8a2ccf66 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 10 May 2019 00:01:10 +0300 Subject: [PATCH 45/45] =?UTF-8?q?Override=20default=20=E2=80=9Cplatformio.?= =?UTF-8?q?ini=E2=80=9D=20with=20a=20custom=20using=20"-c,=20--project-con?= =?UTF-8?q?f"=20option=20//=20Resolve=20#1913?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HISTORY.rst | 4 +++- docs | 2 +- platformio/commands/ci.py | 2 +- platformio/commands/run.py | 15 ++++++++++++--- platformio/managers/core.py | 2 +- tests/commands/test_lib.py | 31 +++++++++++++------------------ tests/test_misc.py | 6 ++++++ 7 files changed, 37 insertions(+), 25 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 77c93c52..f5a953f6 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -11,8 +11,10 @@ PlatformIO 4.0 (`issue #895 `_) * Share common (global) options between declared build environments using ``[env]`` section in `"platformio.ini" (Project Configuration File) `__ (`issue #1643 `_) -* Include external configuration files with `extra_configs `__ option +* Include external configuration files in `"platformio.ini" (Project Configuration File) `__ with `extra_configs `__ option (`issue #1590 `_) +* Override default `"platformio.ini" (Project Configuration File) `__ with a custom using ``-c, --project-conf`` option for `platformio run `__, `platformio debug `__, or `platformio test `__ commands + (`issue #1913 `_) * Override default source and include directories for a library via `library.json `__ manifest using ``includeDir`` and ``srcDir`` fields * Added support for the latest Python "Click" package (CLI Builder) (`issue #349 `_) diff --git a/docs b/docs index 45a3b5a3..c5a33bc0 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 45a3b5a365b9ee651087192f0a42dc876b3afeb8 +Subproject commit c5a33bc006dfedfa2d1a2ab1a340615467b885fd diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index f9e93ace..9fd157e3 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -59,7 +59,7 @@ def validate_path(ctx, param, value): # pylint: disable=unused-argument file_okay=False, dir_okay=True, writable=True, resolve_path=True)) @click.option("--keep-build-dir", is_flag=True) @click.option( - "-C", + "-c", "--project-conf", type=click.Path( exists=True, diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 17f088da..fe497f3b 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -47,12 +47,21 @@ from platformio.project.helpers import ( dir_okay=True, writable=True, resolve_path=True)) +@click.option( + "-c", + "--project-conf", + type=click.Path( + exists=True, + file_okay=True, + dir_okay=False, + readable=True, + resolve_path=True)) @click.option("-s", "--silent", is_flag=True) @click.option("-v", "--verbose", is_flag=True) @click.option("--disable-auto-clean", is_flag=True) @click.pass_context -def cli(ctx, environment, target, upload_port, project_dir, silent, verbose, - disable_auto_clean): +def cli(ctx, environment, target, upload_port, project_dir, project_conf, + silent, verbose, disable_auto_clean): # find project directory on upper level if isfile(project_dir): project_dir = find_project_dir_above(project_dir) @@ -70,7 +79,7 @@ def cli(ctx, environment, target, upload_port, project_dir, silent, verbose, fg="yellow") config = ProjectConfig.get_instance( - join(project_dir, "platformio.ini")) + project_conf or join(project_dir, "platformio.ini")) config.validate() results = [] diff --git a/platformio/managers/core.py b/platformio/managers/core.py index be9e3a1d..0dd84552 100644 --- a/platformio/managers/core.py +++ b/platformio/managers/core.py @@ -27,7 +27,7 @@ CORE_PACKAGES = { "contrib-piohome": "^2.0.1", "contrib-pysite": "~2.%d%d.190418" % (sys.version_info[0], sys.version_info[1]), - "tool-pioplus": "^2.1.5", + "tool-pioplus": "^2.2.0", "tool-unity": "~1.20403.0", "tool-scons": "~2.20501.7" if util.PY2 else "~3.30005.0" } diff --git a/tests/commands/test_lib.py b/tests/commands/test_lib.py index 47e5a709..4b75d81b 100644 --- a/tests/commands/test_lib.py +++ b/tests/commands/test_lib.py @@ -61,7 +61,6 @@ def test_global_install_archive(clirunner, validate_cliresult, isolated_pio_home): result = clirunner.invoke(cmd_lib, [ "-g", "install", - "http://www.airspayce.com/mikem/arduino/RadioHead/RadioHead-1.62.zip", "https://github.com/bblanchon/ArduinoJson/archive/v5.8.2.zip", "https://github.com/bblanchon/ArduinoJson/archive/v5.8.2.zip@5.8.2", "SomeLib=http://dl.platformio.org/libraries/archives/0/9540.tar.gz", @@ -77,10 +76,7 @@ def test_global_install_archive(clirunner, validate_cliresult, assert result.exit_code != 0 items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] - items2 = [ - "RadioHead-1.62", "ArduinoJson", "SomeLib_ID54", - "OneWire_ID1", "ESP32WebServer" - ] + items2 = ["ArduinoJson", "SomeLib_ID54", "OneWire_ID1", "ESP32WebServer"] assert set(items1) >= set(items2) @@ -126,7 +122,7 @@ def test_install_duplicates(clirunner, validate_cliresult, without_internet): # archive result = clirunner.invoke(cmd_lib, [ "-g", "install", - "http://www.airspayce.com/mikem/arduino/RadioHead/RadioHead-1.62.zip" + "https://github.com/Pedroalbuquerque/ESP32WebServer/archive/master.zip" ]) validate_cliresult(result) assert "is already installed" in result.output @@ -148,7 +144,7 @@ def test_global_lib_list(clirunner, validate_cliresult): ("Source: https://github.com/Pedroalbuquerque/ESP32WebServer/archive/master.zip", "Version: 5.10.1", "Source: git+https://github.com/gioblu/PJON.git#3.0", - "Version: 1fb26fd", "RadioHead-1.62") + "Version: 1fb26fd") ]) result = clirunner.invoke(cmd_lib, ["-g", "list", "--json-output"]) @@ -161,10 +157,9 @@ def test_global_lib_list(clirunner, validate_cliresult): items1 = [i['name'] for i in json.loads(result.output)] items2 = [ "ESP32WebServer", "ArduinoJson", "ArduinoJson", "ArduinoJson", - "ArduinoJson", "AsyncMqttClient", "AsyncTCP", "SomeLib", - "ESPAsyncTCP", "NeoPixelBus", "OneWire", "PJON", "PJON", - "PubSubClient", "RFcontrol", "RadioHead-1.62", "platformio-libmirror", - "rs485-nodeproto" + "ArduinoJson", "AsyncMqttClient", "AsyncTCP", "SomeLib", "ESPAsyncTCP", + "NeoPixelBus", "OneWire", "PJON", "PJON", "PubSubClient", "RFcontrol", + "platformio-libmirror", "rs485-nodeproto" ] assert sorted(items1) == sorted(items2) @@ -172,9 +167,9 @@ def test_global_lib_list(clirunner, validate_cliresult): "{name}@{version}".format(**item) for item in json.loads(result.output) ] versions2 = [ - 'ArduinoJson@5.8.2', 'ArduinoJson@5.10.1', 'AsyncMqttClient@0.8.2', - 'NeoPixelBus@2.2.4', 'PJON@07fe9aa', 'PJON@1fb26fd', - 'PubSubClient@bef5814', 'RFcontrol@77d4eb3f8a', 'RadioHead-1.62@0.0.0' + "ArduinoJson@5.8.2", "ArduinoJson@5.10.1", "AsyncMqttClient@0.8.2", + "NeoPixelBus@2.2.4", "PJON@07fe9aa", "PJON@1fb26fd", + "PubSubClient@bef5814", "RFcontrol@77d4eb3f8a" ] assert set(versions1) >= set(versions2) @@ -205,7 +200,7 @@ def test_global_lib_update(clirunner, validate_cliresult): # update rest libraries result = clirunner.invoke(cmd_lib, ["-g", "update"]) validate_cliresult(result) - assert result.output.count("[Detached]") == 6 + assert result.output.count("[Detached]") == 5 assert result.output.count("[Up-to-date]") == 11 assert "Uninstalling RFcontrol @ 77d4eb3f8a" in result.output @@ -235,10 +230,10 @@ def test_global_lib_uninstall(clirunner, validate_cliresult, items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] items2 = [ - "RadioHead-1.62", "rs485-nodeproto", "platformio-libmirror", + "rs485-nodeproto", "platformio-libmirror", "PubSubClient", "ArduinoJson@src-69ebddd821f771debe7ee734d3c7fa81", - "ESPAsyncTCP_ID305", "SomeLib_ID54", "NeoPixelBus_ID547", - "PJON", "AsyncMqttClient_ID346", "ArduinoJson_ID64", + "ESPAsyncTCP_ID305", "SomeLib_ID54", "NeoPixelBus_ID547", "PJON", + "AsyncMqttClient_ID346", "ArduinoJson_ID64", "PJON@src-79de467ebe19de18287becff0a1fb42d", "ESP32WebServer" ] assert set(items1) == set(items2) diff --git a/tests/test_misc.py b/tests/test_misc.py index b918767b..8f6fccf2 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -18,6 +18,12 @@ import requests from platformio import exception, util +def test_platformio_cli(): + result = util.exec_command(["pio", "--help"]) + assert result['returncode'] == 0 + assert "Usage: pio [OPTIONS] COMMAND [ARGS]..." in result['out'] + + def test_ping_internet_ips(): for ip in util.PING_INTERNET_IPS: requests.get("http://%s" % ip, allow_redirects=False, timeout=2)