Merge branch 'develop' into feature/pio-plus-oss

This commit is contained in:
Ivan Kravets
2019-05-10 01:10:51 +03:00
42 changed files with 1148 additions and 748 deletions

View File

@ -1,23 +1,12 @@
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time. See also the "--disable" option for examples.
#enable=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
# disable=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating
disable=locally-disabled,missing-docstring,invalid-name,too-few-public-methods,redefined-variable-type,import-error,similarities,unsupported-membership-test,unsubscriptable-object,ungrouped-imports,cyclic-import,superfluous-parens,useless-object-inheritance,useless-import-alias
disable=
missing-docstring,
ungrouped-imports,
invalid-name,
cyclic-import,
duplicate-code,
superfluous-parens,
too-few-public-methods,
useless-object-inheritance,
useless-import-alias,
fixme

View File

@ -7,15 +7,31 @@ PlatformIO 4.0
4.0.0 (2019-??-??)
~~~~~~~~~~~~~~~~~~
* Added Python 3.5+ support
* Python 3 support
(`issue #895 <https://github.com/platformio/platformio-core/issues/895>`_)
* Share common (global) options between declared build environments using ``[env]`` section in `"platformio.ini" (Project Configuration File) <https://docs.platformio.org/page/projectconf.html>`__
(`issue #1643 <https://github.com/platformio/platformio-core/issues/1643>`_)
* Include external configuration files in `"platformio.ini" (Project Configuration File) <https://docs.platformio.org/page/projectconf.html>`__ with `extra_configs <http://docs.platformio.org/page/projectconf/section_platformio.html#extra-configs>`__ option
(`issue #1590 <https://github.com/platformio/platformio-core/issues/1590>`_)
* Override default `"platformio.ini" (Project Configuration File) <https://docs.platformio.org/page/projectconf.html>`__ with a custom using ``-c, --project-conf`` option for `platformio run <http://docs.platformio.org/page/userguide/cmd_run.html>`__, `platformio debug <http://docs.platformio.org/page/userguide/cmd_debug.html>`__, or `platformio test <http://docs.platformio.org/page/userguide/cmd_test.html>`__ commands
(`issue #1913 <https://github.com/platformio/platformio-core/issues/1913>`_)
* Override default source and include directories for a library via `library.json <http://docs.platformio.org/page/librarymanager/config.html>`__ manifest using ``includeDir`` and ``srcDir`` fields
* Added support for the latest Python "Click" package (CLI Builder)
(`issue #349 <https://github.com/platformio/platformio-core/issues/349>`_)
PlatformIO 3.0
--------------
3.6.7 (2019-??-??)
3.6.8 (2019-??-??)
~~~~~~~~~~~~~~~~~~
* Fixed "systemd-udevd" warnings in `99-platformio-udev.rules <http://docs.platformio.org/page/faq.html#platformio-udev-rules>`__
(`issue #2442 <https://github.com/platformio/platformio-core/issues/2442>`_)
3.6.7 (2019-04-23)
~~~~~~~~~~~~~~~~~~
* `PIO Unified Debugger <https://docs.platformio.org/page/plus/debugging.html>`__: improved debugging in ``debug_load_mode = modified`` and fixed an issue with useless project rebuilding
* Project Generator: fixed a VSCode C/C++'s "Cannot find" warning when CPPPATH folder does not exist
* Fixed an "IndexError: list index out of range" for Arduino sketch preprocessor
(`issue #2268 <https://github.com/platformio/platformio-core/issues/2268>`_)
@ -30,7 +46,7 @@ PlatformIO 3.0
* Fixed an issue when PlatformIO Build System does not pick up "mbed_lib.json" files from libraries
(`issue #2164 <https://github.com/platformio/platformio-core/issues/2164>`_)
* Fixed an error with conflicting declaration of a prototype (Arduino sketch preprocessor)
* Fixed "FileExistsError" when `platformio ci <https://docs.platformio.org/en/latest/userguide/cmd_ci.html>`__ command is used in pair with ``--keep-build-dir`` option
* Fixed "FileExistsError" when `platformio ci <https://docs.platformio.org/page/userguide/cmd_ci.html>`__ command is used in pair with ``--keep-build-dir`` option
* Fixed an issue with incorrect order of project "include" and "src" paths in ``CPPPATH``
(`issue #1914 <https://github.com/platformio/platformio-core/issues/1914>`_)
@ -40,7 +56,7 @@ PlatformIO 3.0
* Project Generator: added new targets for CLion IDE "BUILD_VERBOSE" and "MONITOR" (serial port monitor)
(`issue #359 <https://github.com/platformio/platformio-core/issues/359>`_)
* Fixed an issue with slow updating of PlatformIO Core packages on Windows
* Fixed an issue when `platformio ci <https://docs.platformio.org/en/latest/userguide/cmd_ci.html>`__ recompiles project if ``--keep-build-dir`` option is passed
* Fixed an issue when `platformio ci <https://docs.platformio.org/page/userguide/cmd_ci.html>`__ recompiles project if ``--keep-build-dir`` option is passed
(`issue #2109 <https://github.com/platformio/platformio-core/issues/2109>`_)
* Fixed an issue when ``$PROJECT_HASH`` template was not expanded for the other directory ``***_dir`` options in `"platformio.ini" (Project Configuration File) <https://docs.platformio.org/page/projectconf.html>`__
(`issue #2170 <https://github.com/platformio/platformio-core/issues/2170>`_)
@ -88,9 +104,9 @@ PlatformIO 3.0
* Generate an `include <http://docs.platformio.org/page/projectconf/section_platformio.html#include-dir>`__ and `test <http://docs.platformio.org/page/projectconf/section_platformio.html#test-dir>`__ directories with a README file when initializing a new project
* Support in-line comments for multi-line value (``lib_deps``, ``build_flags``, etc) in `"platformio.ini" (Project Configuration File) <https://docs.platformio.org/page/projectconf.html>`__
* Added ``$PROJECT_HASH`` template variable for `build_dir <http://docs.platformio.org/en/latest/projectconf/section_platformio.html#projectconf-pio-build-dir>`__. One of the use cases is setting a global storage for project artifacts using `PLATFORMIO_BUILD_DIR <http://docs.platformio.org/en/latest/envvars.html#envvar-PLATFORMIO_BUILD_DIR>`__ system environment variable. For example, ``/tmp/pio-build/$PROJECT_HASH`` (Unix) or ``$[sysenv.TEMP}/pio-build/$PROJECT_HASH`` (Windows)
* Added ``$PROJECT_HASH`` template variable for `build_dir <http://docs.platformio.org/page/projectconf/section_platformio.html#projectconf-pio-build-dir>`__. One of the use cases is setting a global storage for project artifacts using `PLATFORMIO_BUILD_DIR <http://docs.platformio.org/page/envvars.html#envvar-PLATFORMIO_BUILD_DIR>`__ system environment variable. For example, ``/tmp/pio-build/$PROJECT_HASH`` (Unix) or ``$[sysenv.TEMP}/pio-build/$PROJECT_HASH`` (Windows)
* Improved a loading speed of PIO Home "Recent News"
* Improved `PIO Unified Debugger <https://docs.platformio.org/en/page/plus/debugging.html>`__ for "mbed" framework and fixed issue with missed local variables
* Improved `PIO Unified Debugger <https://docs.platformio.org/page/plus/debugging.html>`__ for "mbed" framework and fixed issue with missed local variables
* Introduced `"Release" and "Debug" Build Configurations <http://docs.platformio.org/page/projectconf/build_configurations.html>`__
* Build project in "Debug Mode" including debugging information with a new ``debug`` target using `platformio run <https://docs.platformio.org/page/userguide/cmd_run.html>`__ command or `targets <http://docs.platformio.org/page/projectconf/section_env_general.html#targets>`__ option in ``platformio.ini``. The last option allows avoiding project rebuilding between "Run/Debug" modes.
(`issue #1833 <https://github.com/platformio/platformio-core/issues/1833>`_)
@ -148,7 +164,7 @@ PlatformIO 3.0
build environment
(`issue #1665 <https://github.com/platformio/platformio-core/issues/1665>`_)
* Handle "architectures" data from "library.properties" manifest in
`lib_compat_mode = strict <https://docs.platformio.org/en/page/librarymanager/ldf.html#compatibility-mode>`__
`lib_compat_mode = strict <https://docs.platformio.org/page/librarymanager/ldf.html#compatibility-mode>`__
* Added workaround for Python SemVer package's `issue #61 <https://github.com/rbarrois/python-semanticversion/issues/61>`_ with caret range and pre-releases
* Replaced conflicted "env" pattern by "sysenv" for `"platformio.ini" Dynamic Variables" <https://docs.platformio.org/page/projectconf/dynamic_variables.html>`__
(`issue #1705 <https://github.com/platformio/platformio-core/issues/1705>`_)
@ -176,7 +192,7 @@ PlatformIO 3.0
(`issue #1612 <https://github.com/platformio/platformio-core/issues/1612>`_)
* Configure a custom path to SVD file using `debug_svd_path <https://docs.platformio.org/page/projectconf/section_env_debug.html#debug-svd-path>`__
option
* Custom project `description <https://docs.platformio.org/en/page/projectconf/section_platformio.html#description>`_
* Custom project `description <https://docs.platformio.org/page/projectconf/section_platformio.html#description>`_
which will be used by `PlatformIO Home <https://docs.platformio.org/page/home/index.html>`_
* Updated Unity tool to 2.4.3
* Improved support for Black Magic Probe in "uploader" mode
@ -202,9 +218,9 @@ PlatformIO 3.0
- Multiple themes (Dark & Light)
- Ability to specify a name for new project
* Control `PIO Unified Debugger <https://docs.platformio.org/en/page/plus/debugging.html>`__
* Control `PIO Unified Debugger <https://docs.platformio.org/page/plus/debugging.html>`__
and its firmware loading mode using
`debug_load_mode <https://docs.platformio.org/en/page/projectconf/section_env_debug.html#debug-load-mode>`__ option
`debug_load_mode <https://docs.platformio.org/page/projectconf/section_env_debug.html#debug-load-mode>`__ option
* Added aliases (off, light, strict) for
`LDF Compatibility Mode <https://docs.platformio.org/page/librarymanager/ldf.html>`__
* Search for a library using PIO Library Registry ID ``id:X`` (e.g. ``pio lib search id:13``)

View File

@ -78,6 +78,7 @@ Registry
Development Platforms
---------------------
* `Aceinna IMU <https://platformio.org/platforms/aceinna_imu?utm_source=github&utm_medium=core>`_
* `Atmel AVR <https://platformio.org/platforms/atmelavr?utm_source=github&utm_medium=core>`_
* `Atmel SAM <https://platformio.org/platforms/atmelsam?utm_source=github&utm_medium=core>`_
* `Espressif 32 <https://platformio.org/platforms/espressif32?utm_source=github&utm_medium=core>`_
@ -86,6 +87,7 @@ Development Platforms
* `Infineon XMC <https://platformio.org/platforms/infineonxmc?utm_source=github&utm_medium=core>`_
* `Intel ARC32 <https://platformio.org/platforms/intel_arc32?utm_source=github&utm_medium=core>`_
* `Intel MCS-51 (8051) <https://platformio.org/platforms/intel_mcs51?utm_source=github&utm_medium=core>`_
* `Kendryte K210 <https://platformio.org/platforms/kendryte210?utm_source=github&utm_medium=core>`_
* `Lattice iCE40 <https://platformio.org/platforms/lattice_ice40?utm_source=github&utm_medium=core>`_
* `Maxim 32 <https://platformio.org/platforms/maxim32?utm_source=github&utm_medium=core>`_
* `Microchip PIC32 <https://platformio.org/platforms/microchippic32?utm_source=github&utm_medium=core>`_
@ -93,6 +95,7 @@ Development Platforms
* `Nordic nRF52 <https://platformio.org/platforms/nordicnrf52?utm_source=github&utm_medium=core>`_
* `NXP LPC <https://platformio.org/platforms/nxplpc?utm_source=github&utm_medium=core>`_
* `RISC-V <https://platformio.org/platforms/riscv?utm_source=github&utm_medium=core>`_
* `RISC-V GAP <https://platformio.org/platforms/riscv_gap?utm_source=github&utm_medium=core>`_
* `Samsung ARTIK <https://platformio.org/platforms/samsung_artik?utm_source=github&utm_medium=core>`_
* `Silicon Labs EFM32 <https://platformio.org/platforms/siliconlabsefm32?utm_source=github&utm_medium=core>`_
* `ST STM32 <https://platformio.org/platforms/ststm32?utm_source=github&utm_medium=core>`_
@ -112,8 +115,11 @@ Frameworks
* `ESP-IDF <https://platformio.org/frameworks/espidf?utm_source=github&utm_medium=core>`_
* `ESP8266 Non-OS SDK <https://platformio.org/frameworks/esp8266-nonos-sdk?utm_source=github&utm_medium=core>`_
* `ESP8266 RTOS SDK <https://platformio.org/frameworks/esp8266-rtos-sdk?utm_source=github&utm_medium=core>`_
* `Freedom E SDK <https://platformio.org/frameworks/freedom-e-sdk?utm_source=github&utm_medium=core>`_
* `Kendryte Standalone SDK <https://platformio.org/frameworks/kendryte-standalone-sdk?utm_source=github&utm_medium=core>`_
* `libOpenCM3 <https://platformio.org/frameworks/libopencm3?utm_source=github&utm_medium=core>`_
* `mbed <https://platformio.org/frameworks/mbed?utm_source=github&utm_medium=core>`_
* `PULP OS <https://platformio.org/frameworks/pulp-os?utm_source=github&utm_medium=core>`_
* `Pumbaa <https://platformio.org/frameworks/pumbaa?utm_source=github&utm_medium=core>`_
* `Simba <https://platformio.org/frameworks/simba?utm_source=github&utm_medium=core>`_
* `SPL <https://platformio.org/frameworks/spl?utm_source=github&utm_medium=core>`_

2
docs

Submodule docs updated: 1532572c62...c5a33bc006

View File

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
VERSION = (4, 0, "0a7")
VERSION = (4, 0, "0a12")
__version__ = ".".join([str(s) for s in VERSION])
__title__ = "platformio"

View File

@ -14,53 +14,13 @@
import os
import sys
from os.path import isdir, isfile, join
from platform import system
from traceback import format_exc
import click
from platformio import __version__, exception, maintenance
from platformio.util import get_source_dir
class PlatformioCLI(click.MultiCommand):
def list_commands(self, ctx):
cmds = []
commands_dir = join(get_source_dir(), "commands")
for name in os.listdir(commands_dir):
if name.startswith("__init__"):
continue
if (isdir(join(commands_dir, name))
and isfile(join(commands_dir, name, "command.py"))):
cmds.append(name)
elif name.endswith(".py"):
cmds.append(name[:-3])
cmds.sort()
return cmds
def get_command(self, ctx, cmd_name):
mod = None
try:
mod = __import__("platformio.commands." + cmd_name, None, None,
["cli"])
except ImportError:
try:
return self._handle_obsolate_command(cmd_name)
except AttributeError:
raise click.UsageError('No such command "%s"' % cmd_name, ctx)
return mod.cli
@staticmethod
def _handle_obsolate_command(name):
if name == "platforms":
from platformio.commands import platform
return platform.cli
if name == "serialports":
from platformio.commands import device
return device.cli
raise AttributeError()
from platformio.commands import PlatformioCLI
@click.command(

View File

@ -19,11 +19,20 @@ from os import environ
from os.path import expanduser, join
from time import time
from SCons.Script import (ARGUMENTS, COMMAND_LINE_TARGETS, DEFAULT_TARGETS,
AllowSubstExceptions, AlwaysBuild, Default,
DefaultEnvironment, Variables)
from SCons.Script import ARGUMENTS # pylint: disable=import-error
from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error
from SCons.Script import DEFAULT_TARGETS # pylint: disable=import-error
from SCons.Script import AllowSubstExceptions # pylint: disable=import-error
from SCons.Script import AlwaysBuild # pylint: disable=import-error
from SCons.Script import Default # pylint: disable=import-error
from SCons.Script import DefaultEnvironment # pylint: disable=import-error
from SCons.Script import Variables # pylint: disable=import-error
from platformio import util
from platformio.project.helpers import (
get_project_dir, get_project_optional_dir, get_projectbuild_dir,
get_projectdata_dir, get_projectinclude_dir, get_projectlib_dir,
get_projectlibdeps_dir, get_projectsrc_dir, get_projecttest_dir)
AllowSubstExceptions(NameError)
@ -96,19 +105,19 @@ DEFAULT_ENV_OPTIONS = dict(
ENV=environ,
UNIX_TIME=int(time()),
PIOHOME_DIR=util.get_home_dir(),
PROJECT_DIR=util.get_project_dir(),
PROJECTINCLUDE_DIR=util.get_projectinclude_dir(),
PROJECTSRC_DIR=util.get_projectsrc_dir(),
PROJECTTEST_DIR=util.get_projecttest_dir(),
PROJECTDATA_DIR=util.get_projectdata_dir(),
PROJECTBUILD_DIR=util.get_projectbuild_dir(),
PROJECT_DIR=get_project_dir(),
PROJECTINCLUDE_DIR=get_projectinclude_dir(),
PROJECTSRC_DIR=get_projectsrc_dir(),
PROJECTTEST_DIR=get_projecttest_dir(),
PROJECTDATA_DIR=get_projectdata_dir(),
PROJECTBUILD_DIR=get_projectbuild_dir(),
BUILD_DIR=join("$PROJECTBUILD_DIR", "$PIOENV"),
BUILDSRC_DIR=join("$BUILD_DIR", "src"),
BUILDTEST_DIR=join("$BUILD_DIR", "test"),
LIBPATH=["$BUILD_DIR"],
LIBSOURCE_DIRS=[
util.get_projectlib_dir(),
util.get_projectlibdeps_dir(),
get_projectlib_dir(),
get_projectlibdeps_dir(),
join("$PIOHOME_DIR", "lib")
],
PROGNAME="program",
@ -151,10 +160,10 @@ for var in ("BUILD_FLAGS", "SRC_BUILD_FLAGS", "SRC_FILTER", "EXTRA_SCRIPTS",
env.Append(**{var: util.parse_conf_multi_values(environ.get(k))})
# Configure extra library source directories for LDF
if util.get_project_optional_dir("lib_extra_dirs"):
if get_project_optional_dir("lib_extra_dirs"):
env.Prepend(
LIBSOURCE_DIRS=util.parse_conf_multi_values(
util.get_project_optional_dir("lib_extra_dirs")))
get_project_optional_dir("lib_extra_dirs")))
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']

View File

@ -18,7 +18,7 @@ from glob import glob
from os import environ
from os.path import abspath, isfile, join
from SCons.Defaults import processDefines
from SCons.Defaults import processDefines # pylint: disable=import-error
from platformio import util
from platformio.managers.core import get_core_package_dir

View File

@ -26,8 +26,10 @@ from glob import glob
from os.path import (basename, commonprefix, dirname, isdir, isfile, join,
realpath, sep)
import SCons.Scanner
from SCons.Script import ARGUMENTS, COMMAND_LINE_TARGETS, DefaultEnvironment
import SCons.Scanner # pylint: disable=import-error
from SCons.Script import ARGUMENTS # pylint: disable=import-error
from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error
from SCons.Script import DefaultEnvironment # pylint: disable=import-error
from platformio import exception, util
from platformio.builder.tools import platformio as piotool
@ -44,8 +46,8 @@ class LibBuilderFactory(object):
clsname = "PlatformIOLibBuilder"
else:
used_frameworks = LibBuilderFactory.get_used_frameworks(env, path)
common_frameworks = (
set(env.get("PIOFRAMEWORK", [])) & set(used_frameworks))
common_frameworks = (set(env.get("PIOFRAMEWORK", []))
& set(used_frameworks))
if common_frameworks:
clsname = "%sLibBuilder" % list(common_frameworks)[0].title()
elif used_frameworks:
@ -719,6 +721,18 @@ class PlatformIOLibBuilder(LibBuilderBase):
def _is_arduino_manifest(self):
return isfile(join(self.path, "library.properties"))
@property
def include_dir(self):
if "includeDir" in self._manifest.get("build", {}):
return self._manifest.get("build").get("includeDir")
return LibBuilderBase.include_dir.fget(self)
@property
def src_dir(self):
if "srcDir" in self._manifest.get("build", {}):
return self._manifest.get("build").get("srcDir")
return LibBuilderBase.src_dir.fget(self)
@property
def src_filter(self):
if "srcFilter" in self._manifest.get("build", {}):

View File

@ -21,8 +21,8 @@ from os import environ, remove, walk
from os.path import basename, isdir, isfile, join, realpath, relpath, sep
from tempfile import mkstemp
from SCons.Action import Action
from SCons.Script import ARGUMENTS
from SCons.Action import Action # pylint: disable=import-error
from SCons.Script import ARGUMENTS # pylint: disable=import-error
from platformio import util
from platformio.managers.core import get_core_package_dir
@ -296,8 +296,7 @@ def ProcessDebug(env):
if not env.subst("$PIODEBUGFLAGS"):
env.Replace(PIODEBUGFLAGS=["-Og", "-g3", "-ggdb3"])
env.Append(
PIODEBUGFLAGS=["-D__PLATFORMIO_DEBUG__"],
BUILD_FLAGS=env.get("PIODEBUGFLAGS", []))
BUILD_FLAGS=list(env['PIODEBUGFLAGS']) + ["-D__PLATFORMIO_DEBUG__"])
unflags = ["-Os"]
for level in [0, 1, 2]:
for flag in ("O", "g", "ggdb"):

View File

@ -18,7 +18,7 @@ import base64
import sys
from os.path import isdir, isfile, join
from SCons.Script import COMMAND_LINE_TARGETS
from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error
from platformio import exception, util
from platformio.managers.platform import PlatformFactory

View File

@ -22,7 +22,7 @@ from os.path import isfile, join
from shutil import copyfile
from time import sleep
from SCons.Script import ARGUMENTS
from SCons.Script import ARGUMENTS # pylint: disable=import-error
from serial import Serial, SerialException
from platformio import exception, util

View File

@ -20,9 +20,12 @@ from glob import glob
from os import sep, walk
from os.path import basename, dirname, isdir, join, realpath
from SCons import Builder, Util
from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild,
DefaultEnvironment, Export, SConscript)
from SCons import Builder, Util # pylint: disable=import-error
from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error
from SCons.Script import AlwaysBuild # pylint: disable=import-error
from SCons.Script import DefaultEnvironment # pylint: disable=import-error
from SCons.Script import Export # pylint: disable=import-error
from SCons.Script import SConscript # pylint: disable=import-error
from platformio.util import glob_escape, pioversion_to_intstr, string_types

View File

@ -11,3 +11,51 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from os.path import dirname
import click
class PlatformioCLI(click.MultiCommand):
leftover_args = []
def invoke(self, ctx):
PlatformioCLI.leftover_args = ctx.args
if hasattr(ctx, "protected_args"):
PlatformioCLI.leftover_args = ctx.protected_args + ctx.args
return super(PlatformioCLI, self).invoke(ctx)
def list_commands(self, ctx):
cmds = []
for filename in os.listdir(dirname(__file__)):
if filename.startswith("__init__"):
continue
if filename.endswith(".py"):
cmds.append(filename[:-3])
cmds.sort()
return cmds
def get_command(self, ctx, cmd_name):
mod = None
try:
mod = __import__("platformio.commands." + cmd_name, None, None,
["cli"])
except ImportError:
try:
return self._handle_obsolate_command(cmd_name)
except AttributeError:
raise click.UsageError('No such command "%s"' % cmd_name, ctx)
return mod.cli
@staticmethod
def _handle_obsolate_command(name):
if name == "platforms":
from platformio.commands import platform
return platform.cli
if name == "serialports":
from platformio.commands import device
return device.cli
raise AttributeError()

View File

@ -25,6 +25,7 @@ from platformio.commands.init import cli as cmd_init
from platformio.commands.init import validate_boards
from platformio.commands.run import cli as cmd_run
from platformio.exception import CIBuildEnvsEmpty
from platformio.project.config import ProjectConfig
def validate_path(ctx, param, value): # pylint: disable=unused-argument
@ -58,7 +59,7 @@ def validate_path(ctx, param, value): # pylint: disable=unused-argument
file_okay=False, dir_okay=True, writable=True, resolve_path=True))
@click.option("--keep-build-dir", is_flag=True)
@click.option(
"-C",
"-c",
"--project-conf",
type=click.Path(
exists=True,
@ -161,8 +162,7 @@ def _exclude_contents(dst_dir, patterns):
def _copy_project_conf(build_dir, project_conf):
config = util.load_project_config(project_conf)
config = ProjectConfig(project_conf, parse_extra=False)
if config.has_section("platformio"):
config.remove_section("platformio")
with open(join(build_dir, "platformio.ini"), "w") as fp:
config.write(fp)
config.save(join(build_dir, "platformio.ini"))

View File

@ -15,11 +15,13 @@
import json
import sys
from os import getcwd
from os.path import join
import click
from serial.tools import miniterm
from platformio import exception, util
from platformio.project.config import ProjectConfig
@click.group(short_help="Monitor device or list existing")
@ -161,11 +163,10 @@ def device_list( # pylint: disable=too-many-branches
help="Load configuration from `platformio.ini` and specified environment")
def device_monitor(**kwargs): # pylint: disable=too-many-branches
try:
project_options = get_project_options(kwargs['project_dir'],
monitor_options = get_project_options(kwargs['project_dir'],
kwargs['environment'])
monitor_options = {k: v for k, v in project_options or []}
if monitor_options:
for k in ("port", "baud", "speed", "rts", "dtr"):
for k in ("port", "speed", "rts", "dtr"):
k2 = "monitor_%s" % k
if k == "speed":
k = "baud"
@ -205,24 +206,13 @@ def device_monitor(**kwargs): # pylint: disable=too-many-branches
raise exception.MinitermException(e)
def get_project_options(project_dir, environment):
config = util.load_project_config(project_dir)
if not config.sections():
return None
known_envs = [s[4:] for s in config.sections() if s.startswith("env:")]
if environment:
if environment in known_envs:
return config.items("env:%s" % environment)
raise exception.UnknownEnvNames(environment, ", ".join(known_envs))
if not known_envs:
return None
if config.has_option("platformio", "env_default"):
env_default = config.get("platformio",
"env_default").split(", ")[0].strip()
if env_default and env_default in known_envs:
return config.items("env:%s" % env_default)
return config.items("env:%s" % known_envs[0])
def get_project_options(project_dir, environment=None):
config = ProjectConfig.get_instance(join(project_dir, "platformio.ini"))
config.validate(envs=[environment] if environment else None)
if not environment:
default_envs = config.default_envs()
if default_envs:
environment = default_envs[0]
else:
environment = config.envs()[0]
return config.items(env=environment, as_dict=True)

View File

@ -16,16 +16,18 @@
from os import getcwd, makedirs
from os.path import isdir, isfile, join
from shutil import copyfile
import click
from platformio import exception, util
from platformio.commands.platform import \
platform_install as cli_platform_install
from platformio.commands.run import check_project_envs
from platformio.ide.projectgenerator import ProjectGenerator
from platformio.managers.platform import PlatformManager
from platformio.project.config import ProjectConfig
from platformio.project.helpers import (
get_projectinclude_dir, get_projectlib_dir, get_projectsrc_dir,
get_projecttest_dir, is_platformio_project)
def validate_boards(ctx, param, value): # pylint: disable=W0613
@ -88,18 +90,17 @@ def cli(
click.echo("%s - Project Configuration File" % click.style(
"platformio.ini", fg="cyan"))
is_new_project = not util.is_platformio_project(project_dir)
init_base_project(project_dir)
is_new_project = not is_platformio_project(project_dir)
if is_new_project:
init_base_project(project_dir)
if board:
fill_project_envs(ctx, project_dir, board, project_option, env_prefix,
ide is not None)
if ide:
env_name = get_best_envname(project_dir, board)
if not env_name:
raise exception.BoardNotDefined()
pg = ProjectGenerator(project_dir, ide, env_name)
pg = ProjectGenerator(project_dir, ide,
get_best_envname(project_dir, board))
pg.generate()
if is_new_project:
@ -128,38 +129,36 @@ def cli(
def get_best_envname(project_dir, boards=None):
config = util.load_project_config(project_dir)
env_default = None
if config.has_option("platformio", "env_default"):
env_default = util.parse_conf_multi_values(
config.get("platformio", "env_default"))
check_project_envs(config, env_default)
if env_default:
return env_default[0]
section = None
for section in config.sections():
if not section.startswith("env:"):
continue
elif config.has_option(section, "board") and (not boards or config.get(
section, "board") in boards):
break
return section[4:] if section else None
config = ProjectConfig(join(project_dir, "platformio.ini"))
config.validate()
envname = None
default_envs = config.default_envs()
if default_envs:
envname = default_envs[0]
if not boards:
return envname
for env in config.envs():
if not boards:
return env
if not envname:
envname = env
items = config.items(env=env, as_dict=True)
if "board" in items and items.get("board") in boards:
return env
return envname
def init_base_project(project_dir):
if util.is_platformio_project(project_dir):
return
copyfile(
join(util.get_source_dir(), "projectconftpl.ini"),
join(project_dir, "platformio.ini"))
ProjectConfig(join(project_dir, "platformio.ini")).save()
with util.cd(project_dir):
dir_to_readme = [
(util.get_projectsrc_dir(), None),
(util.get_projectinclude_dir(), init_include_readme),
(util.get_projectlib_dir(), init_lib_readme),
(util.get_projecttest_dir(), init_test_readme),
(get_projectsrc_dir(), None),
(get_projectinclude_dir(), init_include_readme),
(get_projectlib_dir(), init_lib_readme),
(get_projecttest_dir(), init_test_readme),
]
for (path, cb) in dir_to_readme:
if isdir(path):
@ -365,11 +364,9 @@ def init_cvs_ignore(project_dir):
def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix,
force_download):
content = []
config = ProjectConfig(
join(project_dir, "platformio.ini"), parse_extra=False)
used_boards = []
used_platforms = []
config = util.load_project_config(project_dir)
for section in config.sections():
cond = [
section.startswith("env:"),
@ -379,12 +376,15 @@ def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix,
used_boards.append(config.get(section, "board"))
pm = PlatformManager()
used_platforms = []
modified = False
for id_ in board_ids:
board_config = pm.board_config(id_)
used_platforms.append(board_config['platform'])
if id_ in used_boards:
continue
used_boards.append(id_)
modified = True
envopts = {"platform": board_config['platform'], "board": id_}
# find default framework for board
@ -398,20 +398,18 @@ def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix,
_name, _value = item.split("=", 1)
envopts[_name.strip()] = _value.strip()
content.append("")
content.append("[env:%s%s]" % (env_prefix, id_))
for name, value in envopts.items():
content.append("%s = %s" % (name, value))
section = "env:%s%s" % (env_prefix, id_)
config.add_section(section)
for option, value in envopts.items():
config.set(section, option, value)
if force_download and used_platforms:
_install_dependent_platforms(ctx, used_platforms)
if not content:
return
with open(join(project_dir, "platformio.ini"), "a") as f:
content.append("")
f.write("\n".join(content))
if modified:
config.save()
config.reset_instances()
def _install_dependent_platforms(ctx, platforms):

View File

@ -21,8 +21,10 @@ from os.path import isdir, join
import click
from platformio import exception, util
from platformio.commands import PlatformioCLI
from platformio.managers.lib import LibraryManager, get_builtin_libs
from platformio.util import get_api_result
from platformio.project.helpers import (
get_project_dir, get_projectlibdeps_dir, is_platformio_project)
try:
from urllib.parse import quote
@ -58,8 +60,8 @@ def cli(ctx, **options):
if not storage_dir:
if options['global']:
storage_dir = join(util.get_home_dir(), "lib")
elif util.is_platformio_project():
storage_dir = util.get_projectlibdeps_dir()
elif is_platformio_project():
storage_dir = get_projectlibdeps_dir()
elif util.is_ci():
storage_dir = join(util.get_home_dir(), "lib")
click.secho(
@ -67,17 +69,17 @@ def cli(ctx, **options):
"Please use `platformio lib --global %s` command to remove "
"this warning." % ctx.invoked_subcommand,
fg="yellow")
elif util.is_platformio_project(storage_dir):
elif is_platformio_project(storage_dir):
with util.cd(storage_dir):
storage_dir = util.get_projectlibdeps_dir()
storage_dir = get_projectlibdeps_dir()
if not storage_dir and not util.is_platformio_project():
raise exception.NotGlobalLibDir(util.get_project_dir(),
if not storage_dir and not is_platformio_project():
raise exception.NotGlobalLibDir(get_project_dir(),
join(util.get_home_dir(), "lib"),
ctx.invoked_subcommand)
ctx.obj = LibraryManager(storage_dir)
if "--json-output" not in ctx.args:
if "--json-output" not in PlatformioCLI.leftover_args:
click.echo("Library Storage: " + storage_dir)
@ -211,7 +213,7 @@ def lib_search(query, json_output, page, noninteractive, **filters):
for value in values:
query.append('%s:"%s"' % (key, value))
result = get_api_result(
result = util.get_api_result(
"/v2/lib/search",
dict(query=" ".join(query), page=page),
cache_valid="1d")
@ -258,7 +260,7 @@ def lib_search(query, json_output, page, noninteractive, **filters):
time.sleep(5)
elif not click.confirm("Show next libraries?"):
break
result = get_api_result(
result = util.get_api_result(
"/v2/lib/search", {
"query": " ".join(query),
"page": int(result['page']) + 1
@ -317,7 +319,7 @@ def lib_show(library, json_output):
},
silent=json_output,
interactive=not json_output)
lib = get_api_result("/lib/info/%d" % lib_id, cache_valid="1d")
lib = util.get_api_result("/lib/info/%d" % lib_id, cache_valid="1d")
if json_output:
return click.echo(json.dumps(lib))
@ -393,7 +395,8 @@ def lib_register(config_url):
and not config_url.startswith("https://")):
raise exception.InvalidLibConfURL(config_url)
result = get_api_result("/lib/register", data=dict(config_url=config_url))
result = util.get_api_result(
"/lib/register", data=dict(config_url=config_url))
if "message" in result and result['message']:
click.secho(
result['message'],
@ -404,7 +407,7 @@ def lib_register(config_url):
@cli.command("stats", short_help="Library Registry Statistics")
@click.option("--json-output", is_flag=True)
def lib_stats(json_output):
result = get_api_result("/lib/stats", cache_valid="1h")
result = util.get_api_result("/lib/stats", cache_valid="1h")
if json_output:
return click.echo(json.dumps(result))

View File

@ -12,20 +12,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from hashlib import sha1
from os import getcwd, makedirs, walk
from os import getcwd, makedirs
from os.path import getmtime, isdir, isfile, join
from time import time
import click
from platformio import __version__, exception, telemetry, util
from platformio import exception, telemetry, util
from platformio.commands.device import device_monitor as cmd_device_monitor
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.lib import LibraryManager, is_builtin_lib
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_dir,
get_projectbuild_dir, get_projectlibdeps_dir)
# pylint: disable=too-many-arguments,too-many-locals,too-many-branches
@ -44,50 +47,48 @@ from platformio.managers.platform import PlatformFactory
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, silent, verbose,
disable_auto_clean):
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 = util.find_project_dir_above(project_dir)
if not util.is_platformio_project(project_dir):
raise exception.NotPlatformIOProject(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(util.get_projectbuild_dir())
_clean_build_dir(get_projectbuild_dir())
except: # pylint: disable=bare-except
click.secho(
"Can not remove temporary directory `%s`. Please remove "
"it manually to avoid build issues" %
util.get_projectbuild_dir(force=True),
get_projectbuild_dir(force=True),
fg="yellow")
config = util.load_project_config()
env_default = None
if config.has_option("platformio", "env_default"):
env_default = util.parse_conf_multi_values(
config.get("platformio", "env_default"))
check_project_defopts(config)
check_project_envs(config, environment or env_default)
config = ProjectConfig.get_instance(
project_conf or join(project_dir, "platformio.ini"))
config.validate()
results = []
start_time = time()
for section in config.sections():
if not section.startswith("env:"):
continue
envname = section[4:]
default_envs = config.default_envs()
for envname in config.envs():
skipenv = any([
environment and envname not in environment, not environment
and env_default and envname not in env_default
and default_envs and envname not in default_envs
])
if skipenv:
results.append((envname, None))
@ -96,9 +97,7 @@ def cli(ctx, environment, target, upload_port, project_dir, silent, verbose,
if not silent and results:
click.echo()
options = {}
for k, v in config.items(section):
options[k] = v
options = config.items(env=envname, as_dict=True)
if "piotest" not in options and "piotest" in ctx.meta:
options['piotest'] = ctx.meta['piotest']
@ -127,26 +126,6 @@ class EnvironmentProcessor(object):
DEFAULT_DUMP_OPTIONS = ("platform", "framework", "board")
KNOWN_PLATFORMIO_OPTIONS = [
"description", "env_default", "home_dir", "lib_dir", "libdeps_dir",
"include_dir", "src_dir", "build_dir", "data_dir", "test_dir",
"boards_dir", "lib_extra_dirs"
]
KNOWN_ENV_OPTIONS = [
"platform", "framework", "board", "build_flags", "src_build_flags",
"build_unflags", "src_filter", "extra_scripts", "targets",
"upload_port", "upload_protocol", "upload_speed", "upload_flags",
"upload_resetmethod", "lib_deps", "lib_ignore", "lib_extra_dirs",
"lib_ldf_mode", "lib_compat_mode", "lib_archive", "piotest",
"test_transport", "test_filter", "test_ignore", "test_port",
"test_speed", "test_build_project_src", "debug_tool", "debug_port",
"debug_init_cmds", "debug_extra_cmds", "debug_server",
"debug_init_break", "debug_load_cmd", "debug_load_mode",
"debug_svd_path", "monitor_port", "monitor_speed", "monitor_rts",
"monitor_dtr"
]
IGNORE_BUILD_OPTIONS = [
"test_transport", "test_filter", "test_ignore", "test_port",
"test_speed", "debug_port", "debug_init_cmds", "debug_extra_cmds",
@ -157,19 +136,6 @@ class EnvironmentProcessor(object):
REMAPED_OPTIONS = {"framework": "pioframework", "platform": "pioplatform"}
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"
}
RENAMED_PLATFORMS = {"espressif": "espressif8266"}
def __init__(
self, # pylint: disable=R0913
cmd_ctx,
@ -203,7 +169,6 @@ class EnvironmentProcessor(object):
self.name, fg="cyan", bold=True), "; ".join(env_dump)))
click.secho("-" * terminal_width, bold=True)
self.options = self._validate_options(self.options)
result = self._run()
is_error = result['returncode'] != 0
@ -220,39 +185,6 @@ class EnvironmentProcessor(object):
return not is_error
def _validate_options(self, options):
result = {}
for k, v in options.items():
# process obsolete options
if k in self.RENAMED_OPTIONS:
click.secho(
"Warning! `%s` option is deprecated and will be "
"removed in the next release! Please use "
"`%s` instead." % (k, self.RENAMED_OPTIONS[k]),
fg="yellow")
k = self.RENAMED_OPTIONS[k]
# process renamed platforms
if k == "platform" and v in self.RENAMED_PLATFORMS:
click.secho(
"Warning! Platform `%s` is deprecated and will be "
"removed in the next release! Please use "
"`%s` instead." % (v, self.RENAMED_PLATFORMS[v]),
fg="yellow")
v = self.RENAMED_PLATFORMS[v]
# warn about unknown options
unknown_conditions = [
k not in self.KNOWN_ENV_OPTIONS, not k.startswith("custom_"),
not k.startswith("board_")
]
if all(unknown_conditions):
click.secho(
"Detected non-PlatformIO `%s` option in `[env:%s]` section"
% (k, self.name),
fg="yellow")
result[k] = v
return result
def get_build_variables(self):
variables = {"pioenv": self.name}
if self.upload_port:
@ -316,7 +248,7 @@ class EnvironmentProcessor(object):
def _autoinstall_libdeps(ctx, libraries, verbose=False):
if not libraries:
return
storage_dir = util.get_projectlibdeps_dir()
storage_dir = get_projectlibdeps_dir()
ctx.obj = LibraryManager(storage_dir)
if verbose:
click.echo("Library Storage: " + storage_dir)
@ -335,9 +267,8 @@ def _clean_build_dir(build_dir):
proj_hash = calculate_project_hash()
# if project's config is modified
if (isdir(build_dir)
and getmtime(join(util.get_project_dir(),
"platformio.ini")) > getmtime(build_dir)):
if (isdir(build_dir) and getmtime(
join(get_project_dir(), "platformio.ini")) > getmtime(build_dir)):
util.rmtree_(build_dir)
# check project structure
@ -391,21 +322,7 @@ def print_summary(results, start_time):
is_error=not successed)
def check_project_defopts(config):
if not config.has_section("platformio"):
return True
unknown = set(k for k, _ in config.items("platformio")) - set(
EnvironmentProcessor.KNOWN_PLATFORMIO_OPTIONS)
if not unknown:
return True
click.secho(
"Warning! Ignore unknown `%s` option in `[platformio]` section" %
", ".join(unknown),
fg="yellow")
return False
def check_project_envs(config, environments=None):
def check_project_envs(config, environments=None): # FIXME: Remove
if not config.sections():
raise exception.ProjectEnvsNotAvailable()
@ -414,23 +331,3 @@ def check_project_envs(config, environments=None):
if unknown:
raise exception.UnknownEnvNames(", ".join(unknown), ", ".join(known))
return True
def calculate_project_hash():
check_suffixes = (".c", ".cc", ".cpp", ".h", ".hpp", ".s", ".S")
chunks = [__version__]
for d in (util.get_projectsrc_dir(), util.get_projectlib_dir()):
if not isdir(d):
continue
for root, _, files in walk(d):
for f in files:
path = join(root, f)
if path.endswith(check_suffixes):
chunks.append(path)
chunks_to_str = ",".join(sorted(chunks))
if "windows" in util.get_systype():
# Fix issue with useless project rebuilding for case insensitive FS.
# A case of disk drive can differ...
chunks_to_str = chunks_to_str.lower()
return sha1(
chunks_to_str if util.PY2 else chunks_to_str.encode()).hexdigest()

View File

@ -43,11 +43,10 @@ def cli(dev):
get_pip_package(to_develop)], ["platformio", "--version"])
cmd = None
r = None
r = {}
try:
for cmd in cmds:
cmd = [util.get_pythonexe_path(), "-m"] + cmd
r = None
r = util.exec_command(cmd)
# try pip with disabled cache

View File

@ -100,7 +100,7 @@ class FileDownloader(object):
raise FDSizeMismatch(_dlsize, self._fname, self.get_size())
if not sha1:
return
return None
dlsha1 = None
try:
@ -113,11 +113,12 @@ class FileDownloader(object):
dlsha1 = result['out']
except (OSError, ValueError):
pass
if dlsha1:
dlsha1 = dlsha1[1:41] if dlsha1.startswith("\\") else dlsha1[:40]
if sha1 != dlsha1:
raise FDSHASumMismatch(dlsha1, self._fname, sha1)
if not dlsha1:
return None
dlsha1 = dlsha1[1:41] if dlsha1.startswith("\\") else dlsha1[:40]
if sha1.lower() != dlsha1.lower():
raise FDSHASumMismatch(dlsha1, self._fname, sha1)
return True
def _preserve_filemtime(self, lmdate):
timedata = parsedate_tz(lmdate)

View File

@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# pylint: disable=not-an-iterable
class PlatformioException(Exception):
@ -21,7 +19,9 @@ class PlatformioException(Exception):
def __str__(self): # pragma: no cover
if self.MESSAGE:
# pylint: disable=not-an-iterable
return self.MESSAGE.format(*self.args)
return super(PlatformioException, self).__str__()
@ -42,11 +42,16 @@ class UserSideException(PlatformioException):
pass
class AbortedByUser(PlatformioException):
class AbortedByUser(UserSideException):
MESSAGE = "Aborted by user"
#
# Development Platform
#
class UnknownPlatform(PlatformioException):
MESSAGE = "Unknown development platform '{0}'"
@ -63,13 +68,6 @@ class PlatformNotInstalledYet(PlatformioException):
"Use `platformio platform install {0}` command")
class BoardNotDefined(PlatformioException):
MESSAGE = (
"You need to specify board ID using `-b` or `--board` option. "
"Supported boards list is available via `platformio boards` command")
class UnknownBoard(PlatformioException):
MESSAGE = "Unknown board ID '{0}'"
@ -85,54 +83,75 @@ class UnknownFramework(PlatformioException):
MESSAGE = "Unknown framework '{0}'"
class UnknownPackage(PlatformioException):
# Package Manager
class PlatformIOPackageException(PlatformioException):
pass
class UnknownPackage(PlatformIOPackageException):
MESSAGE = "Detected unknown package '{0}'"
class MissingPackageManifest(PlatformioException):
class MissingPackageManifest(PlatformIOPackageException):
MESSAGE = "Could not find one of '{0}' manifest files in the package"
class UndefinedPackageVersion(PlatformioException):
class UndefinedPackageVersion(PlatformIOPackageException):
MESSAGE = ("Could not find a version that satisfies the requirement '{0}'"
" for your system '{1}'")
class PackageInstallError(PlatformioException):
class PackageInstallError(PlatformIOPackageException):
MESSAGE = ("Could not install '{0}' with version requirements '{1}' "
"for your system '{2}'.\n\n"
"Please try this solution -> http://bit.ly/faq-package-manager")
class ExtractArchiveItemError(PlatformioException):
class ExtractArchiveItemError(PlatformIOPackageException):
MESSAGE = (
"Could not extract `{0}` to `{1}`. Try to disable antivirus "
"tool or check this solution -> http://bit.ly/faq-package-manager")
class FDUnrecognizedStatusCode(PlatformioException):
class UnsupportedArchiveType(PlatformIOPackageException):
MESSAGE = "Can not unpack file '{0}'"
class FDUnrecognizedStatusCode(PlatformIOPackageException):
MESSAGE = "Got an unrecognized status code '{0}' when downloaded {1}"
class FDSizeMismatch(PlatformioException):
class FDSizeMismatch(PlatformIOPackageException):
MESSAGE = ("The size ({0:d} bytes) of downloaded file '{1}' "
"is not equal to remote size ({2:d} bytes)")
class FDSHASumMismatch(PlatformioException):
class FDSHASumMismatch(PlatformIOPackageException):
MESSAGE = ("The 'sha1' sum '{0}' of downloaded file '{1}' "
"is not equal to remote '{2}'")
class NotPlatformIOProject(PlatformioException):
#
# Project
#
class PlatformIOProjectException(PlatformioException):
pass
class NotPlatformIOProject(PlatformIOProjectException):
MESSAGE = (
"Not a PlatformIO project. `platformio.ini` file has not been "
@ -140,26 +159,82 @@ class NotPlatformIOProject(PlatformioException):
"please use `platformio init` command")
class UndefinedEnvPlatform(PlatformioException):
class InvalidProjectConf(PlatformIOProjectException):
MESSAGE = ("Invalid '{0}' (project configuration file): '{1}'")
class UndefinedEnvPlatform(PlatformIOProjectException):
MESSAGE = "Please specify platform for '{0}' environment"
class UnsupportedArchiveType(PlatformioException):
MESSAGE = "Can not unpack file '{0}'"
class ProjectEnvsNotAvailable(PlatformioException):
class ProjectEnvsNotAvailable(PlatformIOProjectException):
MESSAGE = "Please setup environments in `platformio.ini` file"
class UnknownEnvNames(PlatformioException):
class UnknownEnvNames(PlatformIOProjectException): # FIXME: UnknownProjectEnvs
MESSAGE = "Unknown environment names '{0}'. Valid names are '{1}'"
#
# Library
#
class LibNotFound(PlatformioException):
MESSAGE = ("Library `{0}` has not been found in PlatformIO Registry.\n"
"You can ignore this message, if `{0}` is a built-in library "
"(included in framework, SDK). E.g., SPI, Wire, etc.")
class NotGlobalLibDir(UserSideException):
MESSAGE = (
"The `{0}` is not a PlatformIO project.\n\n"
"To manage libraries in global storage `{1}`,\n"
"please use `platformio lib --global {2}` or specify custom storage "
"`platformio lib --storage-dir /path/to/storage/ {2}`.\n"
"Check `platformio lib --help` for details.")
class InvalidLibConfURL(PlatformioException):
MESSAGE = "Invalid library config URL '{0}'"
#
# UDEV Rules
#
class InvalidUdevRules(PlatformioException):
pass
class MissedUdevRules(InvalidUdevRules):
MESSAGE = (
"Warning! Please install `99-platformio-udev.rules`. \nMode details: "
"https://docs.platformio.org/en/latest/faq.html#platformio-udev-rules")
class OutdatedUdevRules(InvalidUdevRules):
MESSAGE = (
"Warning! Your `{0}` are outdated. Please update or reinstall them."
"\n Mode details: https://docs.platformio.org"
"/en/latest/faq.html#platformio-udev-rules")
#
# Misc
#
class GetSerialPortsError(PlatformioException):
MESSAGE = "No implementation for your platform ('{0}') available"
@ -175,7 +250,7 @@ class APIRequestError(PlatformioException):
MESSAGE = "[API] {0}"
class InternetIsOffline(PlatformioException):
class InternetIsOffline(UserSideException):
MESSAGE = (
"You are not connected to the Internet.\n"
@ -183,33 +258,6 @@ class InternetIsOffline(PlatformioException):
"to install all dependencies and toolchains.")
class LibNotFound(PlatformioException):
MESSAGE = ("Library `{0}` has not been found in PlatformIO Registry.\n"
"You can ignore this message, if `{0}` is a built-in library "
"(included in framework, SDK). E.g., SPI, Wire, etc.")
class NotGlobalLibDir(PlatformioException):
MESSAGE = (
"The `{0}` is not a PlatformIO project.\n\n"
"To manage libraries in global storage `{1}`,\n"
"please use `platformio lib --global {2}` or specify custom storage "
"`platformio lib --storage-dir /path/to/storage/ {2}`.\n"
"Check `platformio lib --help` for details.")
class InvalidLibConfURL(PlatformioException):
MESSAGE = "Invalid library config URL '{0}'"
class InvalidProjectConf(PlatformioException):
MESSAGE = "Invalid `platformio.ini`, project configuration file: '{0}'"
class BuildScriptNotFound(PlatformioException):
MESSAGE = "Invalid path '{0}' to build script"
@ -237,25 +285,6 @@ class CIBuildEnvsEmpty(PlatformioException):
"predefined environments using `--project-conf` option")
class InvalidUdevRules(PlatformioException):
pass
class MissedUdevRules(InvalidUdevRules):
MESSAGE = (
"Warning! Please install `99-platformio-udev.rules`. \nMode details: "
"https://docs.platformio.org/en/latest/faq.html#platformio-udev-rules")
class OutdatedUdevRules(InvalidUdevRules):
MESSAGE = (
"Warning! Your `{0}` are outdated. Please update or reinstall them."
"\n Mode details: https://docs.platformio.org"
"/en/latest/faq.html#platformio-udev-rules")
class UpgradeError(PlatformioException):
MESSAGE = """{0}
@ -290,7 +319,6 @@ class DebugSupportError(PlatformioException):
class DebugInvalidOptions(PlatformioException):
pass

View File

@ -23,6 +23,9 @@ from click.testing import CliRunner
from platformio import exception, util
from platformio.commands.run import cli as cmd_run
from platformio.project.config import ProjectConfig
from platformio.project.helpers import (
get_projectlib_dir, get_projectlibdeps_dir, get_projectsrc_dir)
class ProjectGenerator(object):
@ -44,15 +47,13 @@ class ProjectGenerator(object):
@util.memoized()
def get_project_env(self):
data = {}
config = util.load_project_config(self.project_dir)
for section in config.sections():
if not section.startswith("env:"):
config = ProjectConfig.get_instance(
join(self.project_dir, "platformio.ini"))
for env in config.envs():
if self.env_name != env:
continue
if self.env_name != section[4:]:
continue
data = {"env_name": section[4:]}
for k, v in config.items(section):
data[k] = v
data = config.items(env=env, as_dict=True)
data['env_name'] = self.env_name
return data
def get_project_build_data(self):
@ -89,7 +90,7 @@ class ProjectGenerator(object):
def get_src_files(self):
result = []
with util.cd(self.project_dir):
for root, _, files in os.walk(util.get_projectsrc_dir()):
for root, _, files in os.walk(get_projectsrc_dir()):
for f in files:
result.append(relpath(join(root, f)))
return result
@ -141,9 +142,9 @@ class ProjectGenerator(object):
"src_files": self.get_src_files(),
"user_home_dir": abspath(expanduser("~")),
"project_dir": self.project_dir,
"project_src_dir": util.get_projectsrc_dir(),
"project_lib_dir": util.get_projectlib_dir(),
"project_libdeps_dir": util.get_projectlibdeps_dir(),
"project_src_dir": get_projectsrc_dir(),
"project_lib_dir": get_projectlib_dir(),
"project_libdeps_dir": get_projectlibdeps_dir(),
"systype": util.get_systype(),
"platformio_path": self._fix_os_path(
sys.argv[0] if isfile(sys.argv[0])

View File

@ -22,6 +22,7 @@ import click
import semantic_version
from platformio import __version__, app, exception, telemetry, util
from platformio.commands import PlatformioCLI
from platformio.commands.lib import lib_update as cmd_lib_update
from platformio.commands.platform import \
platform_install as cmd_platform_install
@ -40,12 +41,12 @@ def on_platformio_start(ctx, force, caller):
set_caller(caller)
telemetry.on_command()
if not in_silence(ctx):
if not in_silence():
after_upgrade(ctx)
def on_platformio_end(ctx, result): # pylint: disable=W0613
if in_silence(ctx):
def on_platformio_end(ctx, result): # pylint: disable=unused-argument
if in_silence():
return
try:
@ -64,14 +65,11 @@ def on_platformio_exception(e):
telemetry.on_exception(e)
def in_silence(ctx=None):
ctx = ctx or app.get_session_var("command_ctx")
if not ctx:
return True
return ctx.args and any([
ctx.args[0] == "debug" and "--interpreter" in " ".join(ctx.args),
ctx.args[0] == "upgrade", "--json-output" in ctx.args,
"--version" in ctx.args
def in_silence():
args = PlatformioCLI.leftover_args
return args and any([
args[0] == "debug" and "--interpreter" in " ".join(args),
args[0] == "upgrade", "--json-output" in args, "--version" in args
])

View File

@ -24,11 +24,12 @@ from platformio import __version__, exception, util
from platformio.managers.package import PackageManager
CORE_PACKAGES = {
"contrib-piohome": "^2.0.0",
"contrib-pysite": "~2.%d%d.0" % (sys.version_info[0], sys.version_info[1]),
"tool-pioplus": "^2.0.2",
"contrib-piohome": "^2.0.1",
"contrib-pysite":
"~2.%d%d.190418" % (sys.version_info[0], sys.version_info[1]),
"tool-pioplus": "^2.2.0",
"tool-unity": "~1.20403.0",
"tool-scons": "~2.20501.7" if util.PY2 else "~3.30003.0"
"tool-scons": "~2.20501.7" if util.PY2 else "~3.30005.0"
}
PIOPLUS_AUTO_UPDATES_MAX = 100

View File

@ -164,7 +164,7 @@ class LibraryManager(BasePkgManager):
semver_spec = self.parse_semver_spec(
requirements) if requirements else None
item = None
item = {}
for v in versions:
semver_new = self.parse_semver_version(v['name'])

View File

@ -25,6 +25,7 @@ import semantic_version
from platformio import __version__, app, exception, util
from platformio.managers.core import get_core_package_dir
from platformio.managers.package import BasePkgManager, PackageManager
from platformio.project.helpers import get_projectboards_dir
try:
from urllib.parse import quote
@ -566,7 +567,7 @@ class PlatformBase( # pylint: disable=too-many-public-methods
self._BOARDS_CACHE[board_id] = config
bdirs = [
util.get_projectboards_dir(),
get_projectboards_dir(),
join(util.get_home_dir(), "boards"),
join(self.get_dir(), "boards"),
]

View File

@ -0,0 +1,13 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

View File

@ -0,0 +1,329 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import glob
import json
import os
import re
from os.path import isfile
import click
from platformio import exception
try:
import ConfigParser as ConfigParser
except ImportError:
import configparser as ConfigParser
CONFIG_HEADER = """;PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
"""
KNOWN_PLATFORMIO_OPTIONS = [
"description",
"env_default",
"extra_configs",
# Dirs
"home_dir",
"lib_dir",
"libdeps_dir",
"include_dir",
"src_dir",
"build_dir",
"data_dir",
"test_dir",
"boards_dir",
"lib_extra_dirs"
]
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",
# 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):
VARTPL_RE = re.compile(r"\$\{([^\.\}]+)\.([^\}]+)\}")
expand_interpolations = True
_instances = {}
_parser = None
_parsed = []
@staticmethod
def parse_multi_values(items):
result = []
if not items:
return result
inline_comment_re = re.compile(r"\s+;.*$")
for item in items.split("\n" if "\n" in items else ", "):
item = item.strip()
# comment
if not item or item.startswith((";", "#")):
continue
if ";" in item:
item = inline_comment_re.sub("", item).strip()
result.append(item)
return result
@staticmethod
def get_instance(path):
if path not in ProjectConfig._instances:
ProjectConfig._instances[path] = ProjectConfig(path)
return ProjectConfig._instances[path]
@staticmethod
def reset_instances():
ProjectConfig._instances = {}
def __init__(self, path, parse_extra=True, expand_interpolations=True):
self.path = path
self.expand_interpolations = expand_interpolations
self._parsed = []
self._parser = ConfigParser.ConfigParser()
if isfile(path):
self.read(path, parse_extra)
def __getattr__(self, name):
return getattr(self._parser, name)
def read(self, path, parse_extra=True):
if path in self._parsed:
return
self._parsed.append(path)
try:
self._parser.read(path)
except ConfigParser.Error as e:
raise exception.InvalidProjectConf(path, str(e))
if not parse_extra:
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 item in glob.glob(pattern):
self.read(item)
def options(self, section=None, env=None):
assert section or env
if not section:
section = "env:" + env
options = self._parser.options(section)
# handle global options from [env]
if ((env or section.startswith("env:"))
and self._parser.has_section("env")):
for option in self._parser.options("env"):
if option not in options:
options.append(option)
return options
def has_option(self, section, option):
if self._parser.has_option(section, option):
return True
return (section.startswith("env:") and self._parser.has_section("env")
and self._parser.has_option("env", option))
def items(self, section=None, env=None, as_dict=False):
assert section or env
if not section:
section = "env:" + env
if as_dict:
return {
option: self.get(section, option)
for option in self.options(section)
}
return [(option, self.get(section, option))
for option in self.options(section)]
def get(self, section, option):
if not self.expand_interpolations:
return self._parser.get(section, option)
try:
value = self._parser.get(section, option)
except ConfigParser.NoOptionError:
value = self._parser.get("env", option)
except ConfigParser.Error as e:
raise exception.InvalidProjectConf(self.path, str(e))
if "${" not in value or "}" not in value:
return value
return self.VARTPL_RE.sub(self._re_sub_handler, value)
def _re_sub_handler(self, match):
section, option = match.group(1), match.group(2)
if section == "sysenv":
return os.getenv(option)
return self.get(section, option)
def getlist(self, section, option):
return self.parse_multi_values(self.get(section, option))
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")
def validate(self, envs=None):
if not isfile(self.path):
raise exception.NotPlatformIOProject(self.path)
# check envs
known = set(self.envs())
if not known:
raise exception.ProjectEnvsNotAvailable()
unknown = set((envs or []) + self.default_envs()) - known
if unknown:
raise exception.UnknownEnvNames(", ".join(unknown),
", ".join(known))
return self.validate_options()
def validate_options(self):
warnings = set()
# check [platformio] section
if self._parser.has_section("platformio"):
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))
# check [env:*] sections
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]))
# rename on-the-fly
self._parser.set(section, RENAMED_OPTIONS[option],
self._parser.get(section, option))
self._parser.remove_option(section, option)
continue
# unknown
unknown_conditions = [
option not in KNOWN_ENV_OPTIONS,
not option.startswith("custom_"),
not option.startswith("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
def to_json(self):
result = {}
for section in self.sections():
result[section] = self.items(section, as_dict=True)
return json.dumps(result)
def save(self, path=None):
with open(path or self.path, "w") as fp:
fp.write(CONFIG_HEADER)
self._parser.write(fp)

View File

@ -0,0 +1,139 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
from hashlib import sha1
from os import walk
from os.path import abspath, dirname, expanduser, isdir, isfile, join
from platformio import __version__
from platformio.project.config import ProjectConfig
PY2 = sys.version_info[0] == 2
def get_project_dir():
return os.getcwd()
def is_platformio_project(project_dir=None):
if not project_dir:
project_dir = get_project_dir()
return isfile(join(project_dir, "platformio.ini"))
def find_project_dir_above(path):
if isfile(path):
path = dirname(path)
if is_platformio_project(path):
return path
if isdir(dirname(path)):
return find_project_dir_above(dirname(path))
return None
def get_project_optional_dir(name, default=None):
paths = None
var_name = "PLATFORMIO_%s" % name.upper()
if var_name in os.environ:
paths = os.getenv(var_name)
else:
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
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(
"$PROJECT_HASH",
sha1(project_dir if PY2 else project_dir.encode()).hexdigest()
[:10])
return paths
def get_projectlib_dir():
return get_project_optional_dir("lib_dir", join(get_project_dir(), "lib"))
def get_projectlibdeps_dir():
return get_project_optional_dir("libdeps_dir",
join(get_project_dir(), ".piolibdeps"))
def get_projectsrc_dir():
return get_project_optional_dir("src_dir", join(get_project_dir(), "src"))
def get_projectinclude_dir():
return get_project_optional_dir("include_dir",
join(get_project_dir(), "include"))
def get_projecttest_dir():
return get_project_optional_dir("test_dir", join(get_project_dir(),
"test"))
def get_projectboards_dir():
return get_project_optional_dir("boards_dir",
join(get_project_dir(), "boards"))
def get_projectbuild_dir(force=False):
path = get_project_optional_dir("build_dir",
join(get_project_dir(), ".pioenvs"))
try:
if not isdir(path):
os.makedirs(path)
except Exception as e: # pylint: disable=broad-except
if not force:
raise Exception(e)
return path
def get_projectdata_dir():
return get_project_optional_dir("data_dir", join(get_project_dir(),
"data"))
def calculate_project_hash():
check_suffixes = (".c", ".cc", ".cpp", ".h", ".hpp", ".s", ".S")
chunks = [__version__]
for d in (get_projectsrc_dir(), get_projectlib_dir()):
if not isdir(d):
continue
for root, _, files in walk(d):
for f in files:
path = join(root, f)
if path.endswith(check_suffixes):
chunks.append(path)
chunks_to_str = ",".join(sorted(chunks))
if sys.platform == "win32":
# Fix issue with useless project rebuilding for case insensitive FS.
# A case of disk drive can differ...
chunks_to_str = chunks_to_str.lower()
return sha1(chunks_to_str if PY2 else chunks_to_str.encode()).hexdigest()

View File

@ -1,9 +0,0 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

View File

@ -27,6 +27,7 @@ import click
import requests
from platformio import __version__, app, exception, util
from platformio.commands import PlatformioCLI
try:
import queue
@ -133,10 +134,10 @@ class MeasurementProtocol(TelemetryBase):
return _arg
return None
if not app.get_session_var("command_ctx"):
return
ctx_args = app.get_session_var("command_ctx").args
args = [str(s).lower() for s in ctx_args if not str(s).startswith("-")]
args = [
str(arg).lower() for arg in PlatformioCLI.leftover_args
if not str(arg).startswith("-")
]
if not args:
return
cmd_path = args[:1]
@ -342,12 +343,9 @@ def on_exception(e):
return text.strip()
skip_conditions = [
isinstance(e, cls)
for cls in (IOError, exception.ReturnErrorCode,
exception.AbortedByUser, exception.NotGlobalLibDir,
exception.InternetIsOffline,
exception.NotPlatformIOProject,
exception.UserSideException)
isinstance(e, cls) for cls in (IOError, exception.ReturnErrorCode,
exception.UserSideException,
exception.PlatformIOProjectException)
]
try:
skip_conditions.append("[API] Account: " in str(e))

View File

@ -23,7 +23,6 @@ import sys
import time
from functools import wraps
from glob import glob
from hashlib import sha1
from os.path import (abspath, basename, dirname, expanduser, isdir, isfile,
join, normpath, splitdrive)
from shutil import rmtree
@ -33,52 +32,21 @@ import click
import requests
from platformio import __apiurl__, __version__, exception
from platformio.project.config import ProjectConfig
from platformio.project.helpers import ( # pylint: disable=unused-import
get_project_dir, get_project_optional_dir, get_projectboards_dir,
get_projectbuild_dir, get_projectdata_dir, get_projectlib_dir,
get_projectsrc_dir, get_projecttest_dir, is_platformio_project)
# pylint: disable=too-many-ancestors
# FIXME: check platformio.project.helpers imports
PY2 = sys.version_info[0] == 2
if PY2:
import ConfigParser as ConfigParser
string_types = basestring # pylint: disable=undefined-variable
else:
import configparser as ConfigParser
string_types = str
class ProjectConfig(ConfigParser.ConfigParser):
VARTPL_RE = re.compile(r"\$\{([^\.\}]+)\.([^\}]+)\}")
def items(self, section, **_): # pylint: disable=arguments-differ
items = []
for option in ConfigParser.ConfigParser.options(self, section):
items.append((option, self.get(section, option)))
return items
def get( # pylint: disable=arguments-differ
self, section, option, **kwargs):
try:
value = ConfigParser.ConfigParser.get(self, section, option,
**kwargs)
except ConfigParser.Error as e:
raise exception.InvalidProjectConf(str(e))
if "${" not in value or "}" not in value:
return value
return self.VARTPL_RE.sub(self._re_sub_handler, value)
def _re_sub_handler(self, match):
section, option = match.group(1), match.group(2)
if section in ("env", "sysenv") and not self.has_section(section):
if section == "env":
click.secho(
"Warning! Access to system environment variable via "
"`${{env.{0}}}` is deprecated. Please use "
"`${{sysenv.{0}}}` instead".format(option),
fg="yellow")
return os.getenv(option)
return self.get(section, option)
class AsyncPipe(Thread):
def __init__(self, outcallback=None):
@ -208,40 +176,6 @@ def pioversion_to_intstr():
return [int(i) for i in vermatch.group(1).split(".")[:3]]
def get_project_optional_dir(name, default=None):
paths = None
var_name = "PLATFORMIO_%s" % name.upper()
if var_name in os.environ:
paths = os.getenv(var_name)
else:
try:
config = load_project_config()
if (config.has_section("platformio")
and config.has_option("platformio", name)):
paths = config.get("platformio", name)
except exception.NotPlatformIOProject:
pass
if not paths:
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(
"$PROJECT_HASH",
sha1(project_dir if PY2 else project_dir.encode()).hexdigest()
[:10])
return paths
def get_home_dir():
home_dir = get_project_optional_dir("home_dir",
join(expanduser("~"), ".platformio"))
@ -278,103 +212,17 @@ def get_source_dir():
return dirname(curpath)
def get_project_dir():
return os.getcwd()
def find_project_dir_above(path):
if isfile(path):
path = dirname(path)
if is_platformio_project(path):
return path
if isdir(dirname(path)):
return find_project_dir_above(dirname(path))
return None
def is_platformio_project(project_dir=None):
if not project_dir:
project_dir = get_project_dir()
return isfile(join(project_dir, "platformio.ini"))
def get_projectlib_dir():
return get_project_optional_dir("lib_dir", join(get_project_dir(), "lib"))
def get_projectlibdeps_dir():
return get_project_optional_dir("libdeps_dir",
join(get_project_dir(), ".piolibdeps"))
def get_projectsrc_dir():
return get_project_optional_dir("src_dir", join(get_project_dir(), "src"))
def get_projectinclude_dir():
return get_project_optional_dir("include_dir",
join(get_project_dir(), "include"))
def get_projecttest_dir():
return get_project_optional_dir("test_dir", join(get_project_dir(),
"test"))
def get_projectboards_dir():
return get_project_optional_dir("boards_dir",
join(get_project_dir(), "boards"))
def get_projectbuild_dir(force=False):
path = get_project_optional_dir("build_dir",
join(get_project_dir(), ".pioenvs"))
try:
if not isdir(path):
os.makedirs(path)
except Exception as e: # pylint: disable=broad-except
if not force:
raise Exception(e)
return path
# compatibility with PIO Core+
get_projectpioenvs_dir = get_projectbuild_dir
def get_projectdata_dir():
return get_project_optional_dir("data_dir", join(get_project_dir(),
"data"))
def load_project_config(path=None):
def load_project_config(path=None): # FIXME: Remove
if not path or isdir(path):
path = join(path or get_project_dir(), "platformio.ini")
if not isfile(path):
raise exception.NotPlatformIOProject(
dirname(path) if path.endswith("platformio.ini") else path)
cp = ProjectConfig()
try:
cp.read(path)
except ConfigParser.Error as e:
raise exception.InvalidProjectConf(str(e))
return cp
return ProjectConfig(path)
def parse_conf_multi_values(items):
result = []
if not items:
return result
inline_comment_re = re.compile(r"\s+;.*$")
for item in items.split("\n" if "\n" in items else ", "):
item = item.strip()
# comment
if not item or item.startswith((";", "#")):
continue
if ";" in item:
item = inline_comment_re.sub("", item).strip()
result.append(item)
return result
def parse_conf_multi_values(items): # FIXME: Remove
return ProjectConfig.parse_multi_values(items)
def change_filemtime(path, mtime):
@ -611,7 +459,7 @@ def _get_api_result(
auth=None):
from platformio.app import get_setting
result = None
result = {}
r = None
verify_ssl = sys.version_info >= (2, 7, 9)

View File

@ -84,176 +84,176 @@ SUBSYSTEM=="tty", ATTRS{interface}=="Black Magic GDB Server"
SUBSYSTEM=="tty", ATTRS{interface}=="Black Magic UART Port"
# opendous and estick
ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204f", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204f", MODE="0666"
# Original FT232/FT245 VID:PID
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="0666"
# Original FT2232 VID:PID
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="0666"
# Original FT4232 VID:PID
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="0666"
# Original FT232H VID:PID
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="0666"
# DISTORTEC JTAG-lock-pick Tiny 2
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8220", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8220", MODE="0666"
# TUMPA, TUMPA Lite
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a98", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a99", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a98", MODE="0666"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a99", MODE="0666"
# XDS100v2
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d0", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d0", MODE="0666"
# Xverve Signalyzer Tool (DT-USB-ST), Signalyzer LITE (DT-USB-SLITE)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca1", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="0666"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca1", MODE="0666"
# TI/Luminary Stellaris Evaluation Board FTDI (several)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd9", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd9", MODE="0666"
# TI/Luminary Stellaris In-Circuit Debug Interface FTDI (ICDI) Board
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcda", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcda", MODE="0666"
# egnite Turtelizer 2
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bdc8", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bdc8", MODE="0666"
# Section5 ICEbear
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c140", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c140", MODE="0666"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="0666"
# Amontec JTAGkey and JTAGkey-tiny
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="0666"
# TI ICDI
ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="0666"
# STLink v1
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3744", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3744", MODE="0666"
# STLink v2
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE="0666"
# STLink v2-1
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", MODE="0666"
# Hilscher NXHX Boards
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="0666"
# Hitex STR9-comStick
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002c", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002c", MODE="0666"
# Hitex STM32-PerformanceStick
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="0666"
# Altera USB Blaster
ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6001", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6001", MODE="0666"
# Amontec JTAGkey-HiSpeed
ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="0666"
# SEGGER J-Link
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0101", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0102", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0103", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0104", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0105", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0107", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0108", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1010", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1011", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1012", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1013", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1014", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1015", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1016", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1017", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1018", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0101", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0102", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0103", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0104", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0105", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0107", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0108", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1010", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1011", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1012", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1013", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1014", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1015", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1016", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1017", MODE="0666"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1018", MODE="0666"
# Raisonance RLink
ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="0666"
# Debug Board for Neo1973
ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="0666"
# Olimex ARM-USB-OCD
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="0666"
# Olimex ARM-USB-OCD-TINY
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0004", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0004", MODE="0666"
# Olimex ARM-JTAG-EW
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="001e", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="001e", MODE="0666"
# Olimex ARM-USB-OCD-TINY-H
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="0666"
# Olimex ARM-USB-OCD-H
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002b", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002b", MODE="0666"
# USBprog with OpenOCD firmware
ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="0666"
# TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board
ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="0666"
# Marvell Sheevaplug
ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="0666"
# Keil Software, Inc. ULink
ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2710", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2710", MODE="0666"
# CMSIS-DAP compatible adapters
ATTRS{product}=="*CMSIS-DAP*", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{product}=="*CMSIS-DAP*", MODE="0666"
#SEGGER J-LIK
ATTR{idProduct}=="1001", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1002", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1003", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1004", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1005", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1006", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1007", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1008", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1009", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="100a", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="100b", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="100c", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="100d", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="100e", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="100f", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1010", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1011", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1012", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1013", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1014", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1015", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1016", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1017", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1018", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1019", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="101a", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="101b", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="101c", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="101d", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="101e", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="101f", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1020", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1021", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1022", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1023", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1024", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1025", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1026", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1027", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1028", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1029", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="102a", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="102b", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="102c", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="102d", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="102e", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="102f", ATTR{idVendor}=="1366", MODE="666"
ATTR{idProduct}=="1001", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1002", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1003", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1004", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1005", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1006", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1007", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1008", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1009", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="100a", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="100b", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="100c", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="100d", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="100e", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="100f", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1010", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1011", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1012", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1013", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1014", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1015", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1016", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1017", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1018", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1019", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="101a", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="101b", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="101c", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="101d", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="101e", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="101f", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1020", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1021", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1022", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1023", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1024", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1025", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1026", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1027", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1028", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="1029", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="102a", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="102b", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="102c", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="102d", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="102e", ATTR{idVendor}=="1366", MODE="0666"
ATTR{idProduct}=="102f", ATTR{idVendor}=="1366", MODE="0666"

View File

@ -19,7 +19,7 @@ from platformio import (__author__, __description__, __email__, __license__,
install_requires = [
"bottle<0.13",
"click>=5,<6",
"click>=5,<8",
"colorama",
"pyserial>=3,<4,!=3.3",
"requests>=2.4.0,<3",
@ -41,7 +41,6 @@ setup(
packages=find_packages() + ["scripts"],
package_data={
"platformio": [
"projectconftpl.ini",
"ide/tpls/*/.*.tpl",
"ide/tpls/*/*.tpl",
"ide/tpls/*/*/*.tpl",

View File

@ -57,8 +57,8 @@ def test_init_duplicated_boards(clirunner, validate_cliresult, tmpdir):
def test_init_ide_without_board(clirunner, tmpdir):
with tmpdir.as_cwd():
result = clirunner.invoke(cmd_init, ["--ide", "atom"])
assert result.exit_code == -1
assert isinstance(result.exception, exception.BoardNotDefined)
assert result.exit_code != 0
assert isinstance(result.exception, exception.ProjectEnvsNotAvailable)
def test_init_ide_atom(clirunner, validate_cliresult, tmpdir):

View File

@ -16,8 +16,11 @@ import json
import re
from platformio import exception
from platformio.commands import PlatformioCLI
from platformio.commands.lib import cli as cmd_lib
PlatformioCLI.leftover_args = ["--json-output"] # hook for click
def test_search(clirunner, validate_cliresult):
result = clirunner.invoke(cmd_lib, ["search", "DHT22"])
@ -58,7 +61,6 @@ def test_global_install_archive(clirunner, validate_cliresult,
isolated_pio_home):
result = clirunner.invoke(cmd_lib, [
"-g", "install",
"http://www.airspayce.com/mikem/arduino/RadioHead/RadioHead-1.62.zip",
"https://github.com/bblanchon/ArduinoJson/archive/v5.8.2.zip",
"https://github.com/bblanchon/ArduinoJson/archive/v5.8.2.zip@5.8.2",
"SomeLib=http://dl.platformio.org/libraries/archives/0/9540.tar.gz",
@ -74,10 +76,7 @@ def test_global_install_archive(clirunner, validate_cliresult,
assert result.exit_code != 0
items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()]
items2 = [
"RadioHead-1.62", "ArduinoJson", "SomeLib_ID54",
"OneWire_ID1", "ESP32WebServer"
]
items2 = ["ArduinoJson", "SomeLib_ID54", "OneWire_ID1", "ESP32WebServer"]
assert set(items1) >= set(items2)
@ -123,7 +122,7 @@ def test_install_duplicates(clirunner, validate_cliresult, without_internet):
# archive
result = clirunner.invoke(cmd_lib, [
"-g", "install",
"http://www.airspayce.com/mikem/arduino/RadioHead/RadioHead-1.62.zip"
"https://github.com/Pedroalbuquerque/ESP32WebServer/archive/master.zip"
])
validate_cliresult(result)
assert "is already installed" in result.output
@ -145,7 +144,7 @@ def test_global_lib_list(clirunner, validate_cliresult):
("Source: https://github.com/Pedroalbuquerque/ESP32WebServer/archive/master.zip",
"Version: 5.10.1",
"Source: git+https://github.com/gioblu/PJON.git#3.0",
"Version: 1fb26fd", "RadioHead-1.62")
"Version: 1fb26fd")
])
result = clirunner.invoke(cmd_lib, ["-g", "list", "--json-output"])
@ -158,10 +157,9 @@ def test_global_lib_list(clirunner, validate_cliresult):
items1 = [i['name'] for i in json.loads(result.output)]
items2 = [
"ESP32WebServer", "ArduinoJson", "ArduinoJson", "ArduinoJson",
"ArduinoJson", "AsyncMqttClient", "AsyncTCP", "SomeLib",
"ESPAsyncTCP", "NeoPixelBus", "OneWire", "PJON", "PJON",
"PubSubClient", "RFcontrol", "RadioHead-1.62", "platformio-libmirror",
"rs485-nodeproto"
"ArduinoJson", "AsyncMqttClient", "AsyncTCP", "SomeLib", "ESPAsyncTCP",
"NeoPixelBus", "OneWire", "PJON", "PJON", "PubSubClient", "RFcontrol",
"platformio-libmirror", "rs485-nodeproto"
]
assert sorted(items1) == sorted(items2)
@ -169,9 +167,9 @@ def test_global_lib_list(clirunner, validate_cliresult):
"{name}@{version}".format(**item) for item in json.loads(result.output)
]
versions2 = [
'ArduinoJson@5.8.2', 'ArduinoJson@5.10.1', 'AsyncMqttClient@0.8.2',
'NeoPixelBus@2.2.4', 'PJON@07fe9aa', 'PJON@1fb26fd',
'PubSubClient@bef5814', 'RFcontrol@77d4eb3f8a', 'RadioHead-1.62@0.0.0'
"ArduinoJson@5.8.2", "ArduinoJson@5.10.1", "AsyncMqttClient@0.8.2",
"NeoPixelBus@2.2.4", "PJON@07fe9aa", "PJON@1fb26fd",
"PubSubClient@bef5814", "RFcontrol@77d4eb3f8a"
]
assert set(versions1) >= set(versions2)
@ -202,7 +200,7 @@ def test_global_lib_update(clirunner, validate_cliresult):
# update rest libraries
result = clirunner.invoke(cmd_lib, ["-g", "update"])
validate_cliresult(result)
assert result.output.count("[Detached]") == 6
assert result.output.count("[Detached]") == 5
assert result.output.count("[Up-to-date]") == 11
assert "Uninstalling RFcontrol @ 77d4eb3f8a" in result.output
@ -232,10 +230,10 @@ def test_global_lib_uninstall(clirunner, validate_cliresult,
items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()]
items2 = [
"RadioHead-1.62", "rs485-nodeproto", "platformio-libmirror",
"rs485-nodeproto", "platformio-libmirror",
"PubSubClient", "ArduinoJson@src-69ebddd821f771debe7ee734d3c7fa81",
"ESPAsyncTCP_ID305", "SomeLib_ID54", "NeoPixelBus_ID547",
"PJON", "AsyncMqttClient_ID346", "ArduinoJson_ID64",
"ESPAsyncTCP_ID305", "SomeLib_ID54", "NeoPixelBus_ID547", "PJON",
"AsyncMqttClient_ID346", "ArduinoJson_ID64",
"PJON@src-79de467ebe19de18287becff0a1fb42d", "ESP32WebServer"
]
assert set(items1) == set(items2)

View File

@ -38,14 +38,14 @@ def test_search_raw_output(clirunner, validate_cliresult):
def test_install_unknown_version(clirunner):
result = clirunner.invoke(cli_platform.platform_install,
["atmelavr@99.99.99"])
assert result.exit_code == -1
assert result.exit_code != 0
assert isinstance(result.exception, exception.UndefinedPackageVersion)
def test_install_unknown_from_registry(clirunner):
result = clirunner.invoke(cli_platform.platform_install,
["unknown-platform"])
assert result.exit_code == -1
assert result.exit_code != 0
assert isinstance(result.exception, exception.UnknownPackage)

View File

@ -24,8 +24,10 @@ from platformio import util
def validate_cliresult():
def decorator(result):
assert result.exit_code == 0, result.output
assert not result.exception, result.output
assert result.exit_code == 0, "{} => {}".format(
result.exception, result.output)
assert not result.exception, "{} => {}".format(result.exception,
result.output)
return decorator

View File

@ -18,6 +18,12 @@ import requests
from platformio import exception, util
def test_platformio_cli():
result = util.exec_command(["pio", "--help"])
assert result['returncode'] == 0
assert "Usage: pio [OPTIONS] COMMAND [ARGS]..." in result['out']
def test_ping_internet_ips():
for ip in util.PING_INTERNET_IPS:
requests.get("http://%s" % ip, allow_redirects=False, timeout=2)

116
tests/test_projectconf.py Normal file
View File

@ -0,0 +1,116 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from platformio.project.config import ProjectConfig
BASE_CONFIG = """
[platformio]
env_default = base, extra_2
extra_configs =
extra_envs.ini
extra_debug.ini
# global options per [env:*]
[env]
monitor_speed = 115200
lib_deps = Lib1, Lib2
lib_ignore = ${custom.lib_ignore}
[custom]
debug_flags = -D RELEASE
lib_flags = -lc -lm
extra_flags = ${sysenv.__PIO_TEST_CNF_EXTRA_FLAGS}
lib_ignore = LibIgnoreCustom
[env:base]
build_flags = ${custom.debug_flags} ${custom.extra_flags}
"""
EXTRA_ENVS_CONFIG = """
[env:extra_1]
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
"""
EXTRA_DEBUG_CONFIG = """
# Override original "custom.debug_flags"
[custom]
debug_flags = -D DEBUG=1
[env:extra_2]
build_flags = -Og
"""
def test_parser(tmpdir):
tmpdir.join("platformio.ini").write(BASE_CONFIG)
tmpdir.join("extra_envs.ini").write(EXTRA_ENVS_CONFIG)
tmpdir.join("extra_debug.ini").write(EXTRA_DEBUG_CONFIG)
config = None
with tmpdir.as_cwd():
config = ProjectConfig(tmpdir.join("platformio.ini").strpath)
assert config
# sections
assert config.sections() == [
"platformio", "env", "custom", "env:base", "env:extra_1", "env:extra_2"
]
# envs
assert config.envs() == ["base", "extra_1", "extra_2"]
assert config.default_envs() == ["base", "extra_2"]
# options
assert config.options(env="base") == [
"build_flags", "monitor_speed", "lib_deps", "lib_ignore"
]
# has_option
assert config.has_option("env:base", "monitor_speed")
assert not config.has_option("custom", "monitor_speed")
# sysenv
assert config.get("custom", "extra_flags") == ""
os.environ["__PIO_TEST_CNF_EXTRA_FLAGS"] = "-L /usr/local/lib"
assert config.get("custom", "extra_flags") == "-L /usr/local/lib"
# 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_2", "monitor_speed") == "115200"
assert config.get("env:base",
"build_flags") == ("-D DEBUG=1 -L /usr/local/lib")
# 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")]