forked from platformio/platformio-core
Merge branch 'feature/refactor-project-options' into develop
This commit is contained in:
@ -21,7 +21,7 @@ matrix:
|
||||
install:
|
||||
- git submodule update --init --recursive
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then curl -fsSL https://bootstrap.pypa.io/get-pip.py | sudo python; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo pip install "tox==3.0.0"; else pip install -U tox; fi
|
||||
- pip install -U tox
|
||||
|
||||
# ChipKIT issue: install 32-bit support for GCC PIC32
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libc6-i386; fi
|
||||
|
15
.vscode/settings.json
vendored
15
.vscode/settings.json
vendored
@ -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"
|
||||
}
|
2
Makefile
2
Makefile
@ -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
|
||||
|
||||
|
2
examples
2
examples
Submodule examples updated: 45ec933e28...89963fed9e
@ -16,7 +16,7 @@ import base64
|
||||
import json
|
||||
import sys
|
||||
from os import environ
|
||||
from os.path import expanduser, join
|
||||
from os.path import join
|
||||
from time import time
|
||||
|
||||
from SCons.Script import ARGUMENTS # pylint: disable=import-error
|
||||
@ -33,76 +33,29 @@ from platformio import util
|
||||
from platformio.compat import PY2, path_to_unicode
|
||||
from platformio.proc import get_pythonexe_path
|
||||
from platformio.project import helpers as project_helpers
|
||||
from platformio.project.config import ProjectConfig
|
||||
|
||||
AllowSubstExceptions(NameError)
|
||||
|
||||
# allow common variables from INI file
|
||||
commonvars = Variables(None)
|
||||
commonvars.AddVariables(
|
||||
# append CLI arguments to build environment
|
||||
clivars = Variables(None)
|
||||
clivars.AddVariables(
|
||||
("PLATFORM_MANIFEST",),
|
||||
("BUILD_SCRIPT",),
|
||||
("EXTRA_SCRIPTS",),
|
||||
("PROJECT_CONFIG",),
|
||||
("PIOENV",),
|
||||
("PIOTEST",),
|
||||
("PIOPLATFORM",),
|
||||
("PIOFRAMEWORK",),
|
||||
|
||||
# build options
|
||||
("BUILD_FLAGS",),
|
||||
("SRC_BUILD_FLAGS",),
|
||||
("BUILD_UNFLAGS",),
|
||||
("SRC_FILTER",),
|
||||
|
||||
# library options
|
||||
("LIB_LDF_MODE",),
|
||||
("LIB_COMPAT_MODE",),
|
||||
("LIB_DEPS",),
|
||||
("LIB_IGNORE",),
|
||||
("LIB_EXTRA_DIRS",),
|
||||
("LIB_ARCHIVE",),
|
||||
|
||||
# board options
|
||||
("BOARD",),
|
||||
# deprecated options, use board_{object.path} instead
|
||||
("BOARD_MCU",),
|
||||
("BOARD_F_CPU",),
|
||||
("BOARD_F_FLASH",),
|
||||
("BOARD_FLASH_MODE",),
|
||||
# end of deprecated options
|
||||
|
||||
# upload options
|
||||
("UPLOAD_PORT",),
|
||||
("UPLOAD_PROTOCOL",),
|
||||
("UPLOAD_SPEED",),
|
||||
("UPLOAD_FLAGS",),
|
||||
("UPLOAD_RESETMETHOD",),
|
||||
|
||||
# test options
|
||||
("TEST_BUILD_PROJECT_SRC",),
|
||||
|
||||
# debug options
|
||||
("DEBUG_TOOL",),
|
||||
("DEBUG_SVD_PATH",),
|
||||
|
||||
("UPLOAD_PORT",)
|
||||
) # yapf: disable
|
||||
|
||||
MULTILINE_VARS = [
|
||||
"EXTRA_SCRIPTS", "PIOFRAMEWORK", "BUILD_FLAGS", "SRC_BUILD_FLAGS",
|
||||
"BUILD_UNFLAGS", "UPLOAD_FLAGS", "SRC_FILTER", "LIB_DEPS", "LIB_IGNORE",
|
||||
"LIB_EXTRA_DIRS"
|
||||
]
|
||||
|
||||
DEFAULT_ENV_OPTIONS = dict(
|
||||
tools=[
|
||||
"ar", "gas", "gcc", "g++", "gnulink", "platformio", "pioplatform",
|
||||
"piowinhooks", "piolib", "pioupload", "piomisc", "pioide"
|
||||
], # yapf: disable
|
||||
"pioproject", "piowinhooks", "piolib", "pioupload", "piomisc", "pioide"
|
||||
],
|
||||
toolpath=[join(util.get_source_dir(), "builder", "tools")],
|
||||
variables=commonvars,
|
||||
variables=clivars,
|
||||
|
||||
# Propagating External Environment
|
||||
PIOVARIABLES=list(commonvars.keys()),
|
||||
ENV=environ,
|
||||
UNIX_TIME=int(time()),
|
||||
PROJECT_DIR=project_helpers.get_project_dir(),
|
||||
@ -136,38 +89,22 @@ if not int(ARGUMENTS.get("PIOVERBOSE", 0)):
|
||||
|
||||
env = DefaultEnvironment(**DEFAULT_ENV_OPTIONS)
|
||||
|
||||
# decode common variables
|
||||
for k in list(commonvars.keys()):
|
||||
if k in env:
|
||||
env[k] = base64.b64decode(env[k])
|
||||
if isinstance(env[k], bytes):
|
||||
env[k] = env[k].decode()
|
||||
if k in MULTILINE_VARS:
|
||||
env[k] = ProjectConfig.parse_multi_values(env[k])
|
||||
|
||||
if env.GetOption('clean'):
|
||||
env.PioClean(env.subst("$BUILD_DIR"))
|
||||
env.Exit(0)
|
||||
elif not int(ARGUMENTS.get("PIOVERBOSE", 0)):
|
||||
print("Verbose mode can be enabled via `-v, --verbose` option")
|
||||
|
||||
# Handle custom variables from system environment
|
||||
for var in ("BUILD_FLAGS", "SRC_BUILD_FLAGS", "SRC_FILTER", "EXTRA_SCRIPTS",
|
||||
"UPLOAD_PORT", "UPLOAD_FLAGS", "LIB_EXTRA_DIRS"):
|
||||
k = "PLATFORMIO_%s" % var
|
||||
if k not in environ:
|
||||
continue
|
||||
if var in ("UPLOAD_PORT", ):
|
||||
env[var] = environ.get(k)
|
||||
continue
|
||||
env.Append(**{var: ProjectConfig.parse_multi_values(environ.get(k))})
|
||||
# Load variables from CLI
|
||||
for key in list(clivars.keys()):
|
||||
if key in env:
|
||||
env[key] = base64.b64decode(env[key])
|
||||
if isinstance(env[key], bytes):
|
||||
env[key] = env[key].decode()
|
||||
|
||||
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']
|
||||
]
|
||||
|
||||
env.LoadPioPlatform(commonvars)
|
||||
env.GetProjectConfig().validate([env['PIOENV']], silent=True)
|
||||
env.LoadProjectOptions()
|
||||
env.LoadPioPlatform()
|
||||
|
||||
env.SConscriptChdir(0)
|
||||
env.SConsignFile(
|
||||
|
@ -113,7 +113,7 @@ def _dump_defines(env):
|
||||
|
||||
|
||||
def _get_svd_path(env):
|
||||
svd_path = env.subst("$DEBUG_SVD_PATH")
|
||||
svd_path = env.GetProjectOption("debug_svd_path")
|
||||
if svd_path:
|
||||
return abspath(svd_path)
|
||||
|
||||
@ -139,8 +139,7 @@ def DumpIDEData(env, projenv):
|
||||
LINTCXXCOM = "$CXXFLAGS $CCFLAGS $CPPFLAGS"
|
||||
|
||||
data = {
|
||||
"libsource_dirs":
|
||||
[env.subst(l) for l in env.get("LIBSOURCE_DIRS", [])],
|
||||
"libsource_dirs": [env.subst(l) for l in env.GetLibSourceDirs()],
|
||||
"defines":
|
||||
_dump_defines(env),
|
||||
"includes":
|
||||
|
@ -23,8 +23,8 @@ import os
|
||||
import re
|
||||
import sys
|
||||
from glob import glob
|
||||
from os.path import (basename, commonprefix, dirname, isdir, isfile, join,
|
||||
realpath, sep)
|
||||
from os.path import (basename, commonprefix, dirname, expanduser, isdir,
|
||||
isfile, join, realpath, sep)
|
||||
|
||||
import SCons.Scanner # pylint: disable=import-error
|
||||
from SCons.Script import ARGUMENTS # pylint: disable=import-error
|
||||
@ -207,17 +207,18 @@ class LibBuilderBase(object):
|
||||
|
||||
@property
|
||||
def lib_archive(self):
|
||||
return self.env.get("LIB_ARCHIVE", "") != "false"
|
||||
return self.env.GetProjectOption("lib_archive", True)
|
||||
|
||||
@property
|
||||
def lib_ldf_mode(self):
|
||||
return self.validate_ldf_mode(
|
||||
self.env.get("LIB_LDF_MODE", self.LDF_MODE_DEFAULT))
|
||||
self.env.GetProjectOption("lib_ldf_mode", self.LDF_MODE_DEFAULT))
|
||||
|
||||
@property
|
||||
def lib_compat_mode(self):
|
||||
return self.validate_compat_mode(
|
||||
self.env.get("LIB_COMPAT_MODE", self.COMPAT_MODE_DEFAULT))
|
||||
self.env.GetProjectOption("lib_compat_mode",
|
||||
self.COMPAT_MODE_DEFAULT))
|
||||
|
||||
@property
|
||||
def depbuilders(self):
|
||||
@ -867,7 +868,7 @@ class ProjectAsLibBuilder(LibBuilderBase):
|
||||
pass
|
||||
|
||||
def process_dependencies(self): # pylint: disable=too-many-branches
|
||||
uris = self.env.get("LIB_DEPS", [])
|
||||
uris = self.env.GetProjectOption("lib_deps", [])
|
||||
if not uris:
|
||||
return
|
||||
storage_dirs = []
|
||||
@ -907,6 +908,14 @@ class ProjectAsLibBuilder(LibBuilderBase):
|
||||
return result
|
||||
|
||||
|
||||
def GetLibSourceDirs(env):
|
||||
items = env.GetProjectOption("lib_extra_dirs", [])
|
||||
items.extend(env['LIBSOURCE_DIRS'])
|
||||
return [
|
||||
expanduser(item) if item.startswith("~") else item for item in items
|
||||
]
|
||||
|
||||
|
||||
def GetLibBuilders(env): # pylint: disable=too-many-branches
|
||||
|
||||
if "__PIO_LIB_BUILDERS" in DefaultEnvironment():
|
||||
@ -920,7 +929,7 @@ def GetLibBuilders(env): # pylint: disable=too-many-branches
|
||||
|
||||
def _check_lib_builder(lb):
|
||||
compat_mode = lb.lib_compat_mode
|
||||
if lb.name in env.get("LIB_IGNORE", []):
|
||||
if lb.name in env.GetProjectOption("lib_ignore", []):
|
||||
if verbose:
|
||||
sys.stderr.write("Ignored library %s\n" % lb.path)
|
||||
return None
|
||||
@ -939,7 +948,7 @@ def GetLibBuilders(env): # pylint: disable=too-many-branches
|
||||
return True
|
||||
|
||||
found_incompat = False
|
||||
for libs_dir in env['LIBSOURCE_DIRS']:
|
||||
for libs_dir in env.GetLibSourceDirs():
|
||||
libs_dir = env.subst(libs_dir)
|
||||
if not isdir(libs_dir):
|
||||
continue
|
||||
@ -1038,6 +1047,7 @@ def exists(_):
|
||||
|
||||
|
||||
def generate(env):
|
||||
env.AddMethod(GetLibSourceDirs)
|
||||
env.AddMethod(GetLibBuilders)
|
||||
env.AddMethod(ConfigureProjectLibBuilder)
|
||||
return env
|
||||
|
@ -322,7 +322,7 @@ def ProcessTest(env):
|
||||
|
||||
def GetExtraScripts(env, scope):
|
||||
items = []
|
||||
for item in env.get("EXTRA_SCRIPTS", []):
|
||||
for item in env.GetProjectOption("extra_scripts", []):
|
||||
if scope == "post" and ":" not in item:
|
||||
items.append(item)
|
||||
elif item.startswith("%s:" % scope):
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import base64
|
||||
import sys
|
||||
from os.path import isdir, isfile, join
|
||||
|
||||
@ -23,6 +22,7 @@ from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error
|
||||
from platformio import exception, util
|
||||
from platformio.compat import WINDOWS
|
||||
from platformio.managers.platform import PlatformFactory
|
||||
from platformio.project.config import ProjectOptions
|
||||
|
||||
# pylint: disable=too-many-branches, too-many-locals
|
||||
|
||||
@ -33,10 +33,10 @@ def initPioPlatform(name):
|
||||
|
||||
|
||||
def PioPlatform(env):
|
||||
variables = {}
|
||||
for name in env['PIOVARIABLES']:
|
||||
if name in env:
|
||||
variables[name.lower()] = env[name]
|
||||
variables = env.GetProjectOptions(as_dict=True)
|
||||
if "framework" in variables:
|
||||
# support PIO Core 3.0 dev/platforms
|
||||
variables['pioframework'] = variables['framework']
|
||||
p = initPioPlatform(env['PLATFORM_MANIFEST'])
|
||||
p.configure_default_packages(variables, COMMAND_LINE_TARGETS)
|
||||
return p
|
||||
@ -63,7 +63,7 @@ def GetFrameworkScript(env, framework):
|
||||
return script_path
|
||||
|
||||
|
||||
def LoadPioPlatform(env, variables):
|
||||
def LoadPioPlatform(env):
|
||||
p = env.PioPlatform()
|
||||
installed_packages = p.get_installed_packages()
|
||||
|
||||
@ -92,36 +92,25 @@ def LoadPioPlatform(env, variables):
|
||||
env.Prepend(LIBPATH=[join(p.get_dir(), "ldscripts")])
|
||||
|
||||
if "BOARD" not in env:
|
||||
# handle _MCU and _F_CPU variables for AVR native
|
||||
for key, value in variables.UnknownVariables().items():
|
||||
if not key.startswith("BOARD_"):
|
||||
continue
|
||||
value = base64.b64decode(value)
|
||||
if isinstance(value, bytes):
|
||||
value = value.decode()
|
||||
env.Replace(**{key.upper().replace("BUILD.", ""): value})
|
||||
return
|
||||
|
||||
# update board manifest with a custom data
|
||||
# update board manifest with overridden data from INI config
|
||||
board_config = env.BoardConfig()
|
||||
for key, value in variables.UnknownVariables().items():
|
||||
if not key.startswith("BOARD_"):
|
||||
continue
|
||||
value = base64.b64decode(value)
|
||||
if isinstance(value, bytes):
|
||||
value = value.decode()
|
||||
board_config.update(key.lower()[6:], value)
|
||||
for option, value in env.GetProjectOptions():
|
||||
if option.startswith("board_"):
|
||||
board_config.update(option.lower()[6:], value)
|
||||
|
||||
# update default environment variables
|
||||
for key in list(variables.keys()):
|
||||
if key in env or \
|
||||
not any([key.startswith("BOARD_"), key.startswith("UPLOAD_")]):
|
||||
# load default variables from board config
|
||||
for option_meta in ProjectOptions.values():
|
||||
if not option_meta.buildenvvar or option_meta.buildenvvar in env:
|
||||
continue
|
||||
_opt, _val = key.lower().split("_", 1)
|
||||
if _opt == "board":
|
||||
_opt = "build"
|
||||
if _val in board_config.get(_opt):
|
||||
env.Replace(**{key: board_config.get("%s.%s" % (_opt, _val))})
|
||||
data_path = (option_meta.name[6:]
|
||||
if option_meta.name.startswith("board_") else
|
||||
option_meta.name.replace("_", "."))
|
||||
try:
|
||||
env[option_meta.buildenvvar] = board_config.get(data_path)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if "build.ldscript" in board_config:
|
||||
env.Replace(LDSCRIPT_PATH=board_config.get("build.ldscript"))
|
||||
@ -165,7 +154,7 @@ def PrintConfiguration(env):
|
||||
|
||||
data = [
|
||||
"CURRENT(%s)" % board_config.get_debug_tool_name(
|
||||
env.subst("$DEBUG_TOOL"))
|
||||
env.GetProjectOption("debug_tool"))
|
||||
]
|
||||
onboard = []
|
||||
external = []
|
||||
|
49
platformio/builder/tools/pioproject.py
Normal file
49
platformio/builder/tools/pioproject.py
Normal file
@ -0,0 +1,49 @@
|
||||
# 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 __future__ import absolute_import
|
||||
|
||||
from platformio.project.config import ProjectConfig, ProjectOptions
|
||||
|
||||
|
||||
def GetProjectConfig(env):
|
||||
return ProjectConfig.get_instance(env['PROJECT_CONFIG'])
|
||||
|
||||
|
||||
def GetProjectOptions(env, as_dict=False):
|
||||
return env.GetProjectConfig().items(env=env['PIOENV'], as_dict=as_dict)
|
||||
|
||||
|
||||
def GetProjectOption(env, option, default=None):
|
||||
return env.GetProjectConfig().get("env:" + env['PIOENV'], option, default)
|
||||
|
||||
|
||||
def LoadProjectOptions(env):
|
||||
for option, value in env.GetProjectOptions():
|
||||
option_meta = ProjectOptions.get("env." + option)
|
||||
if not option_meta or not option_meta.buildenvvar:
|
||||
continue
|
||||
env[option_meta.buildenvvar] = value
|
||||
|
||||
|
||||
def exists(_):
|
||||
return True
|
||||
|
||||
|
||||
def generate(env):
|
||||
env.AddMethod(GetProjectConfig)
|
||||
env.AddMethod(GetProjectOptions)
|
||||
env.AddMethod(GetProjectOption)
|
||||
env.AddMethod(LoadProjectOptions)
|
||||
return env
|
@ -163,22 +163,18 @@ 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 = []
|
||||
env_options = {}
|
||||
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 +183,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:
|
||||
|
@ -41,13 +41,11 @@ class ProjectRPC(object):
|
||||
def _get_project_data(project_dir):
|
||||
data = {"boards": [], "envLibdepsDirs": [], "libExtraDirs": []}
|
||||
config = ProjectConfig(join(project_dir, "platformio.ini"))
|
||||
config.validate(validate_options=False)
|
||||
config.validate(silent=True)
|
||||
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"):
|
||||
@ -232,11 +229,9 @@ class ProjectRPC(object):
|
||||
project_description = None
|
||||
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")
|
||||
config.validate(silent=True)
|
||||
project_description = config.get("platformio",
|
||||
"description")
|
||||
except exception.PlatformIOProjectException:
|
||||
continue
|
||||
|
||||
|
@ -70,7 +70,6 @@ def cli(
|
||||
project_option,
|
||||
env_prefix,
|
||||
silent):
|
||||
|
||||
if not silent:
|
||||
if project_dir == getcwd():
|
||||
click.secho(
|
||||
|
@ -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
|
||||
|
@ -1,352 +0,0 @@
|
||||
# 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 os import getcwd, makedirs
|
||||
from os.path import getmtime, isdir, isfile, join
|
||||
from time import time
|
||||
|
||||
import click
|
||||
|
||||
from platformio import exception, telemetry, util
|
||||
from platformio.commands.device import device_monitor as cmd_device_monitor
|
||||
from platformio.commands.lib import (CTX_META_STORAGE_DIRS_KEY,
|
||||
CTX_META_STORAGE_LIBDEPS_KEY)
|
||||
from platformio.commands.lib import lib_install as cmd_lib_install
|
||||
from platformio.commands.platform import \
|
||||
platform_install as cmd_platform_install
|
||||
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_build_dir,
|
||||
get_project_dir, get_project_libdeps_dir)
|
||||
|
||||
# pylint: disable=too-many-arguments,too-many-locals,too-many-branches
|
||||
|
||||
|
||||
@click.command("run", short_help="Process project environments")
|
||||
@click.option("-e", "--environment", multiple=True)
|
||||
@click.option("-t", "--target", multiple=True)
|
||||
@click.option("--upload-port")
|
||||
@click.option(
|
||||
"-d",
|
||||
"--project-dir",
|
||||
default=getcwd,
|
||||
type=click.Path(
|
||||
exists=True,
|
||||
file_okay=True,
|
||||
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, 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)
|
||||
|
||||
with util.cd(project_dir):
|
||||
# clean obsolete build dir
|
||||
if not disable_auto_clean:
|
||||
try:
|
||||
_clean_build_dir(get_project_build_dir())
|
||||
except: # pylint: disable=bare-except
|
||||
click.secho(
|
||||
"Can not remove temporary directory `%s`. Please remove "
|
||||
"it manually to avoid build issues" %
|
||||
get_project_build_dir(force=True),
|
||||
fg="yellow")
|
||||
|
||||
config = ProjectConfig.get_instance(
|
||||
project_conf or join(project_dir, "platformio.ini"))
|
||||
config.validate(environment)
|
||||
|
||||
_handle_legacy_libdeps(project_dir, config)
|
||||
|
||||
results = []
|
||||
start_time = time()
|
||||
default_envs = config.default_envs()
|
||||
for envname in config.envs():
|
||||
skipenv = any([
|
||||
environment and envname not in environment, not environment
|
||||
and default_envs and envname not in default_envs
|
||||
])
|
||||
if skipenv:
|
||||
results.append((envname, None))
|
||||
continue
|
||||
|
||||
if not silent and any(
|
||||
status is not None for (_, status) in results):
|
||||
click.echo()
|
||||
|
||||
options = config.items(env=envname, as_dict=True)
|
||||
if "piotest" not in options and "piotest" in ctx.meta:
|
||||
options['piotest'] = ctx.meta['piotest']
|
||||
|
||||
ep = EnvironmentProcessor(ctx, envname, options, target,
|
||||
upload_port, silent, verbose)
|
||||
result = (envname, ep.process())
|
||||
results.append(result)
|
||||
if result[1] and "monitor" in ep.get_build_targets() and \
|
||||
"nobuild" not in ep.get_build_targets():
|
||||
ctx.invoke(
|
||||
cmd_device_monitor,
|
||||
environment=environment[0] if environment else None)
|
||||
|
||||
found_error = any(status is False for (_, status) in results)
|
||||
|
||||
if (found_error or not silent) and len(results) > 1:
|
||||
click.echo()
|
||||
print_summary(results, start_time)
|
||||
|
||||
if found_error:
|
||||
raise exception.ReturnErrorCode(1)
|
||||
return True
|
||||
|
||||
|
||||
class EnvironmentProcessor(object):
|
||||
|
||||
DEFAULT_DUMP_OPTIONS = ("platform", "framework", "board")
|
||||
|
||||
IGNORE_BUILD_OPTIONS = [
|
||||
"test_transport", "test_filter", "test_ignore", "test_port",
|
||||
"test_speed", "debug_port", "debug_init_cmds", "debug_extra_cmds",
|
||||
"debug_server", "debug_init_break", "debug_load_cmd",
|
||||
"debug_load_mode", "monitor_port", "monitor_speed", "monitor_rts",
|
||||
"monitor_dtr"
|
||||
]
|
||||
|
||||
REMAPED_OPTIONS = {"framework": "pioframework", "platform": "pioplatform"}
|
||||
|
||||
def __init__(
|
||||
self, # pylint: disable=R0913
|
||||
cmd_ctx,
|
||||
name,
|
||||
options,
|
||||
targets,
|
||||
upload_port,
|
||||
silent,
|
||||
verbose):
|
||||
self.cmd_ctx = cmd_ctx
|
||||
self.name = name
|
||||
self.options = options
|
||||
self.targets = targets
|
||||
self.upload_port = upload_port
|
||||
self.silent = silent
|
||||
self.verbose = verbose
|
||||
|
||||
def process(self):
|
||||
terminal_width, _ = click.get_terminal_size()
|
||||
start_time = time()
|
||||
env_dump = []
|
||||
|
||||
for k, v in self.options.items():
|
||||
self.options[k] = self.options[k].strip()
|
||||
if self.verbose or k in self.DEFAULT_DUMP_OPTIONS:
|
||||
env_dump.append("%s: %s" % (k, ", ".join(
|
||||
ProjectConfig.parse_multi_values(v))))
|
||||
|
||||
if not self.silent:
|
||||
click.echo("Processing %s (%s)" % (click.style(
|
||||
self.name, fg="cyan", bold=True), "; ".join(env_dump)))
|
||||
click.secho("-" * terminal_width, bold=True)
|
||||
|
||||
result = self._run()
|
||||
is_error = result['returncode'] != 0
|
||||
|
||||
if self.silent and not is_error:
|
||||
return True
|
||||
|
||||
if is_error or "piotest_processor" not in self.cmd_ctx.meta:
|
||||
print_header(
|
||||
"[%s] Took %.2f seconds" % (
|
||||
(click.style("ERROR", fg="red", bold=True) if is_error else
|
||||
click.style("SUCCESS", fg="green", bold=True)),
|
||||
time() - start_time),
|
||||
is_error=is_error)
|
||||
|
||||
return not is_error
|
||||
|
||||
def get_build_variables(self):
|
||||
variables = {"pioenv": self.name}
|
||||
if self.upload_port:
|
||||
variables['upload_port'] = self.upload_port
|
||||
for k, v in self.options.items():
|
||||
if k in self.REMAPED_OPTIONS:
|
||||
k = self.REMAPED_OPTIONS[k]
|
||||
if k in self.IGNORE_BUILD_OPTIONS:
|
||||
continue
|
||||
if k == "targets" or (k == "upload_port" and self.upload_port):
|
||||
continue
|
||||
variables[k] = v
|
||||
return variables
|
||||
|
||||
def get_build_targets(self):
|
||||
targets = []
|
||||
if self.targets:
|
||||
targets = [t for t in self.targets]
|
||||
elif "targets" in self.options:
|
||||
targets = self.options['targets'].split(", ")
|
||||
return targets
|
||||
|
||||
def _run(self):
|
||||
if "platform" not in self.options:
|
||||
raise exception.UndefinedEnvPlatform(self.name)
|
||||
|
||||
build_vars = self.get_build_variables()
|
||||
build_targets = self.get_build_targets()
|
||||
|
||||
telemetry.on_run_environment(self.options, build_targets)
|
||||
|
||||
# skip monitor target, we call it above
|
||||
if "monitor" in build_targets:
|
||||
build_targets.remove("monitor")
|
||||
if "nobuild" not in build_targets:
|
||||
# install dependent libraries
|
||||
if "lib_install" in self.options:
|
||||
_autoinstall_libdeps(self.cmd_ctx, self.name, [
|
||||
int(d.strip())
|
||||
for d in self.options['lib_install'].split(",")
|
||||
if d.strip()
|
||||
], self.verbose)
|
||||
if "lib_deps" in self.options:
|
||||
_autoinstall_libdeps(
|
||||
self.cmd_ctx, self.name,
|
||||
ProjectConfig.parse_multi_values(self.options['lib_deps']),
|
||||
self.verbose)
|
||||
|
||||
try:
|
||||
p = PlatformFactory.newPlatform(self.options['platform'])
|
||||
except exception.UnknownPlatform:
|
||||
self.cmd_ctx.invoke(
|
||||
cmd_platform_install,
|
||||
platforms=[self.options['platform']],
|
||||
skip_default_package=True)
|
||||
p = PlatformFactory.newPlatform(self.options['platform'])
|
||||
|
||||
return p.run(build_vars, build_targets, self.silent, self.verbose)
|
||||
|
||||
|
||||
def _handle_legacy_libdeps(project_dir, config):
|
||||
legacy_libdeps_dir = join(project_dir, ".piolibdeps")
|
||||
if (not isdir(legacy_libdeps_dir)
|
||||
or legacy_libdeps_dir == get_project_libdeps_dir()):
|
||||
return
|
||||
if not config.has_section("env"):
|
||||
config.add_section("env")
|
||||
lib_extra_dirs = []
|
||||
if config.has_option("env", "lib_extra_dirs"):
|
||||
lib_extra_dirs = config.getlist("env", "lib_extra_dirs")
|
||||
lib_extra_dirs.append(legacy_libdeps_dir)
|
||||
config.set("env", "lib_extra_dirs", lib_extra_dirs)
|
||||
click.secho(
|
||||
"DEPRECATED! A legacy library storage `{0}` has been found in a "
|
||||
"project. \nPlease declare project dependencies in `platformio.ini`"
|
||||
" file using `lib_deps` option and remove `{0}` folder."
|
||||
"\nMore details -> http://docs.platformio.org/page/projectconf/"
|
||||
"section_env_library.html#lib-deps".format(legacy_libdeps_dir),
|
||||
fg="yellow")
|
||||
|
||||
|
||||
def _autoinstall_libdeps(ctx, envname, libraries, verbose=False):
|
||||
if not libraries:
|
||||
return
|
||||
libdeps_dir = join(get_project_libdeps_dir(), envname)
|
||||
ctx.meta.update({
|
||||
CTX_META_STORAGE_DIRS_KEY: [libdeps_dir],
|
||||
CTX_META_STORAGE_LIBDEPS_KEY: {
|
||||
libdeps_dir: libraries
|
||||
}
|
||||
})
|
||||
try:
|
||||
ctx.invoke(cmd_lib_install, silent=not verbose)
|
||||
except exception.InternetIsOffline as e:
|
||||
click.secho(str(e), fg="yellow")
|
||||
|
||||
|
||||
def _clean_build_dir(build_dir):
|
||||
# remove legacy ".pioenvs" folder
|
||||
legacy_build_dir = join(get_project_dir(), ".pioenvs")
|
||||
if isdir(legacy_build_dir) and legacy_build_dir != build_dir:
|
||||
util.rmtree_(legacy_build_dir)
|
||||
|
||||
structhash_file = join(build_dir, "structure.hash")
|
||||
proj_hash = calculate_project_hash()
|
||||
|
||||
# if project's config is modified
|
||||
if (isdir(build_dir) and getmtime(
|
||||
join(get_project_dir(), "platformio.ini")) > getmtime(build_dir)):
|
||||
util.rmtree_(build_dir)
|
||||
|
||||
# check project structure
|
||||
if isdir(build_dir) and isfile(structhash_file):
|
||||
with open(structhash_file) as f:
|
||||
if f.read() == proj_hash:
|
||||
return
|
||||
util.rmtree_(build_dir)
|
||||
|
||||
if not isdir(build_dir):
|
||||
makedirs(build_dir)
|
||||
|
||||
with open(structhash_file, "w") as f:
|
||||
f.write(proj_hash)
|
||||
|
||||
|
||||
def print_header(label, is_error=False, fg=None):
|
||||
terminal_width, _ = click.get_terminal_size()
|
||||
width = len(click.unstyle(label))
|
||||
half_line = "=" * int((terminal_width - width - 2) / 2)
|
||||
click.secho(
|
||||
"%s %s %s" % (half_line, label, half_line), fg=fg, err=is_error)
|
||||
|
||||
|
||||
def print_summary(results, start_time):
|
||||
print_header("[%s]" % click.style("SUMMARY"))
|
||||
|
||||
envname_max_len = 0
|
||||
for (envname, _) in results:
|
||||
if len(envname) > envname_max_len:
|
||||
envname_max_len = len(envname)
|
||||
|
||||
successed = True
|
||||
for (envname, status) in results:
|
||||
status_str = click.style("SUCCESS", fg="green")
|
||||
if status is False:
|
||||
successed = False
|
||||
status_str = click.style("ERROR", fg="red")
|
||||
elif status is None:
|
||||
status_str = click.style("SKIP", fg="yellow")
|
||||
|
||||
format_str = (
|
||||
"Environment {0:<" + str(envname_max_len + 9) + "}\t[{1}]")
|
||||
click.echo(
|
||||
format_str.format(click.style(envname, fg="cyan"), status_str),
|
||||
err=status is False)
|
||||
|
||||
print_header(
|
||||
"[%s] Took %.2f seconds" % (
|
||||
(click.style("SUCCESS", fg="green", bold=True) if successed else
|
||||
click.style("ERROR", fg="red", bold=True)), time() - start_time),
|
||||
is_error=not successed)
|
16
platformio/commands/run/__init__.py
Normal file
16
platformio/commands/run/__init__.py
Normal file
@ -0,0 +1,16 @@
|
||||
# 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.commands.run.command import cli
|
||||
from platformio.commands.run.helpers import print_header
|
119
platformio/commands/run/command.py
Normal file
119
platformio/commands/run/command.py
Normal file
@ -0,0 +1,119 @@
|
||||
# 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 os import getcwd
|
||||
from os.path import isfile, join
|
||||
from time import time
|
||||
|
||||
import click
|
||||
|
||||
from platformio import exception, util
|
||||
from platformio.commands.device import device_monitor as cmd_device_monitor
|
||||
from platformio.commands.run.helpers import (
|
||||
_clean_build_dir, _handle_legacy_libdeps, print_summary)
|
||||
from platformio.commands.run.processor import EnvironmentProcessor
|
||||
from platformio.project.config import ProjectConfig
|
||||
from platformio.project.helpers import (find_project_dir_above,
|
||||
get_project_build_dir)
|
||||
|
||||
# pylint: disable=too-many-arguments,too-many-locals,too-many-branches
|
||||
|
||||
|
||||
@click.command("run", short_help="Process project environments")
|
||||
@click.option("-e", "--environment", multiple=True)
|
||||
@click.option("-t", "--target", multiple=True)
|
||||
@click.option("--upload-port")
|
||||
@click.option(
|
||||
"-d",
|
||||
"--project-dir",
|
||||
default=getcwd,
|
||||
type=click.Path(
|
||||
exists=True,
|
||||
file_okay=True,
|
||||
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, 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)
|
||||
|
||||
with util.cd(project_dir):
|
||||
# clean obsolete build dir
|
||||
if not disable_auto_clean:
|
||||
try:
|
||||
_clean_build_dir(get_project_build_dir())
|
||||
except: # pylint: disable=bare-except
|
||||
click.secho(
|
||||
"Can not remove temporary directory `%s`. Please remove "
|
||||
"it manually to avoid build issues" %
|
||||
get_project_build_dir(force=True),
|
||||
fg="yellow")
|
||||
|
||||
config = ProjectConfig.get_instance(
|
||||
project_conf or join(project_dir, "platformio.ini"))
|
||||
config.validate(environment)
|
||||
|
||||
_handle_legacy_libdeps(project_dir, config)
|
||||
|
||||
results = []
|
||||
start_time = time()
|
||||
default_envs = config.default_envs()
|
||||
for envname in config.envs():
|
||||
skipenv = any([
|
||||
environment and envname not in environment, not environment
|
||||
and default_envs and envname not in default_envs
|
||||
])
|
||||
if skipenv:
|
||||
results.append((envname, None))
|
||||
continue
|
||||
|
||||
if not silent and any(
|
||||
status is not None for (_, status) in results):
|
||||
click.echo()
|
||||
|
||||
ep = EnvironmentProcessor(ctx, envname, config, target,
|
||||
upload_port, silent, verbose)
|
||||
result = (envname, ep.process())
|
||||
results.append(result)
|
||||
|
||||
if result[1] and "monitor" in ep.get_build_targets() and \
|
||||
"nobuild" not in ep.get_build_targets():
|
||||
ctx.invoke(
|
||||
cmd_device_monitor,
|
||||
environment=environment[0] if environment else None)
|
||||
|
||||
found_error = any(status is False for (_, status) in results)
|
||||
|
||||
if (found_error or not silent) and len(results) > 1:
|
||||
click.echo()
|
||||
print_summary(results, start_time)
|
||||
|
||||
if found_error:
|
||||
raise exception.ReturnErrorCode(1)
|
||||
return True
|
127
platformio/commands/run/helpers.py
Normal file
127
platformio/commands/run/helpers.py
Normal file
@ -0,0 +1,127 @@
|
||||
# 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 os import makedirs
|
||||
from os.path import getmtime, isdir, isfile, join
|
||||
from time import time
|
||||
|
||||
import click
|
||||
|
||||
from platformio import exception, util
|
||||
from platformio.commands.lib import (CTX_META_STORAGE_DIRS_KEY,
|
||||
CTX_META_STORAGE_LIBDEPS_KEY)
|
||||
from platformio.commands.lib import lib_install as cmd_lib_install
|
||||
from platformio.project.helpers import (
|
||||
calculate_project_hash, get_project_dir, get_project_libdeps_dir)
|
||||
|
||||
|
||||
def _handle_legacy_libdeps(project_dir, config):
|
||||
legacy_libdeps_dir = join(project_dir, ".piolibdeps")
|
||||
if (not isdir(legacy_libdeps_dir)
|
||||
or legacy_libdeps_dir == get_project_libdeps_dir()):
|
||||
return
|
||||
if not config.has_section("env"):
|
||||
config.add_section("env")
|
||||
lib_extra_dirs = config.get("env", "lib_extra_dirs", [])
|
||||
lib_extra_dirs.append(legacy_libdeps_dir)
|
||||
config.set("env", "lib_extra_dirs", lib_extra_dirs)
|
||||
click.secho(
|
||||
"DEPRECATED! A legacy library storage `{0}` has been found in a "
|
||||
"project. \nPlease declare project dependencies in `platformio.ini`"
|
||||
" file using `lib_deps` option and remove `{0}` folder."
|
||||
"\nMore details -> http://docs.platformio.org/page/projectconf/"
|
||||
"section_env_library.html#lib-deps".format(legacy_libdeps_dir),
|
||||
fg="yellow")
|
||||
|
||||
|
||||
def _autoinstall_libdeps(ctx, envname, libraries, verbose=False):
|
||||
if not libraries:
|
||||
return
|
||||
libdeps_dir = join(get_project_libdeps_dir(), envname)
|
||||
ctx.meta.update({
|
||||
CTX_META_STORAGE_DIRS_KEY: [libdeps_dir],
|
||||
CTX_META_STORAGE_LIBDEPS_KEY: {
|
||||
libdeps_dir: libraries
|
||||
}
|
||||
})
|
||||
try:
|
||||
ctx.invoke(cmd_lib_install, silent=not verbose)
|
||||
except exception.InternetIsOffline as e:
|
||||
click.secho(str(e), fg="yellow")
|
||||
|
||||
|
||||
def _clean_build_dir(build_dir):
|
||||
# remove legacy ".pioenvs" folder
|
||||
legacy_build_dir = join(get_project_dir(), ".pioenvs")
|
||||
if isdir(legacy_build_dir) and legacy_build_dir != build_dir:
|
||||
util.rmtree_(legacy_build_dir)
|
||||
|
||||
structhash_file = join(build_dir, "structure.hash")
|
||||
proj_hash = calculate_project_hash()
|
||||
|
||||
# if project's config is modified
|
||||
if (isdir(build_dir) and getmtime(
|
||||
join(get_project_dir(), "platformio.ini")) > getmtime(build_dir)):
|
||||
util.rmtree_(build_dir)
|
||||
|
||||
# check project structure
|
||||
if isdir(build_dir) and isfile(structhash_file):
|
||||
with open(structhash_file) as f:
|
||||
if f.read() == proj_hash:
|
||||
return
|
||||
util.rmtree_(build_dir)
|
||||
|
||||
if not isdir(build_dir):
|
||||
makedirs(build_dir)
|
||||
|
||||
with open(structhash_file, "w") as f:
|
||||
f.write(proj_hash)
|
||||
|
||||
|
||||
def print_header(label, is_error=False, fg=None):
|
||||
terminal_width, _ = click.get_terminal_size()
|
||||
width = len(click.unstyle(label))
|
||||
half_line = "=" * int((terminal_width - width - 2) / 2)
|
||||
click.secho(
|
||||
"%s %s %s" % (half_line, label, half_line), fg=fg, err=is_error)
|
||||
|
||||
|
||||
def print_summary(results, start_time):
|
||||
print_header("[%s]" % click.style("SUMMARY"))
|
||||
|
||||
succeeded_nums = 0
|
||||
failed_nums = 0
|
||||
envname_max_len = max(
|
||||
[len(click.style(envname, fg="cyan")) for (envname, _) in results])
|
||||
for (envname, status) in results:
|
||||
if status is False:
|
||||
failed_nums += 1
|
||||
status_str = click.style("FAILED", fg="red")
|
||||
elif status is None:
|
||||
status_str = click.style("IGNORED", fg="yellow")
|
||||
else:
|
||||
succeeded_nums += 1
|
||||
status_str = click.style("SUCCESS", fg="green")
|
||||
|
||||
format_str = "Environment {0:<%d}\t[{1}]" % envname_max_len
|
||||
click.echo(
|
||||
format_str.format(click.style(envname, fg="cyan"), status_str),
|
||||
err=status is False)
|
||||
|
||||
print_header(
|
||||
"%s%d succeeded in %.2f seconds" %
|
||||
("%d failed, " % failed_nums if failed_nums else "", succeeded_nums,
|
||||
time() - start_time),
|
||||
is_error=failed_nums,
|
||||
fg="red" if failed_nums else "green")
|
115
platformio/commands/run/processor.py
Normal file
115
platformio/commands/run/processor.py
Normal file
@ -0,0 +1,115 @@
|
||||
# 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 time import time
|
||||
|
||||
import click
|
||||
|
||||
from platformio import exception, telemetry
|
||||
from platformio.commands.platform import \
|
||||
platform_install as cmd_platform_install
|
||||
from platformio.commands.run.helpers import _autoinstall_libdeps, print_header
|
||||
from platformio.managers.platform import PlatformFactory
|
||||
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
|
||||
|
||||
class EnvironmentProcessor(object):
|
||||
|
||||
DEFAULT_PRINT_OPTIONS = ("platform", "framework", "board")
|
||||
|
||||
def __init__( # pylint: disable=too-many-arguments
|
||||
self, cmd_ctx, name, config, targets, upload_port, silent,
|
||||
verbose):
|
||||
self.cmd_ctx = cmd_ctx
|
||||
self.name = name
|
||||
self.config = config
|
||||
self.targets = targets
|
||||
self.upload_port = upload_port
|
||||
self.silent = silent
|
||||
self.verbose = verbose
|
||||
self.options = config.items(env=name, as_dict=True)
|
||||
|
||||
def process(self):
|
||||
terminal_width, _ = click.get_terminal_size()
|
||||
start_time = time()
|
||||
env_dump = []
|
||||
|
||||
for k, v in self.options.items():
|
||||
if self.verbose or k in self.DEFAULT_PRINT_OPTIONS:
|
||||
env_dump.append(
|
||||
"%s: %s" % (k, ", ".join(v) if isinstance(v, list) else v))
|
||||
|
||||
if not self.silent:
|
||||
click.echo("Processing %s (%s)" % (click.style(
|
||||
self.name, fg="cyan", bold=True), "; ".join(env_dump)))
|
||||
click.secho("-" * terminal_width, bold=True)
|
||||
|
||||
result = self._run_platform()
|
||||
is_error = result['returncode'] != 0
|
||||
|
||||
if self.silent and not is_error:
|
||||
return True
|
||||
|
||||
if is_error or "piotest_processor" not in self.cmd_ctx.meta:
|
||||
print_header(
|
||||
"[%s] Took %.2f seconds" % (
|
||||
(click.style("ERROR", fg="red", bold=True) if is_error else
|
||||
click.style("SUCCESS", fg="green", bold=True)),
|
||||
time() - start_time),
|
||||
is_error=is_error)
|
||||
|
||||
return not is_error
|
||||
|
||||
def get_build_variables(self):
|
||||
variables = {"pioenv": self.name, "project_config": self.config.path}
|
||||
if "piotest" in self.cmd_ctx.meta:
|
||||
variables['piotest'] = self.cmd_ctx.meta['piotest']
|
||||
if self.upload_port:
|
||||
# override upload port with a custom from CLI
|
||||
variables['upload_port'] = self.upload_port
|
||||
return variables
|
||||
|
||||
def get_build_targets(self):
|
||||
if self.targets:
|
||||
return [t for t in self.targets]
|
||||
return self.config.get("env:" + self.name, "targets", [])
|
||||
|
||||
def _run_platform(self):
|
||||
if "platform" not in self.options:
|
||||
raise exception.UndefinedEnvPlatform(self.name)
|
||||
|
||||
build_vars = self.get_build_variables()
|
||||
build_targets = self.get_build_targets()
|
||||
|
||||
telemetry.on_run_environment(self.options, build_targets)
|
||||
|
||||
# skip monitor target, we call it above
|
||||
if "monitor" in build_targets:
|
||||
build_targets.remove("monitor")
|
||||
if "nobuild" not in build_targets and "lib_deps" in self.options:
|
||||
_autoinstall_libdeps(
|
||||
self.cmd_ctx, self.name,
|
||||
self.config.get("env:" + self.name, "lib_deps"), self.verbose)
|
||||
|
||||
try:
|
||||
p = PlatformFactory.newPlatform(self.options['platform'])
|
||||
except exception.UnknownPlatform:
|
||||
self.cmd_ctx.invoke(
|
||||
cmd_platform_install,
|
||||
platforms=[self.options['platform']],
|
||||
skip_default_package=True)
|
||||
p = PlatformFactory.newPlatform(self.options['platform'])
|
||||
|
||||
return p.run(build_vars, build_targets, self.silent, self.verbose)
|
@ -22,7 +22,7 @@ from time import time
|
||||
import click
|
||||
|
||||
from platformio import exception, util
|
||||
from platformio.commands.run import print_header
|
||||
from platformio.commands.run.helpers import print_header
|
||||
from platformio.commands.test.embedded import EmbeddedTestProcessor
|
||||
from platformio.commands.test.native import NativeTestProcessor
|
||||
from platformio.project.config import ProjectConfig
|
||||
@ -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,
|
||||
@ -167,10 +166,11 @@ def cli( # pylint: disable=redefined-builtin
|
||||
passed_nums += 1
|
||||
status_str = click.style("PASSED", fg="green")
|
||||
|
||||
format_str = "test/{:<%d} > {:<%d}\t[{}]" % (testname_max_len,
|
||||
envname_max_len)
|
||||
click.echo(
|
||||
("test/{:<%d} > {:<%d}\t[{}]" %
|
||||
(testname_max_len, envname_max_len)).format(
|
||||
testname, click.style(envname, fg="cyan"), status_str),
|
||||
format_str.format(testname, click.style(envname, fg="cyan"),
|
||||
status_str),
|
||||
err=status is False)
|
||||
|
||||
print_header(
|
||||
|
@ -32,7 +32,8 @@ class EmbeddedTestProcessor(TestProcessorBase):
|
||||
target = ["__test"]
|
||||
if self.options['without_uploading']:
|
||||
target.append("checkprogsize")
|
||||
self.build_or_upload(target)
|
||||
if not self.build_or_upload(target):
|
||||
return False
|
||||
|
||||
if not self.options['without_uploading']:
|
||||
self.print_progress("Uploading... (2/3)")
|
||||
@ -41,7 +42,8 @@ class EmbeddedTestProcessor(TestProcessorBase):
|
||||
target.append("nobuild")
|
||||
else:
|
||||
target.append("__test")
|
||||
self.build_or_upload(target)
|
||||
if not self.build_or_upload(target):
|
||||
return False
|
||||
|
||||
if self.options['without_testing']:
|
||||
return None
|
||||
|
@ -25,7 +25,8 @@ class NativeTestProcessor(TestProcessorBase):
|
||||
def process(self):
|
||||
if not self.options['without_building']:
|
||||
self.print_progress("Building... (1/2)")
|
||||
self.build_or_upload(["__test"])
|
||||
if not self.build_or_upload(["__test"]):
|
||||
return False
|
||||
if self.options['without_testing']:
|
||||
return None
|
||||
self.print_progress("Testing... (2/2)")
|
||||
|
@ -21,7 +21,7 @@ import click
|
||||
|
||||
from platformio import exception
|
||||
from platformio.commands.run import cli as cmd_run
|
||||
from platformio.commands.run import print_header
|
||||
from platformio.commands.run.helpers import print_header
|
||||
from platformio.project.helpers import get_project_test_dir
|
||||
|
||||
TRANSPORT_OPTIONS = {
|
||||
@ -82,7 +82,7 @@ class TestProcessorBase(object):
|
||||
|
||||
def __init__(self, cmd_ctx, testname, envname, options):
|
||||
self.cmd_ctx = cmd_ctx
|
||||
self.cmd_ctx.meta['piotest_processor'] = True
|
||||
self.cmd_ctx.meta['piotest_processor'] = True # FIXME
|
||||
self.test_name = testname
|
||||
self.options = options
|
||||
self.env_name = envname
|
||||
@ -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:
|
||||
@ -108,8 +109,9 @@ class TestProcessorBase(object):
|
||||
def print_progress(self, text, is_error=False):
|
||||
click.echo()
|
||||
print_header(
|
||||
"[test/%s] %s" % (click.style(
|
||||
self.test_name, fg="yellow", bold=True), text),
|
||||
"[test/%s > %s] %s" % (click.style(self.test_name, fg="yellow"),
|
||||
click.style(self.env_name, fg="cyan"),
|
||||
text),
|
||||
is_error=is_error)
|
||||
|
||||
def build_or_upload(self, target):
|
||||
@ -118,19 +120,22 @@ class TestProcessorBase(object):
|
||||
self._outputcpp_generated = True
|
||||
|
||||
if self.test_name != "*":
|
||||
self.cmd_ctx.meta['piotest'] = self.test_name
|
||||
self.cmd_ctx.meta['piotest'] = self.test_name # FIXME
|
||||
|
||||
if not self.options['verbose']:
|
||||
click.echo("Please wait...")
|
||||
|
||||
return self.cmd_ctx.invoke(
|
||||
cmd_run,
|
||||
project_dir=self.options['project_dir'],
|
||||
upload_port=self.options['upload_port'],
|
||||
silent=not self.options['verbose'],
|
||||
environment=[self.env_name],
|
||||
disable_auto_clean="nobuild" in target,
|
||||
target=target)
|
||||
try:
|
||||
return self.cmd_ctx.invoke(
|
||||
cmd_run,
|
||||
project_dir=self.options['project_dir'],
|
||||
upload_port=self.options['upload_port'],
|
||||
silent=not self.options['verbose'],
|
||||
environment=[self.env_name],
|
||||
disable_auto_clean="nobuild" in target,
|
||||
target=target)
|
||||
except exception.ReturnErrorCode:
|
||||
return False
|
||||
|
||||
def process(self):
|
||||
raise NotImplementedError
|
||||
|
@ -29,6 +29,7 @@ from platformio.managers.core import get_core_package_dir
|
||||
from platformio.managers.package import BasePkgManager, PackageManager
|
||||
from platformio.proc import (BuildAsyncPipe, copy_pythonpath_to_osenv,
|
||||
exec_command, get_pythonexe_path)
|
||||
from platformio.project.config import ProjectConfig
|
||||
from platformio.project.helpers import (
|
||||
get_project_boards_dir, get_project_core_dir, get_project_packages_dir,
|
||||
get_project_platforms_dir)
|
||||
@ -358,7 +359,12 @@ class PlatformRunMixin(object):
|
||||
assert isinstance(variables, dict)
|
||||
assert isinstance(targets, list)
|
||||
|
||||
self.configure_default_packages(variables, targets)
|
||||
config = ProjectConfig.get_instance(variables['project_config'])
|
||||
options = config.items(env=variables['pioenv'], as_dict=True)
|
||||
if "framework" in options:
|
||||
# support PIO Core 3.0 dev/platforms
|
||||
options['pioframework'] = options['framework']
|
||||
self.configure_default_packages(options, targets)
|
||||
self.install_packages(silent=True)
|
||||
|
||||
self.silent = silent
|
||||
@ -611,12 +617,9 @@ class PlatformBase( # pylint: disable=too-many-public-methods
|
||||
def get_package_type(self, name):
|
||||
return self.packages[name].get("type")
|
||||
|
||||
def configure_default_packages(self, variables, targets):
|
||||
def configure_default_packages(self, options, targets):
|
||||
# enable used frameworks
|
||||
frameworks = variables.get("pioframework", [])
|
||||
if not isinstance(frameworks, list):
|
||||
frameworks = frameworks.split(", ")
|
||||
for framework in frameworks:
|
||||
for framework in options.get("framework", []):
|
||||
if not self.frameworks:
|
||||
continue
|
||||
framework = framework.lower().strip()
|
||||
|
@ -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,39 +152,84 @@ 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 = None
|
||||
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 or default
|
||||
|
||||
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
|
||||
|
||||
# option is not specified by user
|
||||
if value is None:
|
||||
return default
|
||||
|
||||
return self._covert_value(value, option_meta.type)
|
||||
|
||||
@staticmethod
|
||||
def _covert_value(value, to_type):
|
||||
items = value
|
||||
if not isinstance(value, (list, tuple)):
|
||||
items = [value]
|
||||
for i, v in enumerate(items):
|
||||
if to_type == bool:
|
||||
items[i] = v in ("1", "true", "yes", "y")
|
||||
elif to_type == int:
|
||||
items[i] = int(v)
|
||||
elif to_type == float:
|
||||
items[i] = float(v)
|
||||
return items if isinstance(value, (list, tuple)) else items[0]
|
||||
|
||||
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):
|
||||
def validate(self, envs=None, silent=False):
|
||||
if not isfile(self.path):
|
||||
raise exception.NotPlatformIOProject(self.path)
|
||||
# check envs
|
||||
@ -283,74 +241,65 @@ class ProjectConfig(object):
|
||||
if unknown:
|
||||
raise exception.UnknownEnvNames(", ".join(unknown),
|
||||
", ".join(known))
|
||||
return self.validate_options() if validate_options else True
|
||||
return self.validate_options(silent)
|
||||
|
||||
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"):
|
||||
def validate_options(self, silent=False):
|
||||
warnings = []
|
||||
# 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")
|
||||
warnings.append(
|
||||
"`lib_extra_dirs` configuration option is deprecated in "
|
||||
"section [platformio]! Please move it to global `env` section")
|
||||
|
||||
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))
|
||||
warnings.extend(self._validate_unknown_options())
|
||||
|
||||
for warning in warnings:
|
||||
click.secho("Warning! %s" % warning, fg="yellow")
|
||||
if not silent:
|
||||
for warning in warnings:
|
||||
click.secho("Warning! %s" % warning, fg="yellow")
|
||||
|
||||
return True
|
||||
return warnings
|
||||
|
||||
def _validate_env_options(self):
|
||||
warnings = set()
|
||||
def _validate_unknown_options(self):
|
||||
warnings = []
|
||||
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:
|
||||
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]))
|
||||
if option in renamed_options:
|
||||
warnings.append(
|
||||
"`%s` configuration 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
|
||||
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))
|
||||
|
||||
for warning in warnings:
|
||||
click.secho("Warning! %s" % warning, fg="yellow")
|
||||
|
||||
return True
|
||||
warnings.append("Ignore unknown configuration option `%s` "
|
||||
"in section [%s]" % (option, section))
|
||||
return warnings
|
||||
|
||||
def to_json(self):
|
||||
result = {}
|
||||
|
@ -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,46 +44,31 @@ 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():
|
||||
default = join(expanduser("~"), ".platformio")
|
||||
core_dir = get_project_optional_dir(
|
||||
"core_dir",
|
||||
get_project_optional_dir("home_dir",
|
||||
join(expanduser("~"), ".platformio")))
|
||||
"core_dir", get_project_optional_dir("home_dir", default))
|
||||
win_core_dir = None
|
||||
if WINDOWS:
|
||||
if WINDOWS and core_dir == default:
|
||||
win_core_dir = splitdrive(core_dir)[0] + "\\.platformio"
|
||||
if isdir(win_core_dir):
|
||||
core_dir = win_core_dir
|
||||
@ -91,10 +76,12 @@ def get_project_core_dir():
|
||||
if not isdir(core_dir):
|
||||
try:
|
||||
os.makedirs(core_dir)
|
||||
except: # pylint: disable=bare-except
|
||||
except OSError as e:
|
||||
if win_core_dir:
|
||||
os.makedirs(win_core_dir)
|
||||
core_dir = win_core_dir
|
||||
else:
|
||||
raise e
|
||||
|
||||
assert isdir(core_dir)
|
||||
return core_dir
|
||||
|
198
platformio/project/options.py
Normal file
198
platformio/project/options.py
Normal file
@ -0,0 +1,198 @@
|
||||
# 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"]),
|
||||
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),
|
||||
|
||||
# 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")
|
||||
]
|
||||
])
|
@ -310,12 +310,15 @@ def measure_ci():
|
||||
|
||||
|
||||
def on_run_environment(options, targets):
|
||||
opts = [
|
||||
"%s=%s" % (opt, value.replace("\n", ", ") if "\n" in value else value)
|
||||
for opt, value in sorted(options.items())
|
||||
]
|
||||
non_sensative_values = ["board", "platform", "framework"]
|
||||
safe_options = []
|
||||
for key, value in sorted(options.items()):
|
||||
if key in non_sensative_values:
|
||||
safe_options.append("%s=%s" % (key, value))
|
||||
else:
|
||||
safe_options.append(key)
|
||||
targets = [t.title() for t in targets or ["run"]]
|
||||
on_event("Env", " ".join(targets), "&".join(opts))
|
||||
on_event("Env", " ".join(targets), "&".join(safe_options))
|
||||
|
||||
|
||||
def on_event(category, action, label=None, value=None, screen_name=None):
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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,13 @@ 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 = dict(platform=str(boards[0]['platform']),
|
||||
board="uno",
|
||||
framework=[str(boards[0]['frameworks'][0])])
|
||||
assert config.has_section("env:uno")
|
||||
assert not set(expected_result).symmetric_difference(
|
||||
set(config.items("env:uno")))
|
||||
assert sorted(config.items(env="uno", as_dict=True).items()) == sorted(
|
||||
expected_result.items())
|
||||
|
||||
|
||||
def test_init_enable_auto_uploading(clirunner, validate_cliresult):
|
||||
@ -126,11 +126,13 @@ 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 = dict(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 sorted(config.items(env="uno", as_dict=True).items()) == sorted(
|
||||
expected_result.items())
|
||||
|
||||
|
||||
def test_init_custom_framework(clirunner, validate_cliresult):
|
||||
@ -141,11 +143,13 @@ 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 = dict(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 sorted(config.items(env="teensy31",
|
||||
as_dict=True).items()) == sorted(
|
||||
expected_result.items())
|
||||
|
||||
|
||||
def test_init_incorrect_board(clirunner):
|
||||
|
@ -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"
|
||||
@ -87,30 +102,76 @@ def test_parser(tmpdir):
|
||||
assert not config.has_option("custom", "monitor_speed")
|
||||
|
||||
# sysenv
|
||||
assert config.get("custom", "extra_flags") == ""
|
||||
assert config.get("custom", "extra_flags") is None
|
||||
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_HOME_DIR"] = "/custom/core/dir"
|
||||
assert config.get("platformio", "core_dir") == "/custom/core/dir"
|
||||
del os.environ["PLATFORMIO_HOME_DIR"]
|
||||
|
Reference in New Issue
Block a user