Merge branch 'release/v4.0.3'

This commit is contained in:
Ivan Kravets
2019-08-30 15:41:59 +03:00
26 changed files with 198 additions and 134 deletions

View File

@ -6,6 +6,17 @@ Release Notes
PlatformIO 4.0
--------------
4.0.3 (2019-08-30)
~~~~~~~~~~~~~~~~~~
* Added support for multi-environment PlatformIO project for `CLion IDE <http://docs.platformio.org/page/ide/clion.html>`__ (`issue #2824 <https://github.com/platformio/platformio-core/issues/2824>`_)
* Generate ``.ccls`` LSP file for `Vim <http://docs.platformio.org/en/page/vim.html>`__ cross references, hierarchies, completion and semantic highlighting (`issue #2952 <https://github.com/platformio/platformio-core/issues/2952>`_)
* Added support for `PLATFORMIO_DISABLE_COLOR <http://docs.platformio.org/page/envvars.html#envvar-PLATFORMIO_DISABLE_COLOR>`__ system environment variable which disables color ANSI-codes in a terminal output (`issue #2956 <https://github.com/platformio/platformio-core/issues/2956>`_)
* Updated SCons tool to 3.1.1
* Remove ProjectConfig cache when "platformio.ini" was modified outside
* Fixed an issue with PIO Unified Debugger on Windows OS when debug server is piped
* Fixed an issue when `--upload-port <http://docs.platformio.org/page/userguide/cmd_run.html#cmdoption-platformio-run-upload-port>`__ CLI flag does not override declared `upload_port <http://docs.platformio.org/page/projectconf/section_env_upload.html#upload-port>`__ option in `"platformio.ini" (Project Configuration File) <https://docs.platformio.org/page/projectconf.html>`__
4.0.2 (2019-08-23)
~~~~~~~~~~~~~~~~~~

2
docs

Submodule docs updated: 3f5d12ca25...704ff85c7d

View File

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

View File

@ -55,13 +55,15 @@ def configure():
except (AttributeError, ImportError):
pass
# handle PLATFORMIO_FORCE_COLOR
if str(os.getenv("PLATFORMIO_FORCE_COLOR", "")).lower() == "true":
try:
try:
if str(os.getenv("PLATFORMIO_DISABLE_COLOR", "")).lower() == "true":
# pylint: disable=protected-access
click._compat.isatty = lambda stream: False
elif str(os.getenv("PLATFORMIO_FORCE_COLOR", "")).lower() == "true":
# pylint: disable=protected-access
click._compat.isatty = lambda stream: True
except: # pylint: disable=bare-except
pass
except: # pylint: disable=bare-except
pass
# Handle IOError issue with VSCode's Terminal (Windows)
click_echo_origin = [click.echo, click.secho]

View File

@ -140,6 +140,8 @@ def DumpIDEData(env, projenv):
LINTCXXCOM = "$CXXFLAGS $CCFLAGS $CPPFLAGS"
data = {
"env_name":
env['PIOENV'],
"libsource_dirs": [env.subst(l) for l in env.GetLibSourceDirs()],
"defines":
_dump_defines(env),

View File

@ -300,20 +300,8 @@ class LibBuilderBase(object):
])
return items
def _validate_search_files(self, search_files=None):
if not search_files:
search_files = []
assert isinstance(search_files, list)
_search_files = []
for path in search_files:
if path not in self._processed_files:
_search_files.append(path)
self._processed_files.append(path)
return _search_files
def _get_found_includes(self, search_files=None):
def _get_found_includes( # pylint: disable=too-many-branches
self, search_files=None):
# all include directories
if not LibBuilderBase._INCLUDE_DIRS_CACHE:
LibBuilderBase._INCLUDE_DIRS_CACHE = []
@ -326,7 +314,11 @@ class LibBuilderBase(object):
include_dirs.extend(LibBuilderBase._INCLUDE_DIRS_CACHE)
result = []
for path in self._validate_search_files(search_files):
for path in (search_files or []):
if path in self._processed_files:
continue
self._processed_files.append(path)
try:
assert "+" in self.lib_ldf_mode
candidates = LibBuilderBase.CCONDITIONAL_SCANNER(
@ -334,6 +326,11 @@ class LibBuilderBase(object):
self.env,
tuple(include_dirs),
depth=self.CCONDITIONAL_SCANNER_DEPTH)
# mark candidates already processed via Conditional Scanner
self._processed_files.extend([
c.get_abspath() for c in candidates
if c.get_abspath() not in self._processed_files
])
except Exception as e: # pylint: disable=broad-except
if self.verbose and "+" in self.lib_ldf_mode:
sys.stderr.write(

View File

@ -32,7 +32,8 @@ def GetProjectOption(env, option, default=None):
def LoadProjectOptions(env):
for option, value in env.GetProjectOptions():
option_meta = ProjectOptions.get("env." + option)
if not option_meta or not option_meta.buildenvvar:
if (not option_meta or not option_meta.buildenvvar
or option_meta.buildenvvar in env):
continue
env[option_meta.buildenvvar] = value

View File

@ -19,7 +19,7 @@ from hashlib import sha1
from io import BytesIO
from os.path import isfile
from platformio import exception, util
from platformio import exception, fs, util
from platformio.commands.platform import \
platform_install as cmd_platform_install
from platformio.commands.run import cli as cmd_run
@ -165,11 +165,11 @@ def configure_esp32_load_cmds(debug_options, configuration):
mon_cmds = [
'monitor program_esp32 "{{{path}}}" {offset} verify'.format(
path=item['path'], offset=item['offset'])
path=fs.to_unix_path(item['path']), offset=item['offset'])
for item in configuration.get("flash_extra_images")
]
mon_cmds.append('monitor program_esp32 "{%s.bin}" 0x10000 verify' %
configuration['prog_path'][:-4])
fs.to_unix_path(configuration['prog_path'][:-4]))
return mon_cmds

View File

@ -17,6 +17,7 @@ import signal
import click
from twisted.internet import protocol # pylint: disable=import-error
from platformio import fs
from platformio.compat import string_types
from platformio.proc import get_pythonexe_path
from platformio.project.helpers import get_project_core_dir
@ -38,6 +39,10 @@ class BaseProcess(protocol.ProcessProtocol, object):
_patterns = self.COMMON_PATTERNS.copy()
_patterns.update(patterns or {})
for key, value in _patterns.items():
if key.endswith(("_DIR", "_PATH")):
_patterns[key] = fs.to_unix_path(value)
def _replace(text):
for key, value in _patterns.items():
pattern = "$%s" % key

View File

@ -18,7 +18,7 @@ from os.path import isdir, isfile, join
from twisted.internet import error # pylint: disable=import-error
from twisted.internet import reactor # pylint: disable=import-error
from platformio import exception, util
from platformio import exception, fs, util
from platformio.commands.debug.process import BaseProcess
from platformio.proc import where_is_program
@ -74,7 +74,7 @@ class DebugServer(BaseProcess):
str_args = " ".join(
[arg if arg.startswith("-") else '"%s"' % arg for arg in args])
self._debug_port = '| "%s" %s' % (server_executable, str_args)
self._debug_port = self._debug_port.replace("\\", "\\\\")
self._debug_port = fs.to_unix_path(self._debug_port)
else:
env = os.environ.copy()
# prepend server "lib" folder to LD path

View File

@ -388,7 +388,6 @@ def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix,
if modified:
config.save()
config.reset_instances()
def _install_dependent_platforms(ctx, platforms):

View File

@ -23,7 +23,7 @@ from glob import glob
import click
from platformio import exception
from platformio.compat import get_file_contents, glob_escape
from platformio.compat import WINDOWS, get_file_contents, glob_escape
class cd(object):
@ -146,6 +146,12 @@ def match_src_files(src_dir, src_filter=None, src_exts=None):
return sorted(list(matches))
def to_unix_path(path):
if not WINDOWS or not path:
return path
return re.sub(r"[\\]+", "/", path)
def rmtree(path):
def _onerror(func, path, __):

View File

@ -14,14 +14,13 @@
import codecs
import os
import re
import sys
from os.path import abspath, basename, expanduser, isdir, isfile, join, relpath
import bottle
from platformio import fs, util
from platformio.compat import WINDOWS, get_file_contents
from platformio.compat import get_file_contents
from platformio.proc import where_is_program
from platformio.project.config import ProjectConfig
from platformio.project.helpers import (get_project_lib_dir,
@ -98,21 +97,15 @@ class ProjectGenerator(object):
for key, value in tpl_vars.items():
if key.endswith(("_path", "_dir")):
tpl_vars[key] = self.to_unix_path(value)
tpl_vars[key] = fs.to_unix_path(value)
for key in ("includes", "src_files", "libsource_dirs"):
if key not in tpl_vars:
continue
tpl_vars[key] = [self.to_unix_path(inc) for inc in tpl_vars[key]]
tpl_vars[key] = [fs.to_unix_path(inc) for inc in tpl_vars[key]]
tpl_vars['to_unix_path'] = self.to_unix_path
tpl_vars['to_unix_path'] = fs.to_unix_path
return tpl_vars
@staticmethod
def to_unix_path(path):
if not WINDOWS or not path:
return path
return re.sub(r"[\\]+", "/", path)
def get_src_files(self):
result = []
with fs.cd(self.project_dir):

View File

@ -15,10 +15,18 @@
<config projectName="{{project_name}}" targetName="DEBUG" />
</generated>
</component>
<component name="CMakeSettings" AUTO_RELOAD="true" GENERATION_PASS_SYSTEM_ENVIRONMENT="true">
<ADDITIONAL_GENERATION_ENVIRONMENT>
<envs />
</ADDITIONAL_GENERATION_ENVIRONMENT>
<component name="CMakeSettings" AUTO_RELOAD="true">
<configurations>
% envs = config.envs()
% if len(envs) > 1:
% for env in envs:
<configuration PROFILE_NAME="{{ env }}" CONFIG_NAME="{{ env }}" />
% end
<configuration PROFILE_NAME="All" CONFIG_NAME="All" />
% else:
<configuration PROFILE_NAME="{{ env_name }}" CONFIG_NAME="{{ env_name }}" />
% end
</configurations>
</component>
<component name="ChangeListManager">
<list default="true" id="ec922180-b3d3-40f1-af0b-2568113a9075" name="Default" comment="" />
@ -163,10 +171,6 @@
<envs />
<method />
</configuration>
<configuration default="false" name="Build All" type="CMakeRunConfiguration" factoryName="Application" WORKING_DIR="" PASS_PARENT_ENVS="FALSE" CONFIG_NAME="Debug" EXPLICIT_BUILD_TARGET_NAME="all">
<envs />
<method />
</configuration>
<configuration default="false" name="PLATFORMIO_BUILD" type="CMakeRunConfiguration" factoryName="Application" WORKING_DIR="" PASS_PARENT_ENVS="FALSE" PROJECT_NAME="{{project_name}}" TARGET_NAME="PLATFORMIO_BUILD" CONFIG_NAME="Debug">
<envs />
<method />
@ -199,17 +203,6 @@
<envs />
<method />
</configuration>
<list size="9">
<item index="0" class="java.lang.String" itemvalue="Application.Build All" />
<item index="1" class="java.lang.String" itemvalue="Application.PLATFORMIO_BUILD" />
<item index="2" class="java.lang.String" itemvalue="Application.PLATFORMIO_UPLOAD" />
<item index="3" class="java.lang.String" itemvalue="Application.PLATFORMIO_CLEAN" />
<item index="4" class="java.lang.String" itemvalue="Application.PLATFORMIO_TEST" />
<item index="5" class="java.lang.String" itemvalue="Application.PLATFORMIO_PROGRAM" />
<item index="6" class="java.lang.String" itemvalue="Application.PLATFORMIO_UPLOADFS" />
<item index="7" class="java.lang.String" itemvalue="Application.PLATFORMIO_UPDATE" />
<item index="8" class="java.lang.String" itemvalue="Application.PLATFORMIO_REBUILD_PROJECT_INDEX" />
</list>
</component>
<component name="ShelveChangesManager" show_recycled="false" />
<component name="SvnConfiguration">

View File

@ -16,49 +16,49 @@ endif()
add_custom_target(
PLATFORMIO_BUILD ALL
COMMAND ${PLATFORMIO_CMD} -f -c clion run
COMMAND ${PLATFORMIO_CMD} -f -c clion run "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(
PLATFORMIO_BUILD_VERBOSE ALL
COMMAND ${PLATFORMIO_CMD} -f -c clion run --verbose
COMMAND ${PLATFORMIO_CMD} -f -c clion run --verbose "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(
PLATFORMIO_UPLOAD ALL
COMMAND ${PLATFORMIO_CMD} -f -c clion run --target upload
COMMAND ${PLATFORMIO_CMD} -f -c clion run --target upload "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(
PLATFORMIO_CLEAN ALL
COMMAND ${PLATFORMIO_CMD} -f -c clion run --target clean
COMMAND ${PLATFORMIO_CMD} -f -c clion run --target clean "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(
PLATFORMIO_MONITOR ALL
COMMAND ${PLATFORMIO_CMD} -f -c clion device monitor
COMMAND ${PLATFORMIO_CMD} -f -c clion device monitor "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(
PLATFORMIO_TEST ALL
COMMAND ${PLATFORMIO_CMD} -f -c clion test
COMMAND ${PLATFORMIO_CMD} -f -c clion test "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(
PLATFORMIO_PROGRAM ALL
COMMAND ${PLATFORMIO_CMD} -f -c clion run --target program
COMMAND ${PLATFORMIO_CMD} -f -c clion run --target program "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(
PLATFORMIO_UPLOADFS ALL
COMMAND ${PLATFORMIO_CMD} -f -c clion run --target uploadfs
COMMAND ${PLATFORMIO_CMD} -f -c clion run --target uploadfs "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
@ -74,4 +74,10 @@ add_custom_target(
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(
PLATFORMIO_DEVICE_LIST ALL
COMMAND ${PLATFORMIO_CMD} -f -c clion device list
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_executable(${PROJECT_NAME} ${SRC_LIST})

View File

@ -5,6 +5,8 @@
# please create `CMakeListsUser.txt` in the root of project.
# The `CMakeListsUser.txt` will not be overwritten by PlatformIO.
%from platformio.project.helpers import (load_project_ide_data)
%
% import re
%
% def _normalize_path(path):
@ -19,6 +21,14 @@
% end
% return path
% end
%
% envs = config.envs()
% if len(envs) > 1:
set(CMAKE_CONFIGURATION_TYPES "{{ ";".join(envs) }}" CACHE STRING "" FORCE)
% else:
set(CMAKE_CONFIGURATION_TYPES "{{ env_name }}" CACHE STRING "" FORCE)
% end
set(PLATFORMIO_CMD "{{ _normalize_path(platformio_path) }}")
@ -37,12 +47,31 @@ SET(CMAKE_C_STANDARD {{ cc_stds[-1] }})
set(CMAKE_CXX_STANDARD {{ cxx_stds[-1] }})
% end
% for define in defines:
add_definitions(-D'{{!re.sub(r"([\"\(\)#])", r"\\\1", define)}}')
% end
if (CMAKE_BUILD_TYPE MATCHES "{{ env_name }}")
%for define in defines:
add_definitions(-D'{{!re.sub(r"([\"\(\)#])", r"\\\1", define)}}')
%end
% for include in includes:
include_directories("{{ _normalize_path(include) }}")
% end
%for include in includes:
include_directories("{{ _normalize_path(to_unix_path(include)) }}")
%end
endif()
% leftover_envs = set(envs) ^ set([env_name])
%
% if leftover_envs:
% ide_data = load_project_ide_data(project_dir, leftover_envs)
% end
%
% for env, data in ide_data.items():
if (CMAKE_BUILD_TYPE MATCHES "{{ env }}")
% for define in data["defines"]:
add_definitions(-D'{{!re.sub(r"([\"\(\)#])", r"\\\1", define)}}')
% end
% for include in data["includes"]:
include_directories("{{ _normalize_path(to_unix_path(include)) }}")
% end
endif()
% end
FILE(GLOB_RECURSE SRC_LIST "{{ _normalize_path(project_src_dir) }}/*.*" "{{ _normalize_path(project_lib_dir) }}/*.*" "{{ _normalize_path(project_libdeps_dir) }}/*.*")

View File

@ -0,0 +1,22 @@
% import re
% STD_RE = re.compile(r"\-std=[a-z\+]+(\d+)")
% cc_stds = STD_RE.findall(cc_flags)
% cxx_stds = STD_RE.findall(cxx_flags)
%
%
clang
% if cc_stds:
{{"%c"}} -std=c{{ cc_stds[-1] }}
% end
% if cxx_stds:
{{"%cpp"}} -std=c++{{ cxx_stds[-1] }}
% end
% for include in includes:
-I{{ include }}
% end
% for define in defines:
-D{{ define }}
% end

View File

@ -24,12 +24,12 @@ from platformio.proc import copy_pythonpath_to_osenv, get_pythonexe_path
from platformio.project.helpers import get_project_packages_dir
CORE_PACKAGES = {
"contrib-piohome": "^2.1.0",
"contrib-piohome": "^2.3.2",
"contrib-pysite":
"~2.%d%d.190418" % (sys.version_info[0], sys.version_info[1]),
"tool-pioplus": "^2.5.2",
"tool-unity": "~1.20403.0",
"tool-scons": "~2.20501.7" if PY2 else "~3.30005.0"
"tool-scons": "~2.20501.7" if PY2 else "~3.30101.0"
}
PIOPLUS_AUTO_UPDATES_MAX = 100

View File

@ -21,6 +21,7 @@ from glob import glob
from os.path import isdir, join
import click
import semantic_version
from platformio import app, exception, util
from platformio.compat import glob_escape, string_types
@ -166,8 +167,13 @@ class LibraryManager(BasePkgManager):
return 0
return -1 if date1 < date2 else 1
semver_spec = self.parse_semver_spec(
requirements) if requirements else None
semver_spec = None
try:
semver_spec = semantic_version.SimpleSpec(
requirements) if requirements else None
except ValueError:
pass
item = {}
for v in versions:

View File

@ -86,19 +86,18 @@ class PkgRepoMixin(object):
def max_satisfying_repo_version(self, versions, requirements=None):
item = None
reqspec = None
if requirements:
try:
reqspec = self.parse_semver_spec(requirements,
raise_exception=True)
except ValueError:
pass
try:
reqspec = semantic_version.SimpleSpec(
requirements) if requirements else None
except ValueError:
pass
for v in versions:
if not self.is_system_compatible(v.get("system")):
continue
# if "platformio" in v.get("engines", {}):
# if PkgRepoMixin.PIO_VERSION not in self.parse_semver_spec(
# v['engines']['platformio'], raise_exception=True):
# if PkgRepoMixin.PIO_VERSION not in requirements.SimpleSpec(
# v['engines']['platformio']):
# continue
specver = semantic_version.Version(v['version'])
if reqspec and specver not in reqspec:
@ -218,28 +217,6 @@ class PkgInstallerMixin(object):
with FileUnpacker(source_path) as fu:
return fu.unpack(dest_dir, with_progress=False)
@staticmethod
def parse_semver_spec(value, raise_exception=False):
try:
# Workaround for ^ issue and pre-releases
# https://github.com/rbarrois/python-semanticversion/issues/61
requirements = []
for item in str(value).split(","):
item = item.strip()
if not item:
continue
if item.startswith("^"):
major = semantic_version.Version.coerce(item[1:]).major
requirements.append(">=%s" % major)
requirements.append("<%s" % (int(major) + 1))
else:
requirements.append(item)
return semantic_version.Spec(*requirements)
except ValueError as e:
if raise_exception:
raise e
return None
@staticmethod
def parse_semver_version(value, raise_exception=False):
try:
@ -423,8 +400,8 @@ class PkgInstallerMixin(object):
return manifest
try:
if requirements and not self.parse_semver_spec(
requirements, raise_exception=True).match(
if requirements and not semantic_version.SimpleSpec(
requirements).match(
self.parse_semver_version(manifest['version'],
raise_exception=True)):
continue
@ -557,8 +534,8 @@ class PkgInstallerMixin(object):
"Package version %s doesn't satisfy requirements %s" %
(tmp_manifest['version'], requirements))
try:
assert tmp_semver and tmp_semver in self.parse_semver_spec(
requirements, raise_exception=True), mismatch_error
assert tmp_semver and tmp_semver in semantic_version.SimpleSpec(
requirements), mismatch_error
except (AssertionError, ValueError):
assert tmp_manifest['version'] == requirements, mismatch_error

View File

@ -501,7 +501,7 @@ class PlatformBase( # pylint: disable=too-many-public-methods
self.package_repositories)
# if self.engines and "platformio" in self.engines:
# if self.PIO_VERSION not in semantic_version.Spec(
# if self.PIO_VERSION not in semantic_version.SimpleSpec(
# self.engines['platformio']):
# raise exception.IncompatiblePlatform(self.name,
# str(self.PIO_VERSION))

View File

@ -16,7 +16,7 @@ import glob
import json
import os
import re
from os.path import expanduser, isfile
from os.path import expanduser, getmtime, isfile
import click
@ -72,13 +72,14 @@ class ProjectConfig(object):
@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 = {}
mtime = getmtime(path) if isfile(path) else 0
instance = ProjectConfig._instances.get(path)
if instance and instance["mtime"] != mtime:
instance = None
if not instance:
instance = {"mtime": mtime, "config": ProjectConfig(path)}
ProjectConfig._instances[path] = instance
return instance["config"]
def __init__(self, path, parse_extra=True, expand_interpolations=True):
self.path = path
@ -311,6 +312,9 @@ class ProjectConfig(object):
return json.dumps(result)
def save(self, path=None):
path = path or self.path
if path in self._instances:
del self._instances[path]
with open(path or self.path, "w") as fp:
fp.write(CONFIG_HEADER)
self._parser.write(fp)

View File

@ -194,20 +194,29 @@ def compute_project_checksum(config):
return checksum.hexdigest()
def load_project_ide_data(project_dir, env_name):
def load_project_ide_data(project_dir, envs):
from platformio.commands.run import cli as cmd_run
result = CliRunner().invoke(cmd_run, [
"--project-dir", project_dir, "--environment", env_name, "--target",
"idedata"
])
assert envs
if not isinstance(envs, (list, tuple, set)):
envs = [envs]
args = ["--project-dir", project_dir, "--target", "idedata"]
for env in envs:
args.extend(["-e", env])
result = CliRunner().invoke(cmd_run, args)
if result.exit_code != 0 and not isinstance(result.exception,
exception.ReturnErrorCode):
raise result.exception
if '"includes":' not in result.output:
raise exception.PlatformioException(result.output)
data = {}
for line in result.output.split("\n"):
line = line.strip()
if line.startswith('{"') and line.endswith("}"):
return json.loads(line)
return None
if (line.startswith('{"') and line.endswith("}")
and "env_name" in line):
_data = json.loads(line)
if "env_name" in _data:
data[_data['env_name']] = _data
if len(envs) == 1 and envs[0] in data:
return data[envs[0]]
return data or None

View File

@ -330,7 +330,8 @@ Examples are listed from `%s development platform repository <%s>`_:
examples_dir = join(p.get_dir(), "examples")
if isdir(examples_dir):
for eitem in os.listdir(examples_dir):
if not isdir(join(examples_dir, eitem)):
example_dir = join(examples_dir, eitem)
if not isdir(example_dir) or not os.listdir(example_dir):
continue
url = "%s/tree/master/examples/%s" % (github_url, eitem)
lines.append("* `%s <%s>`_" % (eitem, campaign_url(url)))
@ -894,7 +895,8 @@ def update_project_examples():
examples_md_lines = []
if isdir(platform_examples_dir):
for item in os.listdir(platform_examples_dir):
if not isdir(join(platform_examples_dir, item)):
example_dir = join(platform_examples_dir, item)
if not isdir(example_dir) or not os.listdir(example_dir):
continue
url = "%s/tree/master/examples/%s" % (github_url, item)
examples_md_lines.append("* [%s](%s)" % (item, url))

View File

@ -23,8 +23,8 @@ install_requires = [
"colorama",
"pyserial>=3,<4,!=3.3",
"requests>=2.4.0,<3",
"semantic_version>=2.5.0,<3",
"tabulate>=0.8.3"
"semantic_version>=2.8.1,<3",
"tabulate>=0.8.3,<1"
]
setup(