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/ yapf --recursive --in-place platformio/
test: 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 before-commit: isort yapf lint test

View File

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

View File

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

View File

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

View File

@@ -109,9 +109,8 @@ def cli(ctx, **options):
continue continue
storage_dir = join(libdeps_dir, env) storage_dir = join(libdeps_dir, env)
ctx.meta[CTX_META_STORAGE_DIRS_KEY].append(storage_dir) 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.get(
ctx.meta[CTX_META_STORAGE_LIBDEPS_KEY][ "env:" + env, "lib_deps", [])
storage_dir] = config.getlist("env:" + env, "lib_deps")
@cli.command("install", short_help="Install library") @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: if project_environments and env not in project_environments:
continue continue
config.expand_interpolations = False config.expand_interpolations = False
lib_deps = (config.getlist("env:" + env, "lib_deps") lib_deps = config.get("env:" + env, "lib_deps", [])
if config.has_option("env:" + env, "lib_deps") else [])
for library in libraries: for library in libraries:
if library in lib_deps: if library in lib_deps:
continue continue

View File

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

View File

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

View File

@@ -21,6 +21,7 @@ from os.path import isfile
import click import click
from platformio import exception from platformio import exception
from platformio.project.options import ProjectOptions
try: try:
import ConfigParser as ConfigParser 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): class ProjectConfig(object):
@@ -191,11 +100,7 @@ class ProjectConfig(object):
return return
# load extra configs # load extra configs
if (not self._parser.has_section("platformio") for pattern in self.get("platformio", "extra_configs", []):
or not self._parser.has_option("platformio", "extra_configs")):
return
extra_configs = self.getlist("platformio", "extra_configs")
for pattern in extra_configs:
for item in glob.glob(pattern): for item in glob.glob(pattern):
self.read(item) self.read(item)
@@ -212,6 +117,14 @@ class ProjectConfig(object):
if option not in options: if option not in options:
options.append(option) 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 return options
def has_option(self, section, option): def has_option(self, section, option):
@@ -239,37 +152,64 @@ class ProjectConfig(object):
value = "\n" + value # start from a new line value = "\n" + value # start from a new line
self._parser.set(section, option, value) self._parser.set(section, option, value)
def get(self, section, option): def getraw(self, section, option):
if not self.expand_interpolations: if not self.expand_interpolations:
return self._parser.get(section, option) return self._parser.get(section, option)
try: try:
value = self._parser.get(section, option) 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) 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: if "${" not in value or "}" not in value:
return 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) section, option = match.group(1), match.group(2)
if section == "sysenv": if section == "sysenv":
return os.getenv(option) return os.getenv(option)
return self.get(section, option) return self.getraw(section, option)
def getlist(self, section, option): def get(self, section, option, default=None):
return self.parse_multi_values(self.get(section, option)) 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): def envs(self):
return [s[4:] for s in self._parser.sections() if s.startswith("env:")] return [s[4:] for s in self._parser.sections() if s.startswith("env:")]
def default_envs(self): def default_envs(self):
if not self._parser.has_option("platformio", "env_default"): return self.get("platformio", "env_default", [])
return []
return self.getlist("platformio", "env_default")
def validate(self, envs=None, validate_options=True): def validate(self, envs=None, validate_options=True):
if not isfile(self.path): if not isfile(self.path):
@@ -286,66 +226,54 @@ class ProjectConfig(object):
return self.validate_options() if validate_options else True return self.validate_options() if validate_options else True
def validate_options(self): def validate_options(self):
return (self._validate_platformio_options() # legacy `lib_extra_dirs` in [platformio]
and self._validate_env_options()) if (self._parser.has_section("platformio")
and self._parser.has_option("platformio", "lib_extra_dirs")):
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"):
if not self._parser.has_section("env"): if not self._parser.has_section("env"):
self._parser.add_section("env") self._parser.add_section("env")
self._parser.set("env", "lib_extra_dirs", self._parser.set("env", "lib_extra_dirs",
self._parser.get("platformio", "lib_extra_dirs")) self._parser.get("platformio", "lib_extra_dirs"))
self._parser.remove_option("platformio", "lib_extra_dirs") self._parser.remove_option("platformio", "lib_extra_dirs")
warnings.add( click.secho(
"`lib_extra_dirs` option is deprecated in section " "Warning! `lib_extra_dirs` option is deprecated in section "
"`platformio`! Please move it to global `env` section") "[platformio]! Please move it to global `env` section",
fg="yellow")
unknown = set(k for k, _ in self.items("platformio")) - set( return self._validate_unknown_options()
KNOWN_PLATFORMIO_OPTIONS)
if unknown:
warnings.add(
"Ignore unknown `%s` options in section `[platformio]`" %
", ".join(unknown))
for warning in warnings: def _validate_unknown_options(self):
click.secho("Warning! %s" % warning, fg="yellow")
return True
def _validate_env_options(self):
warnings = set() 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(): for section in self._parser.sections():
if section != "env" and not section.startswith("env:"):
continue
for option in self._parser.options(section): for option in self._parser.options(section):
# obsolete # obsolete
if option in RENAMED_OPTIONS: if option in renamed_options:
warnings.add( warnings.add(
"`%s` option in section `[%s]` is deprecated and will " "`%s` option in section `[%s]` is deprecated and will "
"be removed in the next release! Please use `%s` " "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 # 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.get(section, option))
self._parser.remove_option(section, option) self._parser.remove_option(section, option)
continue continue
# unknown # unknown
scope = section.split(":", 1)[0]
unknown_conditions = [ unknown_conditions = [
option not in KNOWN_ENV_OPTIONS, ("%s.%s" % (scope, option)) not in ProjectOptions,
not option.startswith("custom_"), scope != "env" or
not option.startswith("board_") not option.startswith(("custom_", "board_"))
] # yapf: disable ] # yapf: disable
if all(unknown_conditions): if all(unknown_conditions):
warnings.add( warnings.add("Ignore unknown option `%s` in section `[%s]`"
"Detected non-PlatformIO `%s` option in `[%s]` section" % (option, section))
% (option, section))
for warning in warnings: for warning in warnings:
click.secho("Warning! %s" % warning, fg="yellow") click.secho("Warning! %s" % warning, fg="yellow")

View File

@@ -15,7 +15,7 @@
import os import os
from hashlib import sha1 from hashlib import sha1
from os import walk 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) splitdrive)
from platformio import __version__ from platformio import __version__
@@ -44,37 +44,23 @@ def find_project_dir_above(path):
def get_project_optional_dir(name, default=None): 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 if not optional_dir:
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:
return default return default
items = [] if "$PROJECT_HASH" in optional_dir:
for item in paths.split(", "): optional_dir = optional_dir.replace(
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", "$PROJECT_HASH",
sha1(project_dir if PY2 else project_dir.encode()).hexdigest() sha1(project_dir if PY2 else project_dir.encode()).hexdigest()
[:10]) [:10])
return paths if optional_dir.startswith("~"):
optional_dir = expanduser(optional_dir)
return realpath(optional_dir)
def get_project_core_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): def test_ci_empty(clirunner):
result = clirunner.invoke(cmd_ci) result = clirunner.invoke(cmd_ci)
assert result.exit_code == 2 assert result.exit_code != 0
assert "Invalid value: Missing argument 'src'" in result.output assert "Invalid value: Missing argument 'src'" in result.output

View File

@@ -16,7 +16,7 @@ import json
from os import getcwd, makedirs from os import getcwd, makedirs
from os.path import getsize, isdir, isfile, join 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.boards import cli as cmd_boards
from platformio.commands.init import cli as cmd_init from platformio.commands.init import cli as cmd_init
from platformio.project.config import ProjectConfig 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 = ProjectConfig(join(getcwd(), "platformio.ini"))
config.validate() 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 config.has_section("env:uno")
assert not set(expected_result).symmetric_difference( assert config.items("env:uno") == expected_result
set(config.items("env:uno")))
def test_init_enable_auto_uploading(clirunner, validate_cliresult): 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()) validate_pioproject(getcwd())
config = ProjectConfig(join(getcwd(), "platformio.ini")) config = ProjectConfig(join(getcwd(), "platformio.ini"))
config.validate() config.validate()
expected_result = [("platform", "atmelavr"), ("framework", "arduino"), expected_result = [("targets", ["upload"]), ("platform", "atmelavr"),
("board", "uno"), ("targets", "upload")] ("board", "uno"), ("framework", ["arduino"])]
assert config.has_section("env:uno") assert config.has_section("env:uno")
assert not set(expected_result).symmetric_difference( assert config.items("env:uno") == expected_result
set(config.items("env:uno")))
def test_init_custom_framework(clirunner, validate_cliresult): def test_init_custom_framework(clirunner, validate_cliresult):
@@ -141,11 +139,10 @@ def test_init_custom_framework(clirunner, validate_cliresult):
validate_pioproject(getcwd()) validate_pioproject(getcwd())
config = ProjectConfig(join(getcwd(), "platformio.ini")) config = ProjectConfig(join(getcwd(), "platformio.ini"))
config.validate() config.validate()
expected_result = [("platform", "teensy"), ("framework", "mbed"), expected_result = [("platform", "teensy"), ("board", "teensy31"),
("board", "teensy31")] ("framework", ["mbed"])]
assert config.has_section("env:teensy31") assert config.has_section("env:teensy31")
assert not set(expected_result).symmetric_difference( assert config.items("env:teensy31") == expected_result
set(config.items("env:teensy31")))
def test_init_incorrect_board(clirunner): def test_init_incorrect_board(clirunner):

View File

@@ -14,7 +14,9 @@
import os import os
from platformio.project.config import ProjectConfig import pytest
from platformio.project.config import ConfigParser, ProjectConfig
BASE_CONFIG = """ BASE_CONFIG = """
[platformio] [platformio]
@@ -26,7 +28,9 @@ extra_configs =
# global options per [env:*] # global options per [env:*]
[env] [env]
monitor_speed = 115200 monitor_speed = 115200
lib_deps = Lib1, Lib2 lib_deps =
Lib1
Lib2
lib_ignore = ${custom.lib_ignore} lib_ignore = ${custom.lib_ignore}
[custom] [custom]
@@ -46,6 +50,7 @@ build_flags = ${custom.lib_flags} ${custom.debug_flags}
[env:extra_2] [env:extra_2]
build_flags = ${custom.debug_flags} ${custom.extra_flags} build_flags = ${custom.debug_flags} ${custom.extra_flags}
lib_ignore = ${env.lib_ignore}, Lib3 lib_ignore = ${env.lib_ignore}, Lib3
upload_port = /dev/extra_2/port
""" """
EXTRA_DEBUG_CONFIG = """ 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("platformio.ini").write(BASE_CONFIG)
tmpdir.join("extra_envs.ini").write(EXTRA_ENVS_CONFIG) tmpdir.join("extra_envs.ini").write(EXTRA_ENVS_CONFIG)
tmpdir.join("extra_debug.ini").write(EXTRA_DEBUG_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) config = ProjectConfig(tmpdir.join("platformio.ini").strpath)
assert config 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 # sections
assert config.sections() == [ assert config.sections() == [
"platformio", "env", "custom", "env:base", "env:extra_1", "env:extra_2" "platformio", "env", "custom", "env:base", "env:extra_1", "env:extra_2"
@@ -88,29 +103,75 @@ def test_parser(tmpdir):
# sysenv # sysenv
assert config.get("custom", "extra_flags") == "" 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" os.environ["__PIO_TEST_CNF_EXTRA_FLAGS"] = "-L /usr/local/lib"
assert config.get("custom", "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 # get
assert config.get("custom", "debug_flags") == "-D DEBUG=1" 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_1", "build_flags") == [
assert config.get("env:extra_2", "build_flags") == "-Og" "-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:extra_2", "monitor_speed") == "115200"
assert config.get("env:base", assert config.get("env:base", "build_flags") == ([
"build_flags") == ("-D DEBUG=1 -L /usr/local/lib") "-D DEBUG=1 -L /usr/local/lib", "-DSYSENVDEPS1 -DSYSENVDEPS2"
])
# items # items
assert config.items("custom") == [("debug_flags", "-D DEBUG=1"), assert config.items("custom") == [
("lib_flags", "-lc -lm"), ("debug_flags", "-D DEBUG=1"),
("extra_flags", "-L /usr/local/lib"), ("lib_flags", "-lc -lm"),
("lib_ignore", "LibIgnoreCustom")] ("extra_flags", "-L /usr/local/lib"),
assert config.items(env="extra_1") == [("build_flags", ("lib_ignore", "LibIgnoreCustom")
"-lc -lm -D DEBUG=1"), ] # yapf: disable
("monitor_speed", "115200"), assert config.items(env="extra_1") == [
("lib_deps", "Lib1, Lib2"), ("build_flags", ["-lc -lm -D DEBUG=1", "-DSYSENVDEPS1 -DSYSENVDEPS2"]),
("lib_ignore", "LibIgnoreCustom")] ("monitor_speed", "115200"),
assert config.items(env="extra_2") == [("build_flags", "-Og"), ("lib_deps", ["Lib1", "Lib2"]),
("lib_ignore", ("lib_ignore", ["LibIgnoreCustom"]),
"LibIgnoreCustom, Lib3"), ("upload_port", "/dev/sysenv/port")
("monitor_speed", "115200"), ] # yapf: disable
("lib_deps", "Lib1, Lib2")] 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"]