mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-29 17:47:14 +02:00
Merge branch 'hotfix/v3.5.4'
This commit is contained in:
30
HISTORY.rst
30
HISTORY.rst
@ -4,6 +4,30 @@ Release Notes
|
||||
PlatformIO 3.0
|
||||
--------------
|
||||
|
||||
3.5.4 (2018-07-03)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Improved removing of default build flags using `build_unflags <http://docs.platformio.org/page/projectconf/section_env_build.html#build-unflags>`__ option
|
||||
(`issue #1712 <https://github.com/platformio/platformio-core/issues/1712>`_)
|
||||
* Export ``LIBS``, ``LIBPATH``, and ``LINKFLAGS`` data from project dependent
|
||||
libraries to the global build environment
|
||||
* Don't export ``CPPPATH`` data of project dependent libraries to framework's
|
||||
build environment
|
||||
(`issue #1665 <https://github.com/platformio/platformio-core/issues/1665>`_)
|
||||
* Handle "architectures" data from "library.properties" manifest in
|
||||
`lib_compat_mode = strict <http://docs.platformio.org/en/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" <http://docs.platformio.org/page/projectconf/dynamic_variables.html>`__
|
||||
(`issue #1705 <https://github.com/platformio/platformio-core/issues/1705>`_)
|
||||
* Removed "date&time" when processing project with `platformio run <http://docs.platformio.org/page/userguide/cmd_run.html>`__ command
|
||||
(`issue #1343 <https://github.com/platformio/platformio-core/issues/1343>`_)
|
||||
* Fixed issue with invalid LD script if path contains space
|
||||
* Fixed preprocessor for Arduino sketch when function returns certain type
|
||||
(`issue #1683 <https://github.com/platformio/platformio-core/issues/1683>`_)
|
||||
* Fixed issue when `platformio lib uninstall <http://docs.platformio.org/page/userguide/lib/cmd_uninstall.html>`__
|
||||
removes initial source code
|
||||
(`issue #1023 <https://github.com/platformio/platformio-core/issues/1023>`_)
|
||||
|
||||
3.5.3 (2018-06-01)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -19,7 +43,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 <http://docs.platformio.org/page/projectconf/section_env_debug.html#debug-svd-path>`__
|
||||
option
|
||||
* Custom project `description <http://docs.platformio.org/en/latest/projectconf/section_platformio.html#description>`_
|
||||
* Custom project `description <http://docs.platformio.org/en/page/projectconf/section_platformio.html#description>`_
|
||||
which will be used by `PlatformIO Home <http://docs.platformio.org/page/home/index.html>`_
|
||||
* Updated Unity tool to 2.4.3
|
||||
* Improved support for Black Magic Probe in "uploader" mode
|
||||
@ -45,9 +69,9 @@ PlatformIO 3.0
|
||||
- Multiple themes (Dark & Light)
|
||||
- Ability to specify a name for new project
|
||||
|
||||
* Control `PIO Unified Debugger <http://docs.platformio.org/en/latest/plus/debugging.html>`__
|
||||
* Control `PIO Unified Debugger <http://docs.platformio.org/en/page/plus/debugging.html>`__
|
||||
and its firmware loading mode using
|
||||
`debug_load_mode <http://docs.platformio.org/en/latest/projectconf/section_env_debug.html#debug-load-mode>`__ option
|
||||
`debug_load_mode <http://docs.platformio.org/en/page/projectconf/section_env_debug.html#debug-load-mode>`__ option
|
||||
* Added aliases (off, light, strict) for
|
||||
`LDF Compatibility Mode <http://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``)
|
||||
|
2
docs
2
docs
Submodule docs updated: 3ad76be8f7...0b8ac5fbf7
@ -14,7 +14,7 @@
|
||||
|
||||
import sys
|
||||
|
||||
VERSION = (3, 5, 3)
|
||||
VERSION = (3, 5, 4)
|
||||
__version__ = ".".join([str(s) for s in VERSION])
|
||||
|
||||
__title__ = "platformio"
|
||||
|
@ -279,9 +279,8 @@ class LibBuilderBase(object):
|
||||
if (key in item and
|
||||
not util.items_in_list(self.env[env_key], item[key])):
|
||||
if self.verbose:
|
||||
sys.stderr.write(
|
||||
"Skip %s incompatible dependency %s\n" % (key[:-1],
|
||||
item))
|
||||
sys.stderr.write("Skip %s incompatible dependency %s\n"
|
||||
% (key[:-1], item))
|
||||
skip = True
|
||||
if skip:
|
||||
continue
|
||||
@ -394,9 +393,9 @@ class LibBuilderBase(object):
|
||||
if self != lb:
|
||||
if _already_depends(lb):
|
||||
if self.verbose:
|
||||
sys.stderr.write("Warning! Circular dependencies detected "
|
||||
"between `%s` and `%s`\n" % (self.path,
|
||||
lb.path))
|
||||
sys.stderr.write(
|
||||
"Warning! Circular dependencies detected "
|
||||
"between `%s` and `%s`\n" % (self.path, lb.path))
|
||||
self._circular_deps.append(lb)
|
||||
elif lb not in self._depbuilders:
|
||||
self._depbuilders.append(lb)
|
||||
@ -502,6 +501,28 @@ class ArduinoLibBuilder(LibBuilderBase):
|
||||
def is_frameworks_compatible(self, frameworks):
|
||||
return util.items_in_list(frameworks, ["arduino", "energia"])
|
||||
|
||||
def is_platforms_compatible(self, platforms):
|
||||
platforms_map = {
|
||||
"avr": "atmelavr",
|
||||
"sam": "atmelsam",
|
||||
"samd": "atmelsam",
|
||||
"esp8266": "espressif8266",
|
||||
"esp32": "espressif32",
|
||||
"arc32": "intel_arc32",
|
||||
"stm32": "ststm32"
|
||||
}
|
||||
items = []
|
||||
for arch in self._manifest.get("architectures", "").split(","):
|
||||
arch = arch.strip()
|
||||
if arch == "*":
|
||||
items = "*"
|
||||
break
|
||||
if arch in platforms_map:
|
||||
items.append(platforms_map[arch])
|
||||
if not items:
|
||||
return LibBuilderBase.is_platforms_compatible(self, platforms)
|
||||
return util.items_in_list(platforms, items)
|
||||
|
||||
|
||||
class MbedLibBuilder(LibBuilderBase):
|
||||
|
||||
@ -803,7 +824,7 @@ def GetLibBuilders(env): # pylint: disable=too-many-branches
|
||||
return items
|
||||
|
||||
|
||||
def BuildProjectLibraries(env):
|
||||
def ConfigureProjectLibBuilder(env):
|
||||
|
||||
def correct_found_libs(lib_builders):
|
||||
# build full dependency graph
|
||||
@ -822,7 +843,7 @@ def BuildProjectLibraries(env):
|
||||
title = "<%s>" % lb.name
|
||||
vcs_info = lb.vcs_info
|
||||
if lb.version:
|
||||
title += " v%s" % lb.version
|
||||
title += " %s" % lb.version
|
||||
if vcs_info and vcs_info.get("version"):
|
||||
title += " #%s" % vcs_info.get("version")
|
||||
sys.stdout.write("%s|-- %s" % (margin, title))
|
||||
@ -837,7 +858,6 @@ def BuildProjectLibraries(env):
|
||||
print_deps_tree(lb, level + 1)
|
||||
|
||||
project = ProjectAsLibBuilder(env, "$PROJECT_DIR")
|
||||
project.env = env
|
||||
ldf_mode = LibBuilderBase.lib_ldf_mode.fget(project)
|
||||
|
||||
print "Library Dependency Finder -> http://bit.ly/configure-pio-ldf"
|
||||
@ -859,7 +879,7 @@ def BuildProjectLibraries(env):
|
||||
else:
|
||||
print "No dependencies"
|
||||
|
||||
return project.build()
|
||||
return project
|
||||
|
||||
|
||||
def exists(_):
|
||||
@ -868,5 +888,5 @@ def exists(_):
|
||||
|
||||
def generate(env):
|
||||
env.AddMethod(GetLibBuilders)
|
||||
env.AddMethod(BuildProjectLibraries)
|
||||
env.AddMethod(ConfigureProjectLibBuilder)
|
||||
return env
|
||||
|
@ -30,9 +30,10 @@ from platformio.managers.core import get_core_package_dir
|
||||
|
||||
class InoToCPPConverter(object):
|
||||
|
||||
PROTOTYPE_RE = re.compile(r"""^(
|
||||
PROTOTYPE_RE = re.compile(
|
||||
r"""^(
|
||||
(?:template\<.*\>\s*)? # template
|
||||
([a-z_\d]+\*?\s+){1,2} # return type
|
||||
([a-z_\d\&]+\*?\s+){1,2} # return type
|
||||
([a-z_\d]+\s*) # name of prototype
|
||||
\([a-z_,\.\*\&\[\]\s\d]*\) # arguments
|
||||
)\s*\{ # must end with {
|
||||
@ -89,8 +90,8 @@ class InoToCPPConverter(object):
|
||||
self.env.Execute(
|
||||
self.env.VerboseAction(
|
||||
'$CXX -o "{0}" -x c++ -fpreprocessed -dD -E "{1}"'.format(
|
||||
out_file,
|
||||
tmp_path), "Converting " + basename(out_file[:-4])))
|
||||
out_file, tmp_path),
|
||||
"Converting " + basename(out_file[:-4])))
|
||||
atexit.register(_delete_file, tmp_path)
|
||||
return isfile(out_file)
|
||||
|
||||
@ -163,18 +164,17 @@ class InoToCPPConverter(object):
|
||||
|
||||
prototype_names = set([m.group(3).strip() for m in prototypes])
|
||||
split_pos = prototypes[0].start()
|
||||
match_ptrs = re.search(self.PROTOPTRS_TPLRE %
|
||||
("|".join(prototype_names)),
|
||||
contents[:split_pos], re.M)
|
||||
match_ptrs = re.search(
|
||||
self.PROTOPTRS_TPLRE % ("|".join(prototype_names)),
|
||||
contents[:split_pos], re.M)
|
||||
if match_ptrs:
|
||||
split_pos = contents.rfind("\n", 0, match_ptrs.start()) + 1
|
||||
|
||||
result = []
|
||||
result.append(contents[:split_pos].strip())
|
||||
result.append("%s;" % ";\n".join([m.group(1) for m in prototypes]))
|
||||
result.append('#line %d "%s"' %
|
||||
(self._get_total_lines(contents[:split_pos]),
|
||||
self._main_ino.replace("\\", "/")))
|
||||
result.append('#line %d "%s"' % (self._get_total_lines(
|
||||
contents[:split_pos]), self._main_ino.replace("\\", "/")))
|
||||
result.append(contents[split_pos:].strip())
|
||||
return "\n".join(result)
|
||||
|
||||
@ -231,14 +231,25 @@ def GetActualLDScript(env):
|
||||
return None
|
||||
|
||||
script = None
|
||||
script_in_next = False
|
||||
for f in env.get("LINKFLAGS", []):
|
||||
if f.startswith("-Wl,-T"):
|
||||
script = env.subst(f[6:].replace('"', "").strip())
|
||||
if isfile(script):
|
||||
return script
|
||||
path = _lookup_in_ldpath(script)
|
||||
if path:
|
||||
return path
|
||||
raw_script = None
|
||||
if f == "-T":
|
||||
script_in_next = True
|
||||
continue
|
||||
elif script_in_next:
|
||||
script_in_next = False
|
||||
raw_script = f
|
||||
elif f.startswith("-Wl,-T"):
|
||||
raw_script = f[6:]
|
||||
else:
|
||||
continue
|
||||
script = env.subst(raw_script.replace('"', "").strip())
|
||||
if isfile(script):
|
||||
return script
|
||||
path = _lookup_in_ldpath(script)
|
||||
if path:
|
||||
return path
|
||||
|
||||
if script:
|
||||
sys.stderr.write(
|
||||
@ -295,9 +306,6 @@ def ProcessTest(env):
|
||||
src_filter.append("+<%s%s>" % (env['PIOTEST'], sep))
|
||||
env.Replace(PIOTEST_SRC_FILTER=src_filter)
|
||||
|
||||
return env.CollectBuildFiles("$BUILDTEST_DIR", "$PROJECTTEST_DIR",
|
||||
"$PIOTEST_SRC_FILTER")
|
||||
|
||||
|
||||
def GetExtraScripts(env, scope):
|
||||
items = []
|
||||
|
@ -209,9 +209,9 @@ def CheckUploadSize(_, target, source, env): # pylint: disable=W0613,W0621
|
||||
used_size = int(values[0]) + int(values[1])
|
||||
|
||||
if used_size > max_size:
|
||||
sys.stderr.write("Error: The program size (%d bytes) is greater "
|
||||
"than maximum allowed (%s bytes)\n" % (used_size,
|
||||
max_size))
|
||||
sys.stderr.write(
|
||||
"Error: The program size (%d bytes) is greater "
|
||||
"than maximum allowed (%s bytes)\n" % (used_size, max_size))
|
||||
env.Exit(1)
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@ from os.path import basename, dirname, isdir, join, realpath
|
||||
|
||||
from SCons import Builder, Util
|
||||
from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild,
|
||||
DefaultEnvironment, SConscript)
|
||||
DefaultEnvironment, Export, SConscript)
|
||||
|
||||
from platformio.util import glob_escape, pioversion_to_intstr
|
||||
|
||||
@ -41,6 +41,43 @@ def scons_patched_match_splitext(path, suffixes=None):
|
||||
return tokens
|
||||
|
||||
|
||||
def _build_project_deps(env):
|
||||
project_lib_builder = env.ConfigureProjectLibBuilder()
|
||||
|
||||
# append project libs to the beginning of list
|
||||
env.Prepend(LIBS=project_lib_builder.build())
|
||||
# append extra linker related options from libs
|
||||
env.AppendUnique(
|
||||
**{
|
||||
key: project_lib_builder.env.get(key)
|
||||
for key in ("LIBS", "LIBPATH", "LINKFLAGS")
|
||||
if project_lib_builder.env.get(key)
|
||||
})
|
||||
|
||||
if "__test" in COMMAND_LINE_TARGETS:
|
||||
env.ProcessTest()
|
||||
projenv = env.Clone()
|
||||
projenv.BuildSources("$BUILDTEST_DIR", "$PROJECTTEST_DIR",
|
||||
"$PIOTEST_SRC_FILTER")
|
||||
else:
|
||||
projenv = env.Clone()
|
||||
projenv.BuildSources("$BUILDSRC_DIR", "$PROJECTSRC_DIR",
|
||||
env.get("SRC_FILTER"))
|
||||
|
||||
# CPPPATH from dependencies
|
||||
projenv.PrependUnique(CPPPATH=project_lib_builder.env.get("CPPPATH"))
|
||||
# extra build flags from `platformio.ini`
|
||||
projenv.ProcessFlags(env.get("SRC_BUILD_FLAGS"))
|
||||
|
||||
if not env.get("PIOBUILDFILES") and not COMMAND_LINE_TARGETS:
|
||||
sys.stderr.write(
|
||||
"Error: Nothing to build. Please put your source code files "
|
||||
"to '%s' folder\n" % env.subst("$PROJECTSRC_DIR"))
|
||||
env.Exit(1)
|
||||
|
||||
Export("projenv")
|
||||
|
||||
|
||||
def BuildProgram(env):
|
||||
|
||||
def _append_pio_macros():
|
||||
@ -62,6 +99,7 @@ def BuildProgram(env):
|
||||
# process extra flags from board
|
||||
if "BOARD" in env and "build.extra_flags" in env.BoardConfig():
|
||||
env.ProcessFlags(env.BoardConfig().get("build.extra_flags"))
|
||||
|
||||
# apply user flags
|
||||
env.ProcessFlags(env.get("BUILD_FLAGS"))
|
||||
|
||||
@ -74,37 +112,19 @@ def BuildProgram(env):
|
||||
# remove specified flags
|
||||
env.ProcessUnFlags(env.get("BUILD_UNFLAGS"))
|
||||
|
||||
# build dependent libs; place them before built-in libs
|
||||
env.Prepend(LIBS=env.BuildProjectLibraries())
|
||||
# build project with dependencies
|
||||
_build_project_deps(env)
|
||||
|
||||
# append specified LD_SCRIPT
|
||||
if ("LDSCRIPT_PATH" in env
|
||||
# append into the beginning a main LD script
|
||||
if (env.get("LDSCRIPT_PATH")
|
||||
and not any("-Wl,-T" in f for f in env['LINKFLAGS'])):
|
||||
env.Append(LINKFLAGS=['-Wl,-T"$LDSCRIPT_PATH"'])
|
||||
env.Prepend(LINKFLAGS=["-T", "$LDSCRIPT_PATH"])
|
||||
|
||||
# enable "cyclic reference" for linker
|
||||
if env.get("LIBS") and env.GetCompilerType() == "gcc":
|
||||
env.Prepend(_LIBFLAGS="-Wl,--start-group ")
|
||||
env.Append(_LIBFLAGS=" -Wl,--end-group")
|
||||
|
||||
# Handle SRC_BUILD_FLAGS
|
||||
env.ProcessFlags(env.get("SRC_BUILD_FLAGS"))
|
||||
|
||||
if "__test" in COMMAND_LINE_TARGETS:
|
||||
env.Append(PIOBUILDFILES=env.ProcessTest())
|
||||
else:
|
||||
env.Append(
|
||||
PIOBUILDFILES=env.CollectBuildFiles(
|
||||
"$BUILDSRC_DIR",
|
||||
"$PROJECTSRC_DIR",
|
||||
src_filter=env.get("SRC_FILTER")))
|
||||
|
||||
if not env['PIOBUILDFILES'] and not COMMAND_LINE_TARGETS:
|
||||
sys.stderr.write(
|
||||
"Error: Nothing to build. Please put your source code files "
|
||||
"to '%s' folder\n" % env.subst("$PROJECTSRC_DIR"))
|
||||
env.Exit(1)
|
||||
|
||||
program = env.Program(
|
||||
join("$BUILD_DIR", env.subst("$PROGNAME")), env['PIOBUILDFILES'])
|
||||
|
||||
@ -171,7 +191,18 @@ def ProcessFlags(env, flags): # pylint: disable=too-many-branches
|
||||
def ProcessUnFlags(env, flags):
|
||||
if not flags:
|
||||
return
|
||||
for key, unflags in env.ParseFlagsExtended(flags).items():
|
||||
parsed = env.ParseFlagsExtended(flags)
|
||||
|
||||
# get all flags and copy them to each "*FLAGS" variable
|
||||
all_flags = []
|
||||
for key, unflags in parsed.items():
|
||||
if key.endswith("FLAGS"):
|
||||
all_flags.extend(unflags)
|
||||
for key, unflags in parsed.items():
|
||||
if key.endswith("FLAGS"):
|
||||
parsed[key].extend(all_flags)
|
||||
|
||||
for key, unflags in parsed.items():
|
||||
for unflag in unflags:
|
||||
for current in env.get(key, []):
|
||||
conditions = [
|
||||
@ -275,7 +306,7 @@ def BuildFrameworks(env, frameworks):
|
||||
env.ConvertInoToCpp()
|
||||
|
||||
if f in board_frameworks:
|
||||
SConscript(env.GetFrameworkScript(f))
|
||||
SConscript(env.GetFrameworkScript(f), exports="env")
|
||||
else:
|
||||
sys.stderr.write(
|
||||
"Error: This board doesn't support %s framework!\n" % f)
|
||||
@ -289,8 +320,9 @@ def BuildLibrary(env, variant_dir, src_dir, src_filter=None):
|
||||
|
||||
|
||||
def BuildSources(env, variant_dir, src_dir, src_filter=None):
|
||||
nodes = env.CollectBuildFiles(variant_dir, src_dir, src_filter)
|
||||
DefaultEnvironment().Append(
|
||||
PIOBUILDFILES=env.CollectBuildFiles(variant_dir, src_dir, src_filter))
|
||||
PIOBUILDFILES=[env.Object(node) for node in nodes])
|
||||
|
||||
|
||||
def exists(_):
|
||||
|
@ -439,8 +439,8 @@ def lib_stats(json_output):
|
||||
printitem_tpl.format(
|
||||
name=click.style(name, fg="cyan"),
|
||||
url=click.style(
|
||||
"https://platformio.org/lib/search?query=" +
|
||||
quote("keyword:%s" % name),
|
||||
"https://platformio.org/lib/search?query=" + quote(
|
||||
"keyword:%s" % name),
|
||||
fg="blue")))
|
||||
|
||||
for key in ("updated", "added"):
|
||||
|
@ -273,8 +273,8 @@ def platform_show(platform, json_output): # pylint: disable=too-many-branches
|
||||
if item['type']:
|
||||
click.echo("Type: %s" % item['type'])
|
||||
click.echo("Requirements: %s" % item['requirements'])
|
||||
click.echo("Installed: %s" %
|
||||
("Yes" if item.get("version") else "No (optional)"))
|
||||
click.echo("Installed: %s" % ("Yes" if item.get("version") else
|
||||
"No (optional)"))
|
||||
if "version" in item:
|
||||
click.echo("Version: %s" % item['version'])
|
||||
if "originalVersion" in item:
|
||||
|
@ -12,7 +12,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from datetime import datetime
|
||||
from hashlib import sha1
|
||||
from os import getcwd, makedirs, walk
|
||||
from os.path import getmtime, isdir, isfile, join
|
||||
@ -197,10 +196,8 @@ class EnvironmentProcessor(object):
|
||||
"%s: %s" % (k, ", ".join(util.parse_conf_multi_values(v))))
|
||||
|
||||
if not self.silent:
|
||||
click.echo("[%s] Processing %s (%s)" %
|
||||
(datetime.now().strftime("%c"),
|
||||
click.style(self.name, fg="cyan", bold=True),
|
||||
"; ".join(env_dump)))
|
||||
click.echo("Processing %s (%s)" % (click.style(
|
||||
self.name, fg="cyan", bold=True), "; ".join(env_dump)))
|
||||
click.secho("-" * terminal_width, bold=True)
|
||||
|
||||
self.options = self._validate_options(self.options)
|
||||
@ -296,10 +293,10 @@ class EnvironmentProcessor(object):
|
||||
if d.strip()
|
||||
], self.verbose)
|
||||
if "lib_deps" in self.options:
|
||||
_autoinstall_libdeps(self.cmd_ctx,
|
||||
util.parse_conf_multi_values(
|
||||
self.options['lib_deps']),
|
||||
self.verbose)
|
||||
_autoinstall_libdeps(
|
||||
self.cmd_ctx,
|
||||
util.parse_conf_multi_values(self.options['lib_deps']),
|
||||
self.verbose)
|
||||
|
||||
try:
|
||||
p = PlatformFactory.newPlatform(self.options['platform'])
|
||||
@ -385,10 +382,10 @@ def print_summary(results, start_time):
|
||||
err=status is False)
|
||||
|
||||
print_header(
|
||||
"[%s] Took %.2f seconds" %
|
||||
((click.style("SUCCESS", fg="green", bold=True)
|
||||
if successed else click.style("ERROR", fg="red", bold=True)),
|
||||
time() - start_time),
|
||||
"[%s] Took %.2f seconds" % (
|
||||
(click.style("SUCCESS", fg="green", bold=True)
|
||||
if successed else click.style("ERROR", fg="red", bold=True)),
|
||||
time() - start_time),
|
||||
is_error=not successed)
|
||||
|
||||
|
||||
|
@ -32,8 +32,8 @@ def settings_get(name):
|
||||
click.echo(
|
||||
list_tpl.format(
|
||||
name=click.style("Name", fg="cyan"),
|
||||
value=(click.style("Value", fg="green") +
|
||||
click.style(" [Default]", fg="yellow")),
|
||||
value=(click.style("Value", fg="green") + click.style(
|
||||
" [Default]", fg="yellow")),
|
||||
description="Description"))
|
||||
click.echo("-" * terminal_width)
|
||||
|
||||
|
@ -43,9 +43,8 @@ class FileDownloader(object):
|
||||
|
||||
disposition = self._request.headers.get("content-disposition")
|
||||
if disposition and "filename=" in disposition:
|
||||
self._fname = disposition[
|
||||
disposition.index("filename=") + 9:].replace('"', "").replace(
|
||||
"'", "")
|
||||
self._fname = disposition[disposition.index("filename=") +
|
||||
9:].replace('"', "").replace("'", "")
|
||||
self._fname = self._fname.encode("utf8")
|
||||
else:
|
||||
self._fname = [p for p in url.split("/") if p][-1]
|
||||
|
@ -192,6 +192,11 @@ 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"
|
||||
@ -248,7 +253,7 @@ class CygwinEnvDetected(PlatformioException):
|
||||
class DebugSupportError(PlatformioException):
|
||||
|
||||
MESSAGE = ("Currently, PlatformIO does not support debugging for `{0}`.\n"
|
||||
"Please mail contact@pioplus.com or visit "
|
||||
"Please contact support@pioplus.com or visit "
|
||||
"< http://docs.platformio.org/page/plus/debugging.html >")
|
||||
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
"name": "Win32",
|
||||
% elif systype == "darwin":
|
||||
"name": "Mac",
|
||||
"macFrameworkPath": [],
|
||||
% else:
|
||||
"name": "Linux",
|
||||
% end
|
||||
|
@ -208,8 +208,8 @@ def after_upgrade(ctx):
|
||||
|
||||
# PlatformIO banner
|
||||
click.echo("*" * terminal_width)
|
||||
click.echo("If you like %s, please:" %
|
||||
(click.style("PlatformIO", fg="cyan")))
|
||||
click.echo(
|
||||
"If you like %s, please:" % (click.style("PlatformIO", fg="cyan")))
|
||||
click.echo("- %s us on Twitter to stay up-to-date "
|
||||
"on the latest project news > %s" %
|
||||
(click.style("follow", fg="cyan"),
|
||||
@ -224,9 +224,9 @@ def after_upgrade(ctx):
|
||||
(click.style("try", fg="cyan"),
|
||||
click.style("https://platformio.org/platformio-ide", fg="cyan")))
|
||||
if not util.is_ci():
|
||||
click.echo("- %s us with PlatformIO Plus > %s" %
|
||||
(click.style("support", fg="cyan"),
|
||||
click.style("https://pioplus.com", fg="cyan")))
|
||||
click.echo("- %s us with PlatformIO Plus > %s" % (click.style(
|
||||
"support", fg="cyan"), click.style(
|
||||
"https://pioplus.com", fg="cyan")))
|
||||
|
||||
click.echo("*" * terminal_width)
|
||||
click.echo("")
|
||||
@ -296,8 +296,8 @@ def check_internal_updates(ctx, what):
|
||||
if manifest['name'] in outdated_items:
|
||||
continue
|
||||
conds = [
|
||||
pm.outdated(manifest['__pkg_dir']),
|
||||
what == "platforms" and PlatformFactory.newPlatform(
|
||||
pm.outdated(manifest['__pkg_dir']), what == "platforms"
|
||||
and PlatformFactory.newPlatform(
|
||||
manifest['__pkg_dir']).are_outdated_packages()
|
||||
]
|
||||
if any(conds):
|
||||
@ -318,8 +318,8 @@ def check_internal_updates(ctx, what):
|
||||
if not app.get_setting("auto_update_" + what):
|
||||
click.secho("Please update them via ", fg="yellow", nl=False)
|
||||
click.secho(
|
||||
"`platformio %s update`" %
|
||||
("lib --global" if what == "libraries" else "platform"),
|
||||
"`platformio %s update`" % ("lib --global" if what == "libraries"
|
||||
else "platform"),
|
||||
fg="cyan",
|
||||
nl=False)
|
||||
click.secho(" command.\n", fg="yellow")
|
||||
|
@ -107,6 +107,7 @@ def pioplus_call(args, **kwargs):
|
||||
pythonexe_path = util.get_pythonexe_path()
|
||||
os.environ['PYTHONEXEPATH'] = pythonexe_path
|
||||
os.environ['PYTHONPYSITEDIR'] = get_core_package_dir("contrib-pysite")
|
||||
os.environ['PIOCOREPYSITEDIR'] = dirname(util.get_source_dir() or "")
|
||||
os.environ['PATH'] = (os.pathsep).join(
|
||||
[dirname(pythonexe_path), os.environ['PATH']])
|
||||
util.copy_pythonpath_to_osenv()
|
||||
|
@ -208,9 +208,9 @@ class LibraryManager(BasePkgManager):
|
||||
cache_valid="30d")
|
||||
assert dl_data
|
||||
|
||||
return self._install_from_url(name, dl_data['url'].replace(
|
||||
"http://", "https://") if app.get_setting("enable_ssl") else
|
||||
dl_data['url'], requirements)
|
||||
return self._install_from_url(
|
||||
name, dl_data['url'].replace("http://", "https://")
|
||||
if app.get_setting("enable_ssl") else dl_data['url'], requirements)
|
||||
|
||||
def search_lib_id( # pylint: disable=too-many-branches
|
||||
self,
|
||||
@ -237,9 +237,9 @@ class LibraryManager(BasePkgManager):
|
||||
if not isinstance(values, list):
|
||||
values = [v.strip() for v in values.split(",") if v]
|
||||
for value in values:
|
||||
query.append('%s:"%s"' % (key[:-1]
|
||||
if key.endswith("s") else key,
|
||||
value))
|
||||
query.append(
|
||||
'%s:"%s"' % (key[:-1]
|
||||
if key.endswith("s") else key, value))
|
||||
|
||||
lib_info = None
|
||||
result = util.get_api_result(
|
||||
@ -290,9 +290,9 @@ class LibraryManager(BasePkgManager):
|
||||
def _get_lib_id_from_installed(self, filters):
|
||||
if filters['name'].startswith("id="):
|
||||
return int(filters['name'][3:])
|
||||
package_dir = self.get_package_dir(filters['name'],
|
||||
filters.get("requirements",
|
||||
filters.get("version")))
|
||||
package_dir = self.get_package_dir(
|
||||
filters['name'], filters.get("requirements",
|
||||
filters.get("version")))
|
||||
if not package_dir:
|
||||
return None
|
||||
manifest = self.load_manifest(package_dir)
|
||||
|
@ -18,7 +18,7 @@ import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
from os.path import basename, getsize, isdir, isfile, islink, join
|
||||
from os.path import abspath, basename, getsize, isdir, isfile, islink, join
|
||||
from tempfile import mkdtemp
|
||||
|
||||
import click
|
||||
@ -90,7 +90,8 @@ class PkgRepoMixin(object):
|
||||
reqspec = None
|
||||
if requirements:
|
||||
try:
|
||||
reqspec = semantic_version.Spec(requirements)
|
||||
reqspec = self.parse_semver_spec(
|
||||
requirements, raise_exception=True)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
@ -98,8 +99,8 @@ class PkgRepoMixin(object):
|
||||
if not self.is_system_compatible(v.get("system")):
|
||||
continue
|
||||
if "platformio" in v.get("engines", {}):
|
||||
if PkgRepoMixin.PIO_VERSION not in semantic_version.Spec(
|
||||
v['engines']['platformio']):
|
||||
if PkgRepoMixin.PIO_VERSION not in self.parse_semver_spec(
|
||||
v['engines']['platformio'], raise_exception=True):
|
||||
continue
|
||||
specver = semantic_version.Version(v['version'])
|
||||
if reqspec and specver not in reqspec:
|
||||
@ -224,7 +225,20 @@ class PkgInstallerMixin(object):
|
||||
@staticmethod
|
||||
def parse_semver_spec(value, raise_exception=False):
|
||||
try:
|
||||
return semantic_version.Spec(value)
|
||||
# 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
|
||||
@ -367,6 +381,12 @@ class PkgInstallerMixin(object):
|
||||
return manifest.get("__pkg_dir") if manifest and isdir(
|
||||
manifest.get("__pkg_dir")) else None
|
||||
|
||||
def get_package_by_dir(self, pkg_dir):
|
||||
for manifest in self.get_installed():
|
||||
if manifest['__pkg_dir'] == util.path_to_unicode(abspath(pkg_dir)):
|
||||
return manifest
|
||||
return None
|
||||
|
||||
def find_pkg_root(self, src_dir):
|
||||
if self.manifest_exists(src_dir):
|
||||
return src_dir
|
||||
@ -474,8 +494,8 @@ class PkgInstallerMixin(object):
|
||||
"Package version %s doesn't satisfy requirements %s" %
|
||||
(tmp_manifest['version'], requirements))
|
||||
try:
|
||||
assert tmp_semver and tmp_semver in semantic_version.Spec(
|
||||
requirements), mismatch_error
|
||||
assert tmp_semver and tmp_semver in self.parse_semver_spec(
|
||||
requirements, raise_exception=True), mismatch_error
|
||||
except (AssertionError, ValueError):
|
||||
assert tmp_manifest['version'] == requirements, mismatch_error
|
||||
|
||||
@ -500,8 +520,8 @@ class PkgInstallerMixin(object):
|
||||
cur_manifest['version'])
|
||||
if "__src_url" in cur_manifest:
|
||||
target_dirname = "%s@src-%s" % (
|
||||
pkg_dirname,
|
||||
hashlib.md5(cur_manifest['__src_url']).hexdigest())
|
||||
pkg_dirname, hashlib.md5(
|
||||
cur_manifest['__src_url']).hexdigest())
|
||||
shutil.move(pkg_dir, join(self.package_dir, target_dirname))
|
||||
# fix to a version
|
||||
elif action == 2:
|
||||
@ -509,8 +529,8 @@ class PkgInstallerMixin(object):
|
||||
tmp_manifest['version'])
|
||||
if "__src_url" in tmp_manifest:
|
||||
target_dirname = "%s@src-%s" % (
|
||||
pkg_dirname,
|
||||
hashlib.md5(tmp_manifest['__src_url']).hexdigest())
|
||||
pkg_dirname, hashlib.md5(
|
||||
tmp_manifest['__src_url']).hexdigest())
|
||||
pkg_dir = join(self.package_dir, target_dirname)
|
||||
|
||||
# remove previous/not-satisfied package
|
||||
@ -715,20 +735,20 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
||||
return pkg_dir
|
||||
|
||||
def uninstall(self, package, requirements=None, after_update=False):
|
||||
if isdir(package):
|
||||
if isdir(package) and self.get_package_by_dir(package):
|
||||
pkg_dir = package
|
||||
else:
|
||||
name, requirements, url = self.parse_pkg_uri(package, requirements)
|
||||
pkg_dir = self.get_package_dir(name, requirements, url)
|
||||
|
||||
if not pkg_dir:
|
||||
raise exception.UnknownPackage("%s @ %s" % (package,
|
||||
requirements or "*"))
|
||||
raise exception.UnknownPackage(
|
||||
"%s @ %s" % (package, requirements or "*"))
|
||||
|
||||
manifest = self.load_manifest(pkg_dir)
|
||||
click.echo(
|
||||
"Uninstalling %s @ %s: \t" %
|
||||
(click.style(manifest['name'], fg="cyan"), manifest['version']),
|
||||
"Uninstalling %s @ %s: \t" % (click.style(
|
||||
manifest['name'], fg="cyan"), manifest['version']),
|
||||
nl=False)
|
||||
|
||||
if islink(pkg_dir):
|
||||
@ -740,9 +760,9 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
||||
# unfix package with the same name
|
||||
pkg_dir = self.get_package_dir(manifest['name'])
|
||||
if pkg_dir and "@" in pkg_dir:
|
||||
shutil.move(pkg_dir,
|
||||
join(self.package_dir,
|
||||
self.get_install_dirname(manifest)))
|
||||
shutil.move(
|
||||
pkg_dir,
|
||||
join(self.package_dir, self.get_install_dirname(manifest)))
|
||||
self.cache_reset()
|
||||
|
||||
click.echo("[%s]" % click.style("OK", fg="green"))
|
||||
@ -755,14 +775,14 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
||||
return True
|
||||
|
||||
def update(self, package, requirements=None, only_check=False):
|
||||
if isdir(package):
|
||||
if isdir(package) and self.get_package_by_dir(package):
|
||||
pkg_dir = package
|
||||
else:
|
||||
pkg_dir = self.get_package_dir(*self.parse_pkg_uri(package))
|
||||
|
||||
if not pkg_dir:
|
||||
raise exception.UnknownPackage("%s @ %s" % (package,
|
||||
requirements or "*"))
|
||||
raise exception.UnknownPackage(
|
||||
"%s @ %s" % (package, requirements or "*"))
|
||||
|
||||
manifest = self.load_manifest(pkg_dir)
|
||||
name = manifest['name']
|
||||
|
@ -39,9 +39,9 @@ class PlatformManager(BasePkgManager):
|
||||
"{0}://dl.platformio.org/platforms/manifest.json".format(
|
||||
"https" if app.get_setting("enable_ssl") else "http")
|
||||
]
|
||||
BasePkgManager.__init__(self, package_dir
|
||||
or join(util.get_home_dir(), "platforms"),
|
||||
repositories)
|
||||
BasePkgManager.__init__(
|
||||
self, package_dir or join(util.get_home_dir(), "platforms"),
|
||||
repositories)
|
||||
|
||||
@property
|
||||
def manifest_names(self):
|
||||
@ -331,8 +331,8 @@ class PlatformPackagesMixin(object):
|
||||
def get_package_dir(self, name):
|
||||
version = self.packages[name].get("version", "")
|
||||
if ":" in version:
|
||||
return self.pm.get_package_dir(*self.pm.parse_pkg_uri(
|
||||
"%s=%s" % (name, version)))
|
||||
return self.pm.get_package_dir(
|
||||
*self.pm.parse_pkg_uri("%s=%s" % (name, version)))
|
||||
return self.pm.get_package_dir(name, version)
|
||||
|
||||
def get_package_version(self, name):
|
||||
|
@ -36,30 +36,40 @@ from platformio import __apiurl__, __version__, exception
|
||||
# pylint: disable=wrong-import-order, too-many-ancestors
|
||||
|
||||
try:
|
||||
from configparser import ConfigParser
|
||||
import configparser as ConfigParser
|
||||
except ImportError:
|
||||
from ConfigParser import ConfigParser
|
||||
import ConfigParser as ConfigParser
|
||||
|
||||
|
||||
class ProjectConfig(ConfigParser):
|
||||
class ProjectConfig(ConfigParser.ConfigParser):
|
||||
|
||||
VARTPL_RE = re.compile(r"\$\{([^\.\}]+)\.([^\}]+)\}")
|
||||
|
||||
def items(self, section, **_): # pylint: disable=arguments-differ
|
||||
items = []
|
||||
for option in ConfigParser.options(self, section):
|
||||
for option in ConfigParser.ConfigParser.options(self, section):
|
||||
items.append((option, self.get(section, option)))
|
||||
return items
|
||||
|
||||
def get(self, section, option, **kwargs):
|
||||
value = ConfigParser.get(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 == "env" and not self.has_section(section):
|
||||
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)
|
||||
|
||||
@ -331,7 +341,10 @@ def load_project_config(path=None):
|
||||
raise exception.NotPlatformIOProject(
|
||||
dirname(path) if path.endswith("platformio.ini") else path)
|
||||
cp = ProjectConfig()
|
||||
cp.read(path)
|
||||
try:
|
||||
cp.read(path)
|
||||
except ConfigParser.Error as e:
|
||||
raise exception.InvalidProjectConf(str(e))
|
||||
return cp
|
||||
|
||||
|
||||
|
@ -29,8 +29,9 @@ build_flags = %s
|
||||
""" % " ".join([f[0] for f in build_flags]))
|
||||
|
||||
tmpdir.join("extra.py").write("""
|
||||
Import("env")
|
||||
env.Append(CPPDEFINES="POST_SCRIPT_MACRO")
|
||||
Import("projenv")
|
||||
|
||||
projenv.Append(CPPDEFINES="POST_SCRIPT_MACRO")
|
||||
""")
|
||||
|
||||
tmpdir.mkdir("src").join("main.cpp").write("""
|
||||
|
Reference in New Issue
Block a user