Refactor project config options

This commit is contained in:
Ivan Kravets
2019-05-30 16:38:04 +03:00
parent 8d05903bf3
commit 3cc4af1723
14 changed files with 401 additions and 258 deletions

15
.vscode/settings.json vendored
View File

@ -1,15 +0,0 @@
{
"python.pythonPath": "${workspaceRoot}/.tox/develop/bin/python",
"python.formatting.provider": "yapf",
"files.exclude": {
"**/*.pyc": true,
"*.egg-info": true,
".cache": true,
"build": true,
"dist": true
},
"editor.rulers": [79],
"restructuredtext.builtDocumentationPath": "${workspaceRoot}/docs/_build/html",
"restructuredtext.confPath": "${workspaceRoot}/docs",
"restructuredtext.linter.executablePath": "${workspaceRoot}/.tox/docs/bin/restructuredtext-lint"
}

View File

@ -10,7 +10,7 @@ yapf:
yapf --recursive --in-place platformio/
test:
py.test -v -s -n 3 --dist=loadscope tests --ignore tests/test_examples.py --ignore tests/test_pkgmanifest.py
py.test --verbose --capture=no --exitfirst -n 3 --dist=loadscope tests --ignore tests/test_examples.py --ignore tests/test_pkgmanifest.py
before-commit: isort yapf lint test

View File

@ -163,22 +163,17 @@ def device_list( # pylint: disable=too-many-branches
"--environment",
help="Load configuration from `platformio.ini` and specified environment")
def device_monitor(**kwargs): # pylint: disable=too-many-branches
custom_monitor_flags = []
try:
env_options = get_project_options(kwargs['project_dir'],
kwargs['environment'])
if "monitor_flags" in env_options:
custom_monitor_flags = ProjectConfig.parse_multi_values(
env_options['monitor_flags'])
if env_options:
for k in ("port", "speed", "rts", "dtr"):
k2 = "monitor_%s" % k
if k == "speed":
k = "baud"
if kwargs[k] is None and k2 in env_options:
kwargs[k] = env_options[k2]
if k != "port":
kwargs[k] = int(kwargs[k])
for k in ("port", "speed", "rts", "dtr"):
k2 = "monitor_%s" % k
if k == "speed":
k = "baud"
if kwargs[k] is None and k2 in env_options:
kwargs[k] = env_options[k2]
if k != "port":
kwargs[k] = int(kwargs[k])
except exception.NotPlatformIOProject:
pass
@ -187,12 +182,12 @@ def device_monitor(**kwargs): # pylint: disable=too-many-branches
if len(ports) == 1:
kwargs['port'] = ports[0]['port']
sys.argv = ["monitor"] + custom_monitor_flags
sys.argv = ["monitor"] + env_options.get("monitor_flags", [])
for k, v in kwargs.items():
if k in ("port", "baud", "rts", "dtr", "environment", "project_dir"):
continue
k = "--" + k.replace("_", "-")
if k in custom_monitor_flags:
if k in env_options.get("monitor_flags", []):
continue
if isinstance(v, bool):
if v:

View File

@ -44,10 +44,8 @@ class ProjectRPC(object):
config.validate(validate_options=False)
libdeps_dir = get_project_libdeps_dir()
if config.has_section("platformio") and \
config.has_option("platformio", "lib_extra_dirs"):
data['libExtraDirs'].extend(
config.getlist("platformio", "lib_extra_dirs"))
data['libExtraDirs'].extend(
config.get("platformio", "lib_extra_dirs", []))
for section in config.sections():
if not section.startswith("env:"):
@ -55,9 +53,8 @@ class ProjectRPC(object):
data['envLibdepsDirs'].append(join(libdeps_dir, section[4:]))
if config.has_option(section, "board"):
data['boards'].append(config.get(section, "board"))
if config.has_option(section, "lib_extra_dirs"):
data['libExtraDirs'].extend(
config.getlist(section, "lib_extra_dirs"))
data['libExtraDirs'].extend(
config.get(section, "lib_extra_dirs", []))
# skip non existing folders and resolve full path
for key in ("envLibdepsDirs", "libExtraDirs"):
@ -233,10 +230,8 @@ class ProjectRPC(object):
try:
config = ProjectConfig(join(project_dir, "platformio.ini"))
config.validate(validate_options=False)
if config.has_section("platformio") and \
config.has_option("platformio", "description"):
project_description = config.get(
"platformio", "description")
project_description = config.get("platformio",
"description")
except exception.PlatformIOProjectException:
continue

View File

@ -70,7 +70,6 @@ def cli(
project_option,
env_prefix,
silent):
if not silent:
if project_dir == getcwd():
click.secho(

View File

@ -109,9 +109,8 @@ def cli(ctx, **options):
continue
storage_dir = join(libdeps_dir, env)
ctx.meta[CTX_META_STORAGE_DIRS_KEY].append(storage_dir)
if config.has_option("env:" + env, "lib_deps"):
ctx.meta[CTX_META_STORAGE_LIBDEPS_KEY][
storage_dir] = config.getlist("env:" + env, "lib_deps")
ctx.meta[CTX_META_STORAGE_LIBDEPS_KEY][storage_dir] = config.get(
"env:" + env, "lib_deps", [])
@cli.command("install", short_help="Install library")
@ -175,8 +174,7 @@ def lib_install( # pylint: disable=too-many-arguments
if project_environments and env not in project_environments:
continue
config.expand_interpolations = False
lib_deps = (config.getlist("env:" + env, "lib_deps")
if config.has_option("env:" + env, "lib_deps") else [])
lib_deps = config.get("env:" + env, "lib_deps", [])
for library in libraries:
if library in lib_deps:
continue

View File

@ -107,9 +107,8 @@ def cli( # pylint: disable=redefined-builtin
# filter and ignore patterns
patterns = dict(filter=list(filter), ignore=list(ignore))
for key in patterns:
if config.has_option(section, "test_%s" % key):
patterns[key].extend(
config.getlist(section, "test_%s" % key))
patterns[key].extend(
config.get(section, "test_%s" % key, []))
skip_conditions = [
environment and envname not in environment,

View File

@ -92,9 +92,10 @@ class TestProcessorBase(object):
self._outputcpp_generated = False
def get_transport(self):
transport = self.env_options.get("framework")
if self.env_options.get("platform") == "native":
transport = "native"
elif "framework" in self.env_options:
transport = self.env_options.get("framework")[0]
if "test_transport" in self.env_options:
transport = self.env_options['test_transport']
if transport not in TRANSPORT_OPTIONS:

View File

@ -21,6 +21,7 @@ from os.path import isfile
import click
from platformio import exception
from platformio.project.options import ProjectOptions
try:
import ConfigParser as ConfigParser
@ -39,98 +40,6 @@ CONFIG_HEADER = """;PlatformIO Project Configuration File
"""
KNOWN_PLATFORMIO_OPTIONS = [
"description",
"env_default",
"extra_configs",
# Dirs
"core_dir",
"globallib_dir",
"platforms_dir",
"packages_dir",
"cache_dir",
"workspace_dir",
"build_dir",
"libdeps_dir",
"lib_dir",
"include_dir",
"src_dir",
"test_dir",
"boards_dir",
"data_dir"
]
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",
"monitor_flags",
# 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):
@ -191,11 +100,7 @@ class ProjectConfig(object):
return
# load extra configs
if (not self._parser.has_section("platformio")
or not self._parser.has_option("platformio", "extra_configs")):
return
extra_configs = self.getlist("platformio", "extra_configs")
for pattern in extra_configs:
for pattern in self.get("platformio", "extra_configs", []):
for item in glob.glob(pattern):
self.read(item)
@ -212,6 +117,14 @@ class ProjectConfig(object):
if option not in options:
options.append(option)
# handle system environment variables
scope = section.split(":", 1)[0]
for option_meta in ProjectOptions.values():
if option_meta.scope != scope or option_meta.name in options:
continue
if option_meta.sysenvvar and option_meta.sysenvvar in os.environ:
options.append(option_meta.name)
return options
def has_option(self, section, option):
@ -239,37 +152,64 @@ class ProjectConfig(object):
value = "\n" + value # start from a new line
self._parser.set(section, option, value)
def get(self, section, option):
def getraw(self, section, option):
if not self.expand_interpolations:
return self._parser.get(section, option)
try:
value = self._parser.get(section, option)
except ConfigParser.NoOptionError:
except ConfigParser.NoOptionError as e:
if not section.startswith("env:"):
raise e
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)
return self.VARTPL_RE.sub(self._re_interpolation_handler, value)
def _re_sub_handler(self, match):
def _re_interpolation_handler(self, match):
section, option = match.group(1), match.group(2)
if section == "sysenv":
return os.getenv(option)
return self.get(section, option)
return self.getraw(section, option)
def getlist(self, section, option):
return self.parse_multi_values(self.get(section, option))
def get(self, section, option, default=None):
value = default
try:
value = self.getraw(section, option)
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
pass # handle value from system environment
except ConfigParser.Error as e:
raise exception.InvalidProjectConf(self.path, str(e))
option_meta = ProjectOptions.get(
"%s.%s" % (section.split(":", 1)[0], option))
if not option_meta:
return value
if value and option_meta.multiple:
value = self.parse_multi_values(value)
if option_meta.sysenvvar:
envvar_value = os.getenv(option_meta.sysenvvar)
if not envvar_value and option_meta.oldnames:
for oldoption in option_meta.oldnames:
envvar_value = os.getenv("PLATFORMIO_" + oldoption.upper())
if envvar_value:
break
if envvar_value and option_meta.multiple:
value = value or []
value.extend(self.parse_multi_values(envvar_value))
elif envvar_value and not value:
value = envvar_value
return value
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.getlist("platformio", "env_default")
return self.get("platformio", "env_default", [])
def validate(self, envs=None, validate_options=True):
if not isfile(self.path):
@ -286,66 +226,54 @@ class ProjectConfig(object):
return self.validate_options() if validate_options else True
def validate_options(self):
return (self._validate_platformio_options()
and self._validate_env_options())
def _validate_platformio_options(self):
if not self._parser.has_section("platformio"):
return True
warnings = set()
# legacy `lib_extra_dirs`
if self._parser.has_option("platformio", "lib_extra_dirs"):
# legacy `lib_extra_dirs` in [platformio]
if (self._parser.has_section("platformio")
and self._parser.has_option("platformio", "lib_extra_dirs")):
if not self._parser.has_section("env"):
self._parser.add_section("env")
self._parser.set("env", "lib_extra_dirs",
self._parser.get("platformio", "lib_extra_dirs"))
self._parser.remove_option("platformio", "lib_extra_dirs")
warnings.add(
"`lib_extra_dirs` option is deprecated in section "
"`platformio`! Please move it to global `env` section")
click.secho(
"Warning! `lib_extra_dirs` option is deprecated in section "
"[platformio]! Please move it to global `env` section",
fg="yellow")
unknown = set(k for k, _ in self.items("platformio")) - set(
KNOWN_PLATFORMIO_OPTIONS)
if unknown:
warnings.add(
"Ignore unknown `%s` options in section `[platformio]`" %
", ".join(unknown))
return self._validate_unknown_options()
for warning in warnings:
click.secho("Warning! %s" % warning, fg="yellow")
return True
def _validate_env_options(self):
def _validate_unknown_options(self):
warnings = set()
renamed_options = {}
for option in ProjectOptions.values():
if option.oldnames:
renamed_options.update(
{name: option.name
for name in option.oldnames})
for section in self._parser.sections():
if section != "env" and not section.startswith("env:"):
continue
for option in self._parser.options(section):
# obsolete
if option in RENAMED_OPTIONS:
if option in renamed_options:
warnings.add(
"`%s` option in section `[%s]` is deprecated and will "
"be removed in the next release! Please use `%s` "
"instead" % (option, section, RENAMED_OPTIONS[option]))
"instead" % (option, section, renamed_options[option]))
# rename on-the-fly
self._parser.set(section, RENAMED_OPTIONS[option],
self._parser.set(section, renamed_options[option],
self._parser.get(section, option))
self._parser.remove_option(section, option)
continue
# unknown
scope = section.split(":", 1)[0]
unknown_conditions = [
option not in KNOWN_ENV_OPTIONS,
not option.startswith("custom_"),
not option.startswith("board_")
("%s.%s" % (scope, option)) not in ProjectOptions,
scope != "env" or
not option.startswith(("custom_", "board_"))
] # yapf: disable
if all(unknown_conditions):
warnings.add(
"Detected non-PlatformIO `%s` option in `[%s]` section"
% (option, section))
warnings.add("Ignore unknown option `%s` in section `[%s]`"
% (option, section))
for warning in warnings:
click.secho("Warning! %s" % warning, fg="yellow")

View File

@ -15,7 +15,7 @@
import os
from hashlib import sha1
from os import walk
from os.path import (abspath, dirname, expanduser, isdir, isfile, join,
from os.path import (dirname, expanduser, isdir, isfile, join, realpath,
splitdrive)
from platformio import __version__
@ -44,37 +44,23 @@ def find_project_dir_above(path):
def get_project_optional_dir(name, default=None):
paths = None
project_dir = get_project_dir()
config = ProjectConfig.get_instance(join(project_dir, "platformio.ini"))
optional_dir = config.get("platformio", name)
# check for system environment variable
var_name = "PLATFORMIO_%s" % name.upper()
if var_name in os.environ:
paths = os.getenv(var_name)
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:
if not optional_dir:
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(
if "$PROJECT_HASH" in optional_dir:
optional_dir = optional_dir.replace(
"$PROJECT_HASH",
sha1(project_dir if PY2 else project_dir.encode()).hexdigest()
[:10])
return paths
if optional_dir.startswith("~"):
optional_dir = expanduser(optional_dir)
return realpath(optional_dir)
def get_project_core_dir():

View File

@ -0,0 +1,199 @@
# 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.
# pylint: disable=redefined-builtin, too-many-arguments
from collections import OrderedDict, namedtuple
ConfigOptionClass = namedtuple("ConfigOption", [
"scope", "name", "type", "multiple", "sysenvvar", "buildenvvar", "oldnames"
])
def ConfigOption(scope,
name,
type=str,
multiple=False,
sysenvvar=None,
buildenvvar=None,
oldnames=None):
return ConfigOptionClass(scope, name, type, multiple, sysenvvar,
buildenvvar, oldnames)
def ConfigPlatformioOption(*args, **kwargs):
return ConfigOption("platformio", *args, **kwargs)
def ConfigEnvOption(*args, **kwargs):
return ConfigOption("env", *args, **kwargs)
ProjectOptions = OrderedDict([
("%s.%s" % (option.scope, option.name), option) for option in [
#
# [platformio]
#
ConfigPlatformioOption(name="description"),
ConfigPlatformioOption(
name="env_default",
multiple=True,
sysenvvar="PLATFORMIO_ENV_DEFAULT"),
ConfigPlatformioOption(name="extra_configs", multiple=True),
# Dirs
ConfigPlatformioOption(
name="core_dir",
oldnames=["home_dir"],
sysenvvar="PLATFORMIO_CORE_DIR"),
ConfigPlatformioOption(
name="globallib_dir", sysenvvar="PLATFORMIO_GLOBALLIB_DIR"),
ConfigPlatformioOption(
name="platforms_dir", sysenvvar="PLATFORMIO_PLATFORMS_DIR"),
ConfigPlatformioOption(
name="packages_dir", sysenvvar="PLATFORMIO_PACKAGES_DIR"),
ConfigPlatformioOption(
name="cache_dir", sysenvvar="PLATFORMIO_CACHE_DIR"),
ConfigPlatformioOption(
name="workspace_dir", sysenvvar="PLATFORMIO_WORKSPACE_DIR"),
ConfigPlatformioOption(
name="build_dir", sysenvvar="PLATFORMIO_BUILD_DIR"),
ConfigPlatformioOption(
name="libdeps_dir", sysenvvar="PLATFORMIO_LIBDEPS_DIR"),
ConfigPlatformioOption(name="lib_dir", sysenvvar="PLATFORMIO_LIB_DIR"),
ConfigPlatformioOption(
name="include_dir", sysenvvar="PLATFORMIO_INCLUDE_DIR"),
ConfigPlatformioOption(name="src_dir", sysenvvar="PLATFORMIO_SRC_DIR"),
ConfigPlatformioOption(
name="test_dir", sysenvvar="PLATFORMIO_TEST_DIR"),
ConfigPlatformioOption(
name="boards_dir", sysenvvar="PLATFORMIO_BOARDS_DIR"),
ConfigPlatformioOption(
name="data_dir", sysenvvar="PLATFORMIO_DATA_DIR"),
#
# [env]
#
# Generic
ConfigEnvOption(name="platform", buildenvvar="PIOPLATFORM"),
ConfigEnvOption(
name="framework", multiple=True, buildenvvar="PIOFRAMEWORK"),
ConfigEnvOption(name="targets", multiple=True),
# Board
ConfigEnvOption(name="board", buildenvvar="BOARD"),
ConfigEnvOption(
name="board_build.mcu",
oldnames=["board_mcu"],
buildenvvar="BOARD_MCU"),
ConfigEnvOption(
name="board_build.f_cpu",
oldnames=["board_f_cpu"],
buildenvvar="BOARD_F_CPU"),
ConfigEnvOption(
name="board_build.f_flash",
oldnames=["board_f_flash"],
buildenvvar="BOARD_F_FLASH"),
ConfigEnvOption(
name="board_build.flash_mode",
oldnames=["board_flash_mode"],
buildenvvar="BOARD_FLASH_MODE"),
# Build
ConfigEnvOption(
name="build_flags",
multiple=True,
sysenvvar="PLATFORMIO_BUILD_FLAGS",
buildenvvar="BUILD_FLAGS"),
ConfigEnvOption(
name="src_build_flags",
multiple=True,
sysenvvar="PLATFORMIO_SRC_BUILD_FLAGS",
buildenvvar="SRC_BUILD_FLAGS"),
ConfigEnvOption(
name="build_unflags",
multiple=True,
sysenvvar="PLATFORMIO_BUILD_UNFLAGS",
buildenvvar="BUILD_UNFLAGS"),
ConfigEnvOption(
name="src_filter",
multiple=True,
sysenvvar="PLATFORMIO_SRC_FILTER",
buildenvvar="SRC_FILTER"),
# Upload
ConfigEnvOption(
name="upload_port",
sysenvvar="PLATFORMIO_UPLOAD_PORT",
buildenvvar="UPLOAD_PORT"),
ConfigEnvOption(name="upload_protocol", buildenvvar="UPLOAD_PROTOCOL"),
ConfigEnvOption(name="upload_speed", buildenvvar="UPLOAD_SPEED"),
ConfigEnvOption(
name="upload_flags",
multiple=True,
sysenvvar="PLATFORMIO_UPLOAD_FLAGS",
buildenvvar="UPLOAD_FLAGS"),
ConfigEnvOption(
name="upload_resetmethod", buildenvvar="UPLOAD_RESETMETHOD"),
# Monitor
ConfigEnvOption(name="monitor_port"),
ConfigEnvOption(
name="monitor_speed", oldnames=["monitor_baud"], type=int),
ConfigEnvOption(name="monitor_rts"),
ConfigEnvOption(name="monitor_dtr"),
ConfigEnvOption(name="monitor_flags", multiple=True),
# Library
ConfigEnvOption(
name="lib_deps",
oldnames=["lib_use", "lib_force", "lib_install"],
multiple=True),
ConfigEnvOption(name="lib_ignore", multiple=True),
ConfigEnvOption(
name="lib_extra_dirs",
multiple=True,
sysenvvar="PLATFORMIO_LIB_EXTRA_DIRS"),
ConfigEnvOption(name="lib_ldf_mode"),
ConfigEnvOption(name="lib_compat_mode"),
ConfigEnvOption(name="lib_archive", type=bool), # FIXME: B
# Test
ConfigEnvOption(name="test_filter", multiple=True),
ConfigEnvOption(name="test_ignore", multiple=True),
ConfigEnvOption(name="test_port"),
ConfigEnvOption(name="test_speed"),
ConfigEnvOption(name="test_transport"),
ConfigEnvOption(name="test_build_project_src"),
# Debug
ConfigEnvOption(name="debug_tool"),
ConfigEnvOption(name="debug_init_break"),
ConfigEnvOption(name="debug_init_cmds", multiple=True),
ConfigEnvOption(name="debug_extra_cmds", multiple=True),
ConfigEnvOption(name="debug_load_cmd"),
ConfigEnvOption(name="debug_load_mode"),
ConfigEnvOption(name="debug_server"),
ConfigEnvOption(name="debug_port"),
ConfigEnvOption(name="debug_svd_path"),
# Other
ConfigEnvOption(
name="extra_scripts",
oldnames=["extra_script"],
multiple=True,
sysenvvar="PLATFORMIO_EXTRA_SCRIPTS")
]
])

View File

@ -20,7 +20,7 @@ from platformio.commands.lib import cli as cmd_lib
def test_ci_empty(clirunner):
result = clirunner.invoke(cmd_ci)
assert result.exit_code == 2
assert result.exit_code != 0
assert "Invalid value: Missing argument 'src'" in result.output

View File

@ -16,7 +16,7 @@ import json
from os import getcwd, makedirs
from os.path import getsize, isdir, isfile, join
from platformio import exception, util
from platformio import exception
from platformio.commands.boards import cli as cmd_boards
from platformio.commands.init import cli as cmd_init
from platformio.project.config import ProjectConfig
@ -109,13 +109,12 @@ def test_init_special_board(clirunner, validate_cliresult):
config = ProjectConfig(join(getcwd(), "platformio.ini"))
config.validate()
expected_result = [("platform", str(boards[0]['platform'])),
("framework",
str(boards[0]['frameworks'][0])), ("board", "uno")]
expected_result = [("platform", boards[0]['platform']),
("board", "uno"),
("framework", [boards[0]['frameworks'][0]])]
assert config.has_section("env:uno")
assert not set(expected_result).symmetric_difference(
set(config.items("env:uno")))
assert config.items("env:uno") == expected_result
def test_init_enable_auto_uploading(clirunner, validate_cliresult):
@ -126,11 +125,10 @@ def test_init_enable_auto_uploading(clirunner, validate_cliresult):
validate_pioproject(getcwd())
config = ProjectConfig(join(getcwd(), "platformio.ini"))
config.validate()
expected_result = [("platform", "atmelavr"), ("framework", "arduino"),
("board", "uno"), ("targets", "upload")]
expected_result = [("targets", ["upload"]), ("platform", "atmelavr"),
("board", "uno"), ("framework", ["arduino"])]
assert config.has_section("env:uno")
assert not set(expected_result).symmetric_difference(
set(config.items("env:uno")))
assert config.items("env:uno") == expected_result
def test_init_custom_framework(clirunner, validate_cliresult):
@ -141,11 +139,10 @@ def test_init_custom_framework(clirunner, validate_cliresult):
validate_pioproject(getcwd())
config = ProjectConfig(join(getcwd(), "platformio.ini"))
config.validate()
expected_result = [("platform", "teensy"), ("framework", "mbed"),
("board", "teensy31")]
expected_result = [("platform", "teensy"), ("board", "teensy31"),
("framework", ["mbed"])]
assert config.has_section("env:teensy31")
assert not set(expected_result).symmetric_difference(
set(config.items("env:teensy31")))
assert config.items("env:teensy31") == expected_result
def test_init_incorrect_board(clirunner):

View File

@ -14,7 +14,9 @@
import os
from platformio.project.config import ProjectConfig
import pytest
from platformio.project.config import ConfigParser, ProjectConfig
BASE_CONFIG = """
[platformio]
@ -26,7 +28,9 @@ extra_configs =
# global options per [env:*]
[env]
monitor_speed = 115200
lib_deps = Lib1, Lib2
lib_deps =
Lib1
Lib2
lib_ignore = ${custom.lib_ignore}
[custom]
@ -46,6 +50,7 @@ build_flags = ${custom.lib_flags} ${custom.debug_flags}
[env:extra_2]
build_flags = ${custom.debug_flags} ${custom.extra_flags}
lib_ignore = ${env.lib_ignore}, Lib3
upload_port = /dev/extra_2/port
"""
EXTRA_DEBUG_CONFIG = """
@ -58,7 +63,7 @@ build_flags = -Og
"""
def test_parser(tmpdir):
def test_real_config(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)
@ -68,6 +73,16 @@ def test_parser(tmpdir):
config = ProjectConfig(tmpdir.join("platformio.ini").strpath)
assert config
# unknown section
with pytest.raises(ConfigParser.NoSectionError):
config.getraw("unknown_section", "unknown_option")
# unknown option
with pytest.raises(ConfigParser.NoOptionError):
config.getraw("custom", "unknown_option")
# unknown option even if exists in [env]
with pytest.raises(ConfigParser.NoOptionError):
config.getraw("platformio", "monitor_speed")
# sections
assert config.sections() == [
"platformio", "env", "custom", "env:base", "env:extra_1", "env:extra_2"
@ -88,29 +103,75 @@ def test_parser(tmpdir):
# sysenv
assert config.get("custom", "extra_flags") == ""
assert config.get("env:base", "build_flags") == ["-D DEBUG=1"]
assert config.get("env:base", "upload_port") is None
assert config.get("env:extra_2", "upload_port") == "/dev/extra_2/port"
os.environ["PLATFORMIO_BUILD_FLAGS"] = "-DSYSENVDEPS1 -DSYSENVDEPS2"
os.environ["PLATFORMIO_UPLOAD_PORT"] = "/dev/sysenv/port"
os.environ["__PIO_TEST_CNF_EXTRA_FLAGS"] = "-L /usr/local/lib"
assert config.get("custom", "extra_flags") == "-L /usr/local/lib"
assert config.get("env:base", "build_flags") == [
"-D DEBUG=1 -L /usr/local/lib", "-DSYSENVDEPS1 -DSYSENVDEPS2"
]
assert config.get("env:base", "upload_port") == "/dev/sysenv/port"
assert config.get("env:extra_2", "upload_port") == "/dev/extra_2/port"
# getraw
assert config.getraw("env:extra_1", "lib_deps") == "\nLib1\nLib2"
assert config.getraw("env:extra_1", "build_flags") == "-lc -lm -D DEBUG=1"
# get
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_1", "build_flags") == [
"-lc -lm -D DEBUG=1", "-DSYSENVDEPS1 -DSYSENVDEPS2"
]
assert config.get("env:extra_2", "build_flags") == [
"-Og", "-DSYSENVDEPS1 -DSYSENVDEPS2"]
assert config.get("env:extra_2", "monitor_speed") == "115200"
assert config.get("env:base",
"build_flags") == ("-D DEBUG=1 -L /usr/local/lib")
assert config.get("env:base", "build_flags") == ([
"-D DEBUG=1 -L /usr/local/lib", "-DSYSENVDEPS1 -DSYSENVDEPS2"
])
# items
assert config.items("custom") == [("debug_flags", "-D DEBUG=1"),
("lib_flags", "-lc -lm"),
("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")]
assert config.items("custom") == [
("debug_flags", "-D DEBUG=1"),
("lib_flags", "-lc -lm"),
("extra_flags", "-L /usr/local/lib"),
("lib_ignore", "LibIgnoreCustom")
] # yapf: disable
assert config.items(env="extra_1") == [
("build_flags", ["-lc -lm -D DEBUG=1", "-DSYSENVDEPS1 -DSYSENVDEPS2"]),
("monitor_speed", "115200"),
("lib_deps", ["Lib1", "Lib2"]),
("lib_ignore", ["LibIgnoreCustom"]),
("upload_port", "/dev/sysenv/port")
] # yapf: disable
assert config.items(env="extra_2") == [
("build_flags", ["-Og", "-DSYSENVDEPS1 -DSYSENVDEPS2"]),
("lib_ignore", ["LibIgnoreCustom", "Lib3"]),
("upload_port", "/dev/extra_2/port"),
("monitor_speed", "115200"),
("lib_deps", ["Lib1", "Lib2"])
] # yapf: disable
# cleanup system environment variables
del os.environ["PLATFORMIO_BUILD_FLAGS"]
del os.environ["PLATFORMIO_UPLOAD_PORT"]
del os.environ["__PIO_TEST_CNF_EXTRA_FLAGS"]
def test_empty_config():
config = ProjectConfig("/non/existing/platformio.ini")
# unknown section
with pytest.raises(ConfigParser.NoSectionError):
config.getraw("unknown_section", "unknown_option")
assert config.sections() == []
assert config.get("section", "option") is None
assert config.get("section", "option", 13) == 13
# sysenv
os.environ["PLATFORMIO_CORE_DIR"] = "/custom/core/dir"
assert config.get("platformio", "core_dir") == "/custom/core/dir"
del os.environ["PLATFORMIO_CORE_DIR"]