From 4f98a3fd42e4f0e5ec9dcc9c9ce3f6ae1c2b247f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 8 May 2019 20:19:39 +0300 Subject: [PATCH] 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")]