mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-30 18:17:13 +02:00
Include external configuration files with "extra_configs" option // Resolve #1590
This commit is contained in:
@ -20,4 +20,4 @@ confidence=
|
|||||||
# --disable=W"
|
# --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=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
|
||||||
|
@ -7,8 +7,10 @@ PlatformIO 4.0
|
|||||||
4.0.0 (2019-??-??)
|
4.0.0 (2019-??-??)
|
||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
* Added Python 3.5+ support
|
* Python 3 support
|
||||||
(`issue #895 <https://github.com/platformio/platformio-core/issues/895>`_)
|
(`issue #895 <https://github.com/platformio/platformio-core/issues/895>`_)
|
||||||
|
* Include external configuration files with "extra_configs" option
|
||||||
|
(`issue #1590 <https://github.com/platformio/platformio-core/issues/1590>`_)
|
||||||
|
|
||||||
PlatformIO 3.0
|
PlatformIO 3.0
|
||||||
--------------
|
--------------
|
||||||
|
2
docs
2
docs
Submodule docs updated: 4350844caf...9a51b84742
@ -130,7 +130,7 @@ class EnvironmentProcessor(object):
|
|||||||
KNOWN_PLATFORMIO_OPTIONS = [
|
KNOWN_PLATFORMIO_OPTIONS = [
|
||||||
"description", "env_default", "home_dir", "lib_dir", "libdeps_dir",
|
"description", "env_default", "home_dir", "lib_dir", "libdeps_dir",
|
||||||
"include_dir", "src_dir", "build_dir", "data_dir", "test_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 = [
|
KNOWN_ENV_OPTIONS = [
|
||||||
|
@ -207,7 +207,7 @@ class InvalidLibConfURL(PlatformioException):
|
|||||||
|
|
||||||
class InvalidProjectConf(PlatformioException):
|
class InvalidProjectConf(PlatformioException):
|
||||||
|
|
||||||
MESSAGE = "Invalid `platformio.ini`, project configuration file: '{0}'"
|
MESSAGE = ("Invalid '{0}' (project configuration file): '{1}'")
|
||||||
|
|
||||||
|
|
||||||
class BuildScriptNotFound(PlatformioException):
|
class BuildScriptNotFound(PlatformioException):
|
||||||
|
13
platformio/project/__init__.py
Normal file
13
platformio/project/__init__.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# 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.
|
106
platformio/project/config.py
Normal file
106
platformio/project/config.py
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# 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)
|
@ -33,52 +33,17 @@ import click
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
from platformio import __apiurl__, __version__, exception
|
from platformio import __apiurl__, __version__, exception
|
||||||
|
from platformio.project.config import ProjectConfig
|
||||||
|
|
||||||
# pylint: disable=too-many-ancestors
|
# pylint: disable=too-many-ancestors
|
||||||
|
|
||||||
PY2 = sys.version_info[0] == 2
|
PY2 = sys.version_info[0] == 2
|
||||||
if PY2:
|
if PY2:
|
||||||
import ConfigParser as ConfigParser
|
|
||||||
string_types = basestring # pylint: disable=undefined-variable
|
string_types = basestring # pylint: disable=undefined-variable
|
||||||
else:
|
else:
|
||||||
import configparser as ConfigParser
|
|
||||||
string_types = str
|
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):
|
class AsyncPipe(Thread):
|
||||||
|
|
||||||
def __init__(self, outcallback=None):
|
def __init__(self, outcallback=None):
|
||||||
@ -347,34 +312,17 @@ def get_projectdata_dir():
|
|||||||
"data"))
|
"data"))
|
||||||
|
|
||||||
|
|
||||||
def load_project_config(path=None):
|
def load_project_config(path=None): # FIXME:
|
||||||
if not path or isdir(path):
|
if not path or isdir(path):
|
||||||
path = join(path or get_project_dir(), "platformio.ini")
|
path = join(path or get_project_dir(), "platformio.ini")
|
||||||
if not isfile(path):
|
if not isfile(path):
|
||||||
raise exception.NotPlatformIOProject(
|
raise exception.NotPlatformIOProject(
|
||||||
dirname(path) if path.endswith("platformio.ini") else path)
|
dirname(path) if path.endswith("platformio.ini") else path)
|
||||||
cp = ProjectConfig()
|
return ProjectConfig(path)
|
||||||
try:
|
|
||||||
cp.read(path)
|
|
||||||
except ConfigParser.Error as e:
|
|
||||||
raise exception.InvalidProjectConf(str(e))
|
|
||||||
return cp
|
|
||||||
|
|
||||||
|
|
||||||
def parse_conf_multi_values(items):
|
def parse_conf_multi_values(items): # FIXME:
|
||||||
result = []
|
return ProjectConfig.parse_multi_values(items)
|
||||||
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 change_filemtime(path, mtime):
|
def change_filemtime(path, mtime):
|
||||||
|
74
tests/test_projectconf.py
Normal file
74
tests/test_projectconf.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# 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"
|
Reference in New Issue
Block a user