Merge branch 'release/v3.6.1'

This commit is contained in:
Ivan Kravets
2018-10-29 14:10:56 +02:00
56 changed files with 1194 additions and 832 deletions

View File

@ -1,12 +1,18 @@
build: off build: off
environment:
platform:
- x86
- x64
environment:
matrix: matrix:
- TOXENV: "py27" - TOXENV: "py27"
install: install:
- cmd: git submodule update --init --recursive - cmd: git submodule update --init --recursive
- cmd: SET PATH=%PATH%;C:\Python27\Scripts;C:\MinGW\bin - cmd: SET PATH=C:\MinGW\bin;%PATH%
- if %PLATFORM% == x64 SET PATH=C:\Python27-x64;C:\Python27-x64\Scripts;%PATH%
- if %PLATFORM% == x86 SET PATH=C:\Python27;C:\Python27\Scripts;%PATH%
- cmd: pip install tox - cmd: pip install tox
test_script: test_script:

View File

@ -20,4 +20,4 @@ confidence=
# --disable=W" # --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=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 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

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,7 @@ PlatformIO
`PIO Plus <https://platformio.org/pricing?utm_source=github&utm_medium=core>`_ | `PIO Plus <https://platformio.org/pricing?utm_source=github&utm_medium=core>`_ |
`PlatformIO IDE <https://platformio.org/platformio-ide?utm_source=github&utm_medium=core>`_ | `PlatformIO IDE <https://platformio.org/platformio-ide?utm_source=github&utm_medium=core>`_ |
`Project Examples <https://github.com/platformio/platformio-examples/>`_ | `Project Examples <https://github.com/platformio/platformio-examples/>`_ |
`Docs <http://docs.platformio.org?utm_source=github&utm_medium=core>`_ | `Docs <https://docs.platformio.org?utm_source=github&utm_medium=core>`_ |
`Donate <https://platformio.org/donate?utm_source=github&utm_medium=core>`_ | `Donate <https://platformio.org/donate?utm_source=github&utm_medium=core>`_ |
`Contact Us <https://platformio.org/contact?utm_source=github&utm_medium=core>`_ `Contact Us <https://platformio.org/contact?utm_source=github&utm_medium=core>`_
@ -45,26 +45,26 @@ firmware updates.
Get Started Get Started
----------- -----------
* `What is PlatformIO? <http://docs.platformio.org/en/latest/what-is-platformio.html?utm_source=github&utm_medium=core>`_ * `What is PlatformIO? <https://docs.platformio.org/en/latest/what-is-platformio.html?utm_source=github&utm_medium=core>`_
Open Source Open Source
----------- -----------
* `PlatformIO IDE <https://platformio.org/platformio-ide?utm_source=github&utm_medium=core>`_ * `PlatformIO IDE <https://platformio.org/platformio-ide?utm_source=github&utm_medium=core>`_
* `PlatformIO Core (CLI) <http://docs.platformio.org/en/latest/core.html?utm_source=github&utm_medium=core>`_ * `PlatformIO Core (CLI) <https://docs.platformio.org/en/latest/core.html?utm_source=github&utm_medium=core>`_
* `Library Management <http://docs.platformio.org/page/librarymanager/index.html?utm_source=github&utm_medium=core>`_ * `Library Management <https://docs.platformio.org/page/librarymanager/index.html?utm_source=github&utm_medium=core>`_
* `Project Examples <https://github.com/platformio/platformio-examples?utm_source=github&utm_medium=core>`_ * `Project Examples <https://github.com/platformio/platformio-examples?utm_source=github&utm_medium=core>`_
* `Desktop IDEs Integration <http://docs.platformio.org/page/ide.html?utm_source=github&utm_medium=core>`_ * `Desktop IDEs Integration <https://docs.platformio.org/page/ide.html?utm_source=github&utm_medium=core>`_
* `Continuous Integration <http://docs.platformio.org/page/ci/index.html?utm_source=github&utm_medium=core>`_ * `Continuous Integration <https://docs.platformio.org/page/ci/index.html?utm_source=github&utm_medium=core>`_
* `Advanced Scripting API <http://docs.platformio.org/page/projectconf/advanced_scripting.html?utm_source=github&utm_medium=core>`_ * `Advanced Scripting API <https://docs.platformio.org/page/projectconf/advanced_scripting.html?utm_source=github&utm_medium=core>`_
PIO Plus PIO Plus
-------- --------
* `PIO Remote <http://docs.platformio.org/page/plus/pio-remote.html?utm_source=github&utm_medium=core>`_ * `PIO Remote <https://docs.platformio.org/page/plus/pio-remote.html?utm_source=github&utm_medium=core>`_
* `PIO Unified Debugger <http://docs.platformio.org/page/plus/debugging.html?utm_source=github&utm_medium=core>`_ * `PIO Unified Debugger <https://docs.platformio.org/page/plus/debugging.html?utm_source=github&utm_medium=core>`_
* `PIO Unit Testing <http://docs.platformio.org/en/latest/plus/unit-testing.html?utm_source=github&utm_medium=core>`_ * `PIO Unit Testing <https://docs.platformio.org/en/latest/plus/unit-testing.html?utm_source=github&utm_medium=core>`_
* `Cloud IDEs Integration <http://docs.platformio.org/en/latest/ide.html?utm_source=github&utm_medium=core#solution-pio-delivery>`_ * `Cloud IDEs Integration <https://docs.platformio.org/en/latest/ide.html?utm_source=github&utm_medium=core#solution-pio-delivery>`_
* `Integration Services <https://platformio.org/pricing?utm_source=github&utm_medium=core#enterprise-features>`_ * `Integration Services <https://platformio.org/pricing?utm_source=github&utm_medium=core#enterprise-features>`_
Registry Registry
@ -85,6 +85,7 @@ Development Platforms
* `Freescale Kinetis <https://platformio.org/platforms/freescalekinetis?utm_source=github&utm_medium=core>`_ * `Freescale Kinetis <https://platformio.org/platforms/freescalekinetis?utm_source=github&utm_medium=core>`_
* `Infineon XMC <https://platformio.org/platforms/infineonxmc?utm_source=github&utm_medium=core>`_ * `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 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>`_
* `Lattice iCE40 <https://platformio.org/platforms/lattice_ice40?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>`_ * `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>`_ * `Microchip PIC32 <https://platformio.org/platforms/microchippic32?utm_source=github&utm_medium=core>`_

2
docs

Submodule docs updated: 21c1cf522c...30c88f6247

View File

@ -14,7 +14,7 @@
import sys import sys
VERSION = (3, 6, 0) VERSION = (3, 6, 1)
__version__ = ".".join([str(s) for s in VERSION]) __version__ = ".".join([str(s) for s in VERSION])
__title__ = "platformio" __title__ = "platformio"
@ -26,8 +26,8 @@ __description__ = (
"FPGA, CMSIS, SPL, AVR, Samsung ARTIK, libOpenCM3") "FPGA, CMSIS, SPL, AVR, Samsung ARTIK, libOpenCM3")
__url__ = "https://platformio.org" __url__ = "https://platformio.org"
__author__ = "Ivan Kravets" __author__ = "PlatformIO"
__email__ = "me@ikravets.com" __email__ = "contact@platformio.org"
__license__ = "Apache Software License" __license__ = "Apache Software License"
__copyright__ = "Copyright 2014-present PlatformIO" __copyright__ = "Copyright 2014-present PlatformIO"

View File

@ -107,8 +107,8 @@ def configure():
try: try:
click_echo_origin[origin](*args, **kwargs) click_echo_origin[origin](*args, **kwargs)
except IOError: except IOError:
(sys.stderr.write if kwargs.get("err") else (sys.stderr.write if kwargs.get("err") else sys.stdout.write)(
sys.stdout.write)("%s\n" % (args[0] if args else "")) "%s\n" % (args[0] if args else ""))
click.echo = lambda *args, **kwargs: _safe_echo(0, *args, **kwargs) click.echo = lambda *args, **kwargs: _safe_echo(0, *args, **kwargs)
click.secho = lambda *args, **kwargs: _safe_echo(1, *args, **kwargs) click.secho = lambda *args, **kwargs: _safe_echo(1, *args, **kwargs)
@ -135,7 +135,7 @@ An unexpected error occurred. Further steps:
`pip install -U platformio` command `pip install -U platformio` command
* Try to find answer in FAQ Troubleshooting section * Try to find answer in FAQ Troubleshooting section
http://docs.platformio.org/page/faq.html https://docs.platformio.org/page/faq.html
* Report this problem to the developers * Report this problem to the developers
https://github.com/platformio/platformio-core/issues https://github.com/platformio/platformio-core/issues

View File

@ -63,7 +63,7 @@ DEFAULT_SETTINGS = {
}, },
"enable_telemetry": { "enable_telemetry": {
"description": "description":
("Telemetry service <http://docs.platformio.org/page/" ("Telemetry service <https://docs.platformio.org/page/"
"userguide/cmd_settings.html?#enable-telemetry> (Yes/No)"), "userguide/cmd_settings.html?#enable-telemetry> (Yes/No)"),
"value": "value":
True True
@ -352,8 +352,8 @@ def get_cid():
pass pass
cid = str( cid = str(
uuid.UUID( uuid.UUID(
bytes=hashlib.md5(str(_uid if _uid else uuid.getnode())) bytes=hashlib.md5(str(_uid if _uid else uuid.getnode())).
.digest())) digest()))
if "windows" in util.get_systype() or os.getuid() > 0: if "windows" in util.get_systype() or os.getuid() > 0:
set_state_item("cid", cid) set_state_item("cid", cid)
return cid return cid

View File

@ -135,7 +135,7 @@ if env.GetOption('clean'):
env.PioClean(env.subst("$BUILD_DIR")) env.PioClean(env.subst("$BUILD_DIR"))
env.Exit(0) env.Exit(0)
elif not int(ARGUMENTS.get("PIOVERBOSE", 0)): elif not int(ARGUMENTS.get("PIOVERBOSE", 0)):
print "Verbose mode can be enabled via `-v, --verbose` option" print("Verbose mode can be enabled via `-v, --verbose` option")
# Handle custom variables from system environment # Handle custom variables from system environment
for var in ("BUILD_FLAGS", "SRC_BUILD_FLAGS", "SRC_FILTER", "EXTRA_SCRIPTS", for var in ("BUILD_FLAGS", "SRC_BUILD_FLAGS", "SRC_FILTER", "EXTRA_SCRIPTS",
@ -191,24 +191,25 @@ env.AddPreAction(
env.VerboseAction(lambda source, target, env: env.PrintUploadInfo(), env.VerboseAction(lambda source, target, env: env.PrintUploadInfo(),
"Configuring upload protocol...")) "Configuring upload protocol..."))
AlwaysBuild(env.Alias("debug", DEFAULT_TARGETS))
AlwaysBuild(env.Alias("__debug", DEFAULT_TARGETS)) AlwaysBuild(env.Alias("__debug", DEFAULT_TARGETS))
AlwaysBuild(env.Alias("__test", DEFAULT_TARGETS)) AlwaysBuild(env.Alias("__test", DEFAULT_TARGETS))
############################################################################## ##############################################################################
if "envdump" in COMMAND_LINE_TARGETS: if "envdump" in COMMAND_LINE_TARGETS:
print env.Dump() print(env.Dump())
env.Exit(0) env.Exit(0)
if "idedata" in COMMAND_LINE_TARGETS: if "idedata" in COMMAND_LINE_TARGETS:
try: try:
print "\n%s\n" % util.path_to_unicode( print("\n%s\n" % util.path_to_unicode(
json.dumps(env.DumpIDEData(), ensure_ascii=False)) json.dumps(env.DumpIDEData(), ensure_ascii=False)))
env.Exit(0) env.Exit(0)
except UnicodeDecodeError: except UnicodeDecodeError:
sys.stderr.write( sys.stderr.write(
"\nUnicodeDecodeError: Non-ASCII characters found in build " "\nUnicodeDecodeError: Non-ASCII characters found in build "
"environment\n" "environment\n"
"See explanation in FAQ > Troubleshooting > Building\n" "See explanation in FAQ > Troubleshooting > Building\n"
"http://docs.platformio.org/page/faq.html\n\n") "https://docs.platformio.org/page/faq.html\n\n")
env.Exit(1) env.Exit(1)

View File

@ -25,7 +25,7 @@ from platformio.managers.core import get_core_package_dir
def _dump_includes(env): def _dump_includes(env):
includes = [] includes = [env.subst("$PROJECTINCLUDE_DIR"), env.subst("$PROJECTSRC_DIR")]
for item in env.get("CPPPATH", []): for item in env.get("CPPPATH", []):
includes.append(env.subst(item)) includes.append(env.subst(item))
@ -97,8 +97,8 @@ def _dump_defines(env):
board_mcu = env.BoardConfig().get("build.mcu") board_mcu = env.BoardConfig().get("build.mcu")
if board_mcu: if board_mcu:
defines.append( defines.append(
str("__AVR_%s__" % board_mcu.upper() str("__AVR_%s__" % board_mcu.upper().replace(
.replace("ATMEGA", "ATmega").replace("ATTINY", "ATtiny"))) "ATMEGA", "ATmega").replace("ATTINY", "ATtiny")))
# built-in GCC marcos # built-in GCC marcos
# if env.GetCompilerType() == "gcc": # if env.GetCompilerType() == "gcc":

View File

@ -373,7 +373,7 @@ class LibBuilderBase(object):
if isfile("%s.%s" % (_f_part, ext)): if isfile("%s.%s" % (_f_part, ext)):
incs.append( incs.append(
self.env.File("%s.%s" % (_f_part, ext))) self.env.File("%s.%s" % (_f_part, ext)))
# print path, map(lambda n: n.get_abspath(), incs) # print(path, map(lambda n: n.get_abspath(), incs))
for inc in incs: for inc in incs:
if inc not in result: if inc not in result:
result.append(inc) result.append(inc)
@ -808,7 +808,7 @@ def GetLibBuilders(env): # pylint: disable=too-many-branches
if verbose and found_incompat: if verbose and found_incompat:
sys.stderr.write( sys.stderr.write(
"More details about \"Library Compatibility Mode\": " "More details about \"Library Compatibility Mode\": "
"http://docs.platformio.org/page/librarymanager/ldf.html#" "https://docs.platformio.org/page/librarymanager/ldf.html#"
"ldf-compat-mode\n") "ldf-compat-mode\n")
DefaultEnvironment()['__PIO_LIB_BUILDERS'] = items DefaultEnvironment()['__PIO_LIB_BUILDERS'] = items
@ -851,24 +851,24 @@ def ConfigureProjectLibBuilder(env):
project = ProjectAsLibBuilder(env, "$PROJECT_DIR") project = ProjectAsLibBuilder(env, "$PROJECT_DIR")
ldf_mode = LibBuilderBase.lib_ldf_mode.fget(project) ldf_mode = LibBuilderBase.lib_ldf_mode.fget(project)
print "Library Dependency Finder -> http://bit.ly/configure-pio-ldf" print("Library Dependency Finder -> http://bit.ly/configure-pio-ldf")
print "LDF MODES: FINDER(%s) COMPATIBILITY(%s)" % (ldf_mode, print("LDF MODES: FINDER(%s) COMPATIBILITY(%s)" %
project.lib_compat_mode) (ldf_mode, project.lib_compat_mode))
lib_builders = env.GetLibBuilders() lib_builders = env.GetLibBuilders()
print "Collected %d compatible libraries" % len(lib_builders) print("Collected %d compatible libraries" % len(lib_builders))
print "Scanning dependencies..." print("Scanning dependencies...")
project.search_deps_recursive() project.search_deps_recursive()
if ldf_mode.startswith("chain") and project.depbuilders: if ldf_mode.startswith("chain") and project.depbuilders:
correct_found_libs(lib_builders) correct_found_libs(lib_builders)
if project.depbuilders: if project.depbuilders:
print "Dependency Graph" print("Dependency Graph")
print_deps_tree(project) print_deps_tree(project)
else: else:
print "No dependencies" print("No dependencies")
return project return project

View File

@ -274,13 +274,13 @@ def VerboseAction(_, act, actstr):
def PioClean(env, clean_dir): def PioClean(env, clean_dir):
if not isdir(clean_dir): if not isdir(clean_dir):
print "Build environment is clean" print("Build environment is clean")
env.Exit(0) env.Exit(0)
for root, _, files in walk(clean_dir): for root, _, files in walk(clean_dir):
for file_ in files: for file_ in files:
remove(join(root, file_)) remove(join(root, file_))
print "Removed %s" % relpath(join(root, file_)) print("Removed %s" % relpath(join(root, file_)))
print "Done cleaning" print("Done cleaning")
util.rmtree_(clean_dir) util.rmtree_(clean_dir)
env.Exit(0) env.Exit(0)
@ -288,10 +288,14 @@ def PioClean(env, clean_dir):
def ProcessDebug(env): def ProcessDebug(env):
if not env.subst("$PIODEBUGFLAGS"): if not env.subst("$PIODEBUGFLAGS"):
env.Replace(PIODEBUGFLAGS=["-Og", "-g3", "-ggdb3"]) env.Replace(PIODEBUGFLAGS=["-Og", "-g3", "-ggdb3"])
env.Append(PIODEBUGFLAGS=["-D__PLATFORMIO_DEBUG__"])
env.Append( env.Append(
BUILD_FLAGS=env.get("PIODEBUGFLAGS", []), PIODEBUGFLAGS=["-D__PLATFORMIO_DEBUG__"],
BUILD_UNFLAGS=["-Os", "-O0", "-O1", "-O2", "-O3"]) BUILD_FLAGS=env.get("PIODEBUGFLAGS", []))
unflags = ["-Os"]
for level in [0, 1, 2]:
for flag in ("O", "g", "ggdb"):
unflags.append("-%s%d" % (flag, level))
env.Append(BUILD_UNFLAGS=unflags)
def ProcessTest(env): def ProcessTest(env):

View File

@ -23,7 +23,7 @@ from SCons.Script import COMMAND_LINE_TARGETS
from platformio import exception, util from platformio import exception, util
from platformio.managers.platform import PlatformFactory from platformio.managers.platform import PlatformFactory
# pylint: disable=too-many-branches # pylint: disable=too-many-branches, too-many-locals
@util.memoized() @util.memoized()
@ -122,8 +122,10 @@ def LoadPioPlatform(env, variables):
def PrintConfiguration(env): def PrintConfiguration(env):
platform_data = ["PLATFORM: %s >" % env.PioPlatform().title] platform = env.PioPlatform()
platform_data = ["PLATFORM: %s >" % platform.title]
system_data = ["SYSTEM:"] system_data = ["SYSTEM:"]
configuration_data = ["CONFIGURATION:"]
mcu = env.subst("$BOARD_MCU") mcu = env.subst("$BOARD_MCU")
f_cpu = env.subst("$BOARD_F_CPU") f_cpu = env.subst("$BOARD_F_CPU")
if mcu: if mcu:
@ -142,11 +144,13 @@ def PrintConfiguration(env):
flash = board_config.get("upload", {}).get("maximum_size") flash = board_config.get("upload", {}).get("maximum_size")
system_data.append("%s RAM (%s Flash)" % (util.format_filesize(ram), system_data.append("%s RAM (%s Flash)" % (util.format_filesize(ram),
util.format_filesize(flash))) util.format_filesize(flash)))
configuration_data.append(
"https://docs.platformio.org/page/boards/%s/%s.html" %
(platform.name, board_config.id))
if platform_data: for data in (configuration_data, platform_data, system_data):
print " ".join(platform_data) if len(data) > 1:
if system_data: print(" ".join(data))
print " ".join(system_data)
# Debugging # Debugging
if not debug_tools: if not debug_tools:
@ -168,7 +172,7 @@ def PrintConfiguration(env):
if external: if external:
data.append("EXTERNAL(%s)" % ", ".join(sorted(external))) data.append("EXTERNAL(%s)" % ", ".join(sorted(external)))
print "DEBUG: %s" % " ".join(data) print("DEBUG: %s" % " ".join(data))
def exists(_): def exists(_):

View File

@ -25,7 +25,7 @@ from time import sleep
from SCons.Script import ARGUMENTS from SCons.Script import ARGUMENTS
from serial import Serial, SerialException from serial import Serial, SerialException
from platformio import util from platformio import exception, util
# pylint: disable=unused-argument # pylint: disable=unused-argument
@ -43,7 +43,7 @@ def FlushSerialBuffer(env, port):
def TouchSerialPort(env, port, baudrate): def TouchSerialPort(env, port, baudrate):
port = env.subst(port) port = env.subst(port)
print "Forcing reset using %dbps open/close on port %s" % (baudrate, port) print("Forcing reset using %dbps open/close on port %s" % (baudrate, port))
try: try:
s = Serial(port=port, baudrate=baudrate) s = Serial(port=port, baudrate=baudrate)
s.setDTR(False) s.setDTR(False)
@ -54,7 +54,7 @@ def TouchSerialPort(env, port, baudrate):
def WaitForNewSerialPort(env, before): def WaitForNewSerialPort(env, before):
print "Waiting for the new upload port..." print("Waiting for the new upload port...")
prev_port = env.subst("$UPLOAD_PORT") prev_port = env.subst("$UPLOAD_PORT")
new_port = None new_port = None
elapsed = 0 elapsed = 0
@ -146,7 +146,7 @@ def AutodetectUploadPort(*args, **kwargs):
return port return port
if "UPLOAD_PORT" in env and not _get_pattern(): if "UPLOAD_PORT" in env and not _get_pattern():
print env.subst("Use manually specified: $UPLOAD_PORT") print(env.subst("Use manually specified: $UPLOAD_PORT"))
return return
if (env.subst("$UPLOAD_PROTOCOL") == "mbed" if (env.subst("$UPLOAD_PROTOCOL") == "mbed"
@ -154,19 +154,14 @@ def AutodetectUploadPort(*args, **kwargs):
and not env.subst("$UPLOAD_PROTOCOL"))): and not env.subst("$UPLOAD_PROTOCOL"))):
env.Replace(UPLOAD_PORT=_look_for_mbed_disk()) env.Replace(UPLOAD_PORT=_look_for_mbed_disk())
else: else:
if ("linux" in util.get_systype() and not any([ try:
isfile("/etc/udev/rules.d/99-platformio-udev.rules"), util.ensure_udev_rules()
isfile("/lib/udev/rules.d/99-platformio-udev.rules") except exception.InvalidUdevRules as e:
])): sys.stderr.write("\n%s\n\n" % e)
sys.stderr.write(
"\nWarning! Please install `99-platformio-udev.rules` and "
"check that your board's PID and VID are listed in the rules."
"\n http://docs.platformio.org/en/latest/faq.html"
"#platformio-udev-rules\n")
env.Replace(UPLOAD_PORT=_look_for_serial_port()) env.Replace(UPLOAD_PORT=_look_for_serial_port())
if env.subst("$UPLOAD_PORT"): if env.subst("$UPLOAD_PORT"):
print env.subst("Auto-detected: $UPLOAD_PORT") print(env.subst("Auto-detected: $UPLOAD_PORT"))
else: else:
sys.stderr.write( sys.stderr.write(
"Error: Please specify `upload_port` for environment or use " "Error: Please specify `upload_port` for environment or use "
@ -185,8 +180,8 @@ def UploadToDisk(_, target, source, env):
continue continue
copyfile(fpath, copyfile(fpath,
join(env.subst("$UPLOAD_PORT"), "%s.%s" % (progname, ext))) join(env.subst("$UPLOAD_PORT"), "%s.%s" % (progname, ext)))
print "Firmware has been successfully uploaded.\n"\ print("Firmware has been successfully uploaded.\n"
"(Some boards may require manual hard reset)" "(Some boards may require manual hard reset)")
def CheckUploadSize(_, target, source, env): def CheckUploadSize(_, target, source, env):
@ -251,14 +246,14 @@ def CheckUploadSize(_, target, source, env):
program_size = _calculate_size(output, env.get("SIZEPROGREGEXP")) program_size = _calculate_size(output, env.get("SIZEPROGREGEXP"))
data_size = _calculate_size(output, env.get("SIZEDATAREGEXP")) data_size = _calculate_size(output, env.get("SIZEDATAREGEXP"))
print "Memory Usage -> http://bit.ly/pio-memory-usage" print("Memory Usage -> http://bit.ly/pio-memory-usage")
if data_max_size and data_size > -1: if data_max_size and data_size > -1:
print "DATA: %s" % _format_availale_bytes(data_size, data_max_size) print("DATA: %s" % _format_availale_bytes(data_size, data_max_size))
if program_size > -1: if program_size > -1:
print "PROGRAM: %s" % _format_availale_bytes(program_size, print("PROGRAM: %s" % _format_availale_bytes(program_size,
program_max_size) program_max_size))
if int(ARGUMENTS.get("PIOVERBOSE", 0)): if int(ARGUMENTS.get("PIOVERBOSE", 0)):
print output print(output)
# raise error # raise error
# if data_max_size and data_size > data_max_size: # if data_max_size and data_size > data_max_size:
@ -280,9 +275,9 @@ def PrintUploadInfo(env):
available.extend(env.BoardConfig().get("upload", {}).get( available.extend(env.BoardConfig().get("upload", {}).get(
"protocols", [])) "protocols", []))
if available: if available:
print "AVAILABLE: %s" % ", ".join(sorted(set(available))) print("AVAILABLE: %s" % ", ".join(sorted(set(available))))
if configured: if configured:
print "CURRENT: upload_protocol = %s" % configured print("CURRENT: upload_protocol = %s" % configured)
def exists(_): def exists(_):

View File

@ -93,7 +93,7 @@ def BuildProgram(env):
if not Util.case_sensitive_suffixes(".s", ".S"): if not Util.case_sensitive_suffixes(".s", ".S"):
env.Replace(AS="$CC", ASCOM="$ASPPCOM") env.Replace(AS="$CC", ASCOM="$ASPPCOM")
if "__debug" in COMMAND_LINE_TARGETS: if set(["__debug", "debug"]) & set(COMMAND_LINE_TARGETS):
env.ProcessDebug() env.ProcessDebug()
# process extra flags from board # process extra flags from board
@ -141,10 +141,15 @@ def BuildProgram(env):
return program return program
def ParseFlagsExtended(env, flags): def ParseFlagsExtended(env, flags): # pylint: disable=too-many-branches
if isinstance(flags, list): if not isinstance(flags, list):
flags = " ".join(flags) flags = [flags]
result = env.ParseFlags(str(flags)) result = {}
for raw in flags:
for key, value in env.ParseFlags(str(raw)).items():
if key not in result:
result[key] = []
result[key].extend(value)
cppdefines = [] cppdefines = []
for item in result['CPPDEFINES']: for item in result['CPPDEFINES']:
@ -319,6 +324,7 @@ def BuildFrameworks(env, frameworks):
def BuildLibrary(env, variant_dir, src_dir, src_filter=None): def BuildLibrary(env, variant_dir, src_dir, src_filter=None):
env.ProcessUnFlags(env.get("BUILD_UNFLAGS"))
return env.StaticLibrary( return env.StaticLibrary(
env.subst(variant_dir), env.subst(variant_dir),
env.CollectBuildFiles(variant_dir, src_dir, src_filter)) env.CollectBuildFiles(variant_dir, src_dir, src_filter))

View File

@ -86,7 +86,7 @@ def cli( # pylint: disable=too-many-arguments
app.set_session_var("force_option", True) app.set_session_var("force_option", True)
_clean_dir(build_dir) _clean_dir(build_dir)
for dir_name, patterns in dict(lib=lib, src=src).iteritems(): for dir_name, patterns in dict(lib=lib, src=src).items():
if not patterns: if not patterns:
continue continue
contents = [] contents = []

View File

@ -55,7 +55,7 @@ def device_list( # pylint: disable=too-many-branches
"mdns": "Multicast DNS Services" "mdns": "Multicast DNS Services"
} }
for key, value in data.iteritems(): for key, value in data.items():
if not single_key: if not single_key:
click.secho(titles[key], bold=True) click.secho(titles[key], bold=True)
click.echo("=" * len(titles[key])) click.echo("=" * len(titles[key]))
@ -85,7 +85,7 @@ def device_list( # pylint: disable=too-many-branches
if item['properties']: if item['properties']:
click.echo("Properties: %s" % ("; ".join([ click.echo("Properties: %s" % ("; ".join([
"%s=%s" % (k, v) "%s=%s" % (k, v)
for k, v in item['properties'].iteritems() for k, v in item['properties'].items()
]))) ])))
click.echo("") click.echo("")
@ -182,7 +182,7 @@ def device_monitor(**kwargs): # pylint: disable=too-many-branches
kwargs['port'] = ports[0]['port'] kwargs['port'] = ports[0]['port']
sys.argv = ["monitor"] sys.argv = ["monitor"]
for k, v in kwargs.iteritems(): for k, v in kwargs.items():
if k in ("port", "baud", "rts", "dtr", "environment", "project_dir"): if k in ("port", "baud", "rts", "dtr", "environment", "project_dir"):
continue continue
k = "--" + k.replace("_", "-") k = "--" + k.replace("_", "-")

View File

@ -15,7 +15,6 @@
import sys import sys
import click import click
import requests
from platformio.managers.core import pioplus_call from platformio.managers.core import pioplus_call
@ -30,13 +29,3 @@ from platformio.managers.core import pioplus_call
@click.option("--no-open", is_flag=True) @click.option("--no-open", is_flag=True)
def cli(*args, **kwargs): # pylint: disable=unused-argument def cli(*args, **kwargs): # pylint: disable=unused-argument
pioplus_call(sys.argv[1:]) pioplus_call(sys.argv[1:])
def shutdown_servers():
port = 8010
while port < 9000:
try:
requests.get("http://127.0.0.1:%d?__shutdown__=1" % port)
port += 1
except: # pylint: disable=bare-except
return

View File

@ -73,22 +73,21 @@ def cli(
click.secho( click.secho(
"\nThe current working directory", fg="yellow", nl=False) "\nThe current working directory", fg="yellow", nl=False)
click.secho(" %s " % project_dir, fg="cyan", nl=False) click.secho(" %s " % project_dir, fg="cyan", nl=False)
click.secho( click.secho("will be used for the project.", fg="yellow")
"will be used for project.\n"
"You can specify another project directory via\n"
"`platformio init -d %PATH_TO_THE_PROJECT_DIR%` command.",
fg="yellow")
click.echo("") click.echo("")
click.echo("The next files/directories have been created in %s" % click.echo("The next files/directories have been created in %s" %
click.style(project_dir, fg="cyan")) click.style(project_dir, fg="cyan"))
click.echo("%s - Project Configuration File" % click.style( click.echo("%s - Put project header files here" % click.style(
"platformio.ini", fg="cyan")) "include", fg="cyan"))
click.echo(
"%s - Put your source files here" % click.style("src", fg="cyan"))
click.echo("%s - Put here project specific (private) libraries" % click.echo("%s - Put here project specific (private) libraries" %
click.style("lib", fg="cyan")) click.style("lib", fg="cyan"))
click.echo("%s - Put project source files here" % click.style(
"src", fg="cyan"))
click.echo("%s - Project Configuration File" % click.style(
"platformio.ini", fg="cyan"))
is_new_project = util.is_platformio_project(project_dir)
init_base_project(project_dir) init_base_project(project_dir)
if board: if board:
@ -102,16 +101,28 @@ def cli(
pg = ProjectGenerator(project_dir, ide, env_name) pg = ProjectGenerator(project_dir, ide, env_name)
pg.generate() pg.generate()
if not silent: if is_new_project:
init_ci_conf(project_dir)
init_cvs_ignore(project_dir)
if silent:
return
if ide:
click.secho( click.secho(
"\nProject has been successfully initialized!\nUseful commands:\n" "\nProject has been successfully %s including configuration files "
"`platformio run` - process/build project from the current " "for `%s` IDE." % ("initialized" if is_new_project else "updated",
"directory\n" ide),
"`platformio run --target upload` or `platformio run -t upload` " fg="green")
"- upload firmware to embedded board\n" else:
"`platformio run --target clean` - clean project (remove compiled " click.secho(
"files)\n" "\nProject has been successfully %s! Useful commands:\n"
"`platformio run --help` - additional information", "`pio run` - process/build project from the current directory\n"
"`pio run --target upload` or `pio run -t upload` "
"- upload firmware to a target\n"
"`pio run --target clean` - clean project (remove compiled files)"
"\n`pio run --help` - additional information" %
("initialized" if is_new_project else "updated"),
fg="green") fg="green")
@ -134,35 +145,82 @@ def get_best_envname(project_dir, boards=None):
def init_base_project(project_dir): def init_base_project(project_dir):
if not util.is_platformio_project(project_dir): if util.is_platformio_project(project_dir):
copyfile( return
join(util.get_source_dir(), "projectconftpl.ini"),
join(project_dir, "platformio.ini")) copyfile(
join(util.get_source_dir(), "projectconftpl.ini"),
join(project_dir, "platformio.ini"))
with util.cd(project_dir): with util.cd(project_dir):
lib_dir = util.get_projectlib_dir() dir_to_readme = [
src_dir = util.get_projectsrc_dir() (util.get_projectsrc_dir(), None),
for d in (src_dir, lib_dir): (util.get_projectinclude_dir(), init_include_readme),
if not isdir(d): (util.get_projectlib_dir(), init_lib_readme),
makedirs(d) (util.get_projecttest_dir(), init_test_readme),
]
for (path, cb) in dir_to_readme:
if isdir(path):
continue
makedirs(path)
if cb:
cb(path)
init_lib_readme(lib_dir)
init_ci_conf(project_dir) def init_include_readme(include_dir):
init_cvs_ignore(project_dir) with open(join(include_dir, "README"), "w") as f:
f.write("""
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
""")
def init_lib_readme(lib_dir): def init_lib_readme(lib_dir):
if isfile(join(lib_dir, "readme.txt")): with open(join(lib_dir, "README"), "w") as f:
return
with open(join(lib_dir, "readme.txt"), "w") as f:
f.write(""" f.write("""
This directory is intended for the project specific (private) libraries. This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link to executable file. PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in separate directory, like The source code of each library should be placed in a an own separate directory
"lib/private_lib/[here are source files]". ("lib/your_library_name/[here are source files]").
For example, see how can be organized `Foo` and `Bar` libraries: For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib |--lib
| | | |
@ -172,40 +230,62 @@ For example, see how can be organized `Foo` and `Bar` libraries:
| | |--src | | |--src
| | |- Bar.c | | |- Bar.c
| | |- Bar.h | | |- Bar.h
| | |- library.json (optional, custom build options, etc) http://docs.platformio.org/page/librarymanager/config.html | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| | | |
| |--Foo | |--Foo
| | |- Foo.c | | |- Foo.c
| | |- Foo.h | | |- Foo.h
| | | |
| |- readme.txt --> THIS FILE | |- README --> THIS FILE
| |
|- platformio.ini |- platformio.ini
|--src |--src
|- main.c |- main.c
Then in `src/main.c` you should use: and a contents of `src/main.c`:
```
#include <Foo.h> #include <Foo.h>
#include <Bar.h> #include <Bar.h>
// rest H/C/CPP code int main (void)
{
...
}
PlatformIO will find your libraries automatically, configure preprocessor's ```
include paths and build them.
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder More information about PlatformIO Library Dependency Finder
- http://docs.platformio.org/page/librarymanager/ldf.html - https://docs.platformio.org/page/librarymanager/ldf.html
""")
def init_test_readme(test_dir):
with open(join(test_dir, "README"), "w") as f:
f.write("""
This directory is intended for PIO Unit Testing and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html
""") """)
def init_ci_conf(project_dir): def init_ci_conf(project_dir):
if isfile(join(project_dir, ".travis.yml")): conf_path = join(project_dir, ".travis.yml")
if isfile(conf_path):
return return
with open(join(project_dir, ".travis.yml"), "w") as f: with open(conf_path, "w") as f:
f.write("""# Continuous Integration (CI) is the practice, in software f.write("""# Continuous Integration (CI) is the practice, in software
# engineering, of merging all developer working copies with a shared mainline # engineering, of merging all developer working copies with a shared mainline
# several times a day < http://docs.platformio.org/page/ci/index.html > # several times a day < https://docs.platformio.org/page/ci/index.html >
# #
# Documentation: # Documentation:
# #
@ -213,13 +293,13 @@ def init_ci_conf(project_dir):
# < https://docs.travis-ci.com/user/integration/platformio/ > # < https://docs.travis-ci.com/user/integration/platformio/ >
# #
# * PlatformIO integration with Travis CI # * PlatformIO integration with Travis CI
# < http://docs.platformio.org/page/ci/travis.html > # < https://docs.platformio.org/page/ci/travis.html >
# #
# * User Guide for `platformio ci` command # * User Guide for `platformio ci` command
# < http://docs.platformio.org/page/userguide/cmd_ci.html > # < https://docs.platformio.org/page/userguide/cmd_ci.html >
# #
# #
# Please choice one of the following templates (proposed below) and uncomment # Please choose one of the following templates (proposed below) and uncomment
# it (remove "# " before each line) or use own configuration according to the # it (remove "# " before each line) or use own configuration according to the
# Travis CI documentation (see above). # Travis CI documentation (see above).
# #
@ -247,7 +327,7 @@ def init_ci_conf(project_dir):
# #
# Template #2: The project is intended to by used as a library with examples # Template #2: The project is intended to be used as a library with examples.
# #
# language: python # language: python
@ -274,23 +354,11 @@ def init_ci_conf(project_dir):
def init_cvs_ignore(project_dir): def init_cvs_ignore(project_dir):
ignore_path = join(project_dir, ".gitignore") conf_path = join(project_dir, ".gitignore")
default = [".pioenvs\n", ".piolibdeps\n"] if isfile(conf_path):
current = []
modified = False
if isfile(ignore_path):
with open(ignore_path) as fp:
current = fp.readlines()
if current and not current[-1].endswith("\n"):
current[-1] += "\n"
for d in default:
if d not in current:
modified = True
current.append(d)
if not modified:
return return
with open(ignore_path, "w") as fp: with open(conf_path, "w") as fp:
fp.writelines(current) fp.writelines([".pio\n", ".pioenvs\n", ".piolibdeps\n"])
def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix, def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix,

View File

@ -203,7 +203,7 @@ def lib_search(query, json_output, page, noninteractive, **filters):
if not isinstance(query, list): if not isinstance(query, list):
query = list(query) query = list(query)
for key, values in filters.iteritems(): for key, values in filters.items():
for value in values: for value in values:
query.append('%s:"%s"' % (key, value)) query.append('%s:"%s"' % (key, value))
@ -228,7 +228,7 @@ def lib_search(query, json_output, page, noninteractive, **filters):
click.echo("For more examples and advanced search syntax, " click.echo("For more examples and advanced search syntax, "
"please use documentation:") "please use documentation:")
click.secho( click.secho(
"http://docs.platformio.org/page/userguide/lib/cmd_search.html\n", "https://docs.platformio.org/page/userguide/lib/cmd_search.html\n",
fg="cyan") fg="cyan")
return return
@ -307,13 +307,12 @@ def lib_builtin(storage, json_output):
def lib_show(library, json_output): def lib_show(library, json_output):
lm = LibraryManager() lm = LibraryManager()
name, requirements, _ = lm.parse_pkg_uri(library) name, requirements, _ = lm.parse_pkg_uri(library)
lib_id = lm.search_lib_id( lib_id = lm.search_lib_id({
{ "name": name,
"name": name, "requirements": requirements
"requirements": requirements },
}, silent=json_output,
silent=json_output, interactive=not json_output)
interactive=not json_output)
lib = get_api_result("/lib/info/%d" % lib_id, cache_valid="1d") lib = get_api_result("/lib/info/%d" % lib_id, cache_valid="1d")
if json_output: if json_output:
return click.echo(json.dumps(lib)) return click.echo(json.dumps(lib))
@ -423,16 +422,16 @@ def lib_stats(json_output):
click.echo("-" * terminal_width) click.echo("-" * terminal_width)
def _print_lib_item(item): def _print_lib_item(item):
click.echo((printitemdate_tpl date = str(
if "date" in item else printitem_tpl).format( time.strftime("%c", util.parse_date(item['date'])) if "date" in
name=click.style(item['name'], fg="cyan"), item else "")
date=str( url = click.style(
time.strftime("%c", util.parse_date(item['date'])) "https://platformio.org/lib/show/%s/%s" % (item['id'],
if "date" in item else ""), quote(item['name'])),
url=click.style( fg="blue")
"https://platformio.org/lib/show/%s/%s" % click.echo(
(item['id'], quote(item['name'])), (printitemdate_tpl if "date" in item else printitem_tpl).format(
fg="blue"))) name=click.style(item['name'], fg="cyan"), date=date, url=url))
def _print_tag_item(name): def _print_tag_item(name):
click.echo( click.echo(

View File

@ -273,8 +273,8 @@ def platform_show(platform, json_output): # pylint: disable=too-many-branches
if item['type']: if item['type']:
click.echo("Type: %s" % item['type']) click.echo("Type: %s" % item['type'])
click.echo("Requirements: %s" % item['requirements']) click.echo("Requirements: %s" % item['requirements'])
click.echo("Installed: %s" % ("Yes" if item.get("version") else click.echo("Installed: %s" %
"No (optional)")) ("Yes" if item.get("version") else "No (optional)"))
if "version" in item: if "version" in item:
click.echo("Version: %s" % item['version']) click.echo("Version: %s" % item['version'])
if "originalVersion" in item: if "originalVersion" in item:
@ -365,8 +365,8 @@ def platform_update(platforms, only_packages, only_check, json_output):
if not pkg_dir: if not pkg_dir:
continue continue
latest = pm.outdated(pkg_dir, requirements) latest = pm.outdated(pkg_dir, requirements)
if (not latest and not PlatformFactory.newPlatform(pkg_dir) if (not latest and not PlatformFactory.newPlatform(pkg_dir).
.are_outdated_packages()): are_outdated_packages()):
continue continue
data = _get_installed_platform_data( data = _get_installed_platform_data(
pkg_dir, with_boards=False, expose_packages=False) pkg_dir, with_boards=False, expose_packages=False)

View File

@ -108,7 +108,9 @@ def cli(ctx, environment, target, upload_port, project_dir, silent, verbose,
results.append(result) results.append(result)
if result[1] and "monitor" in ep.get_build_targets() and \ if result[1] and "monitor" in ep.get_build_targets() and \
"nobuild" not in ep.get_build_targets(): "nobuild" not in ep.get_build_targets():
ctx.invoke(cmd_device_monitor) ctx.invoke(
cmd_device_monitor,
environment=environment[0] if environment else None)
found_error = any(status is False for (_, status) in results) found_error = any(status is False for (_, status) in results)
@ -210,10 +212,10 @@ class EnvironmentProcessor(object):
if is_error or "piotest_processor" not in self.cmd_ctx.meta: if is_error or "piotest_processor" not in self.cmd_ctx.meta:
print_header( print_header(
"[%s] Took %.2f seconds" % "[%s] Took %.2f seconds" % (
((click.style("ERROR", fg="red", bold=True) (click.style("ERROR", fg="red", bold=True) if is_error else
if is_error else click.style( click.style("SUCCESS", fg="green", bold=True)),
"SUCCESS", fg="green", bold=True)), time() - start_time), time() - start_time),
is_error=is_error) is_error=is_error)
return not is_error return not is_error
@ -384,9 +386,8 @@ def print_summary(results, start_time):
print_header( print_header(
"[%s] Took %.2f seconds" % ( "[%s] Took %.2f seconds" % (
(click.style("SUCCESS", fg="green", bold=True) (click.style("SUCCESS", fg="green", bold=True) if successed else
if successed else click.style("ERROR", fg="red", bold=True)), click.style("ERROR", fg="red", bold=True)), time() - start_time),
time() - start_time),
is_error=not successed) is_error=not successed)

View File

@ -32,14 +32,14 @@ from platformio.managers.lib import LibraryManager
help="Do not update, only check for new version") help="Do not update, only check for new version")
@click.pass_context @click.pass_context
def cli(ctx, core_packages, only_check): def cli(ctx, core_packages, only_check):
# cleanup lib search results, cached board and platform lists
app.clean_cache()
update_core_packages(only_check) update_core_packages(only_check)
if core_packages: if core_packages:
return return
# cleanup lib search results, cached board and platform lists
app.clean_cache()
click.echo() click.echo()
click.echo("Platform Manager") click.echo("Platform Manager")
click.echo("================") click.echo("================")

View File

@ -20,7 +20,7 @@ import click
import requests import requests
from platformio import VERSION, __version__, exception, util from platformio import VERSION, __version__, exception, util
from platformio.commands.home import shutdown_servers from platformio.managers.core import shutdown_piohome_servers
@click.command( @click.command(
@ -36,7 +36,7 @@ def cli(dev):
click.secho("Please wait while upgrading PlatformIO ...", fg="yellow") click.secho("Please wait while upgrading PlatformIO ...", fg="yellow")
# kill all PIO Home servers, they block `pioplus` binary # kill all PIO Home servers, they block `pioplus` binary
shutdown_servers() shutdown_piohome_servers()
to_develop = dev or not all(c.isdigit() for c in __version__ if c != ".") to_develop = dev or not all(c.isdigit() for c in __version__ if c != ".")
cmds = (["pip", "install", "--upgrade", cmds = (["pip", "install", "--upgrade",
@ -63,7 +63,7 @@ def cli(dev):
fg="green") fg="green")
click.echo("Release notes: ", nl=False) click.echo("Release notes: ", nl=False)
click.secho( click.secho(
"http://docs.platformio.org/en/latest/history.html", fg="cyan") "https://docs.platformio.org/en/latest/history.html", fg="cyan")
except Exception as e: # pylint: disable=broad-except except Exception as e: # pylint: disable=broad-except
if not r: if not r:
raise exception.UpgradeError("\n".join([str(cmd), str(e)])) raise exception.UpgradeError("\n".join([str(cmd), str(e)]))
@ -102,8 +102,9 @@ def get_pip_package(to_develop):
pkg_name = os.path.join(cache_dir, "piocoredevelop.zip") pkg_name = os.path.join(cache_dir, "piocoredevelop.zip")
try: try:
with open(pkg_name, "w") as fp: with open(pkg_name, "w") as fp:
r = util.exec_command( r = util.exec_command(["curl", "-fsSL", dl_url],
["curl", "-fsSL", dl_url], stdout=fp, universal_newlines=True) stdout=fp,
universal_newlines=True)
assert r['returncode'] == 0 assert r['returncode'] == 0
# check ZIP structure # check ZIP structure
with ZipFile(pkg_name) as zp: with ZipFile(pkg_name) as zp:

View File

@ -178,7 +178,7 @@ class InternetIsOffline(PlatformioException):
MESSAGE = ( MESSAGE = (
"You are not connected to the Internet.\n" "You are not connected to the Internet.\n"
"If you build a project first time, we need Internet connection " "If you build a project first time, we need Internet connection "
"to install all dependencies and toolchain.") "to install all dependencies and toolchains.")
class LibNotFound(PlatformioException): class LibNotFound(PlatformioException):
@ -235,13 +235,32 @@ class CIBuildEnvsEmpty(PlatformioException):
"predefined environments using `--project-conf` option") "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): class UpgradeError(PlatformioException):
MESSAGE = """{0} MESSAGE = """{0}
* Upgrade using `pip install -U platformio` * Upgrade using `pip install -U platformio`
* Try different installation/upgrading steps: * Try different installation/upgrading steps:
http://docs.platformio.org/page/installation.html https://docs.platformio.org/page/installation.html
""" """
@ -265,7 +284,7 @@ class DebugSupportError(PlatformioException):
MESSAGE = ("Currently, PlatformIO does not support debugging for `{0}`.\n" MESSAGE = ("Currently, PlatformIO does not support debugging for `{0}`.\n"
"Please contact support@pioplus.com or visit " "Please contact support@pioplus.com or visit "
"< http://docs.platformio.org/page/plus/debugging.html >") "< https://docs.platformio.org/page/plus/debugging.html >")
class DebugInvalidOptions(PlatformioException): class DebugInvalidOptions(PlatformioException):

View File

@ -127,22 +127,8 @@ class ProjectGenerator(object):
@staticmethod @staticmethod
def _merge_contents(dst_path, contents): def _merge_contents(dst_path, contents):
file_name = basename(dst_path) if basename(dst_path) == ".gitignore" and isfile(dst_path):
return
# merge .gitignore
if file_name == ".gitignore" and isfile(dst_path):
modified = False
default = [l.strip() for l in contents.split("\n")]
with open(dst_path) as fp:
current = [l.strip() for l in fp.readlines()]
for d in default:
if d and d not in current:
modified = True
current.append(d)
if not modified:
return
contents = "\n".join(current) + "\n"
with open(dst_path, "w") as f: with open(dst_path, "w") as f:
f.write(contents) f.write(contents)

View File

@ -3,4 +3,4 @@
% end % end
% for define in defines: % for define in defines:
-D{{!define}} -D{{!define}}
% end % end

View File

@ -1,3 +1,4 @@
.pio
.pioenvs .pioenvs
.piolibdeps .piolibdeps
.clang_complete .clang_complete

View File

@ -1,3 +1,4 @@
.pio
.pioenvs .pioenvs
.piolibdeps .piolibdeps
CMakeListsPrivate.txt CMakeListsPrivate.txt

View File

@ -9,6 +9,9 @@
<file path="$PROJECT_DIR$/lib" /> <file path="$PROJECT_DIR$/lib" />
<file path="$PROJECT_DIR$/.piolibdeps" /> <file path="$PROJECT_DIR$/.piolibdeps" />
</libraryRoots> </libraryRoots>
<excludeRoots>
<file path="$PROJECT_DIR$/.pio" />
</excludeRoots>
<excludeRoots> <excludeRoots>
<file path="$PROJECT_DIR$/.pioenvs" /> <file path="$PROJECT_DIR$/.pioenvs" />
</excludeRoots> </excludeRoots>

View File

@ -1,6 +1,6 @@
% for include in includes: % for include in includes:
-I{{include}} -I"{{include}}"
% end % end
% for define in defines: % for define in defines:
-D{{!define}} -D{{!define}}
% end % end

View File

@ -1,3 +1,4 @@
.pio
.pioenvs .pioenvs
.piolibdeps .piolibdeps
.clang_complete .clang_complete

View File

@ -11,7 +11,7 @@
<itemPath>nbproject/private/launcher.properties</itemPath> <itemPath>nbproject/private/launcher.properties</itemPath>
</logicalFolder> </logicalFolder>
</logicalFolder> </logicalFolder>
<sourceFolderFilter>^(nbproject|.pioenvs)$</sourceFolderFilter> <sourceFolderFilter>^(nbproject|.pio|.pioenvs)$</sourceFolderFilter>
<sourceRootList> <sourceRootList>
<Elem>.</Elem> <Elem>.</Elem>
</sourceRootList> </sourceRootList>

View File

@ -1,6 +1,6 @@
% for include in includes: % for include in includes:
-I{{include}} -I"{{include}}"
% end % end
% for define in defines: % for define in defines:
-D{{!define}} -D{{!define}}
% end % end

View File

@ -3,6 +3,6 @@
"gccDefaultCFlags": "-fsyntax-only {{! cc_flags.replace(' -MMD ', ' ').replace('"', '\\"') }}", "gccDefaultCFlags": "-fsyntax-only {{! cc_flags.replace(' -MMD ', ' ').replace('"', '\\"') }}",
"gccDefaultCppFlags": "-fsyntax-only {{! cxx_flags.replace(' -MMD ', ' ').replace('"', '\\"') }}", "gccDefaultCppFlags": "-fsyntax-only {{! cxx_flags.replace(' -MMD ', ' ').replace('"', '\\"') }}",
"gccErrorLimit": 15, "gccErrorLimit": 15,
"gccIncludePaths": "{{ ','.join(includes).replace("\\", "/") }}", "gccIncludePaths": "{{! ','.join("'{}'".format(w.replace("\\", '/')) for w in includes)}}",
"gccSuppressWarnings": false "gccSuppressWarnings": false
} }

View File

@ -1,3 +1,4 @@
.pio
.pioenvs .pioenvs
.piolibdeps .piolibdeps
.clang_complete .clang_complete

View File

@ -1,3 +1,4 @@
.pio
.pioenvs .pioenvs
.piolibdeps .piolibdeps
.vscode/.browse.c_cpp.db* .vscode/.browse.c_cpp.db*

View File

@ -1,5 +1,5 @@
{ {
"!!! WARNING !!!": "PLEASE DO NOT MODIFY THIS FILE! USE http://docs.platformio.org/page/projectconf/section_env_build.html#build-flags", "!!! WARNING !!!": "PLEASE DO NOT MODIFY THIS FILE! USE https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags",
"configurations": [ "configurations": [
{ {
% import platform % import platform

View File

@ -2,8 +2,8 @@
// PIO Unified Debugger // PIO Unified Debugger
// //
// Documentation: http://docs.platformio.org/page/plus/debugging.html // Documentation: https://docs.platformio.org/page/plus/debugging.html
// Configuration: http://docs.platformio.org/page/projectconf/section_env_debug.html // Configuration: https://docs.platformio.org/page/projectconf/section_env_debug.html
% from os.path import dirname, join % from os.path import dirname, join
% %
@ -23,13 +23,16 @@
% if svd_path: % if svd_path:
"svdPath": "{{ _escape_path(svd_path) }}", "svdPath": "{{ _escape_path(svd_path) }}",
% end % end
"preLaunchTask": "PlatformIO: Pre-Debug", "preLaunchTask": {
"type": "PlatformIO",
"task": "Pre-Debug"
},
"internalConsoleOptions": "openOnSessionStart" "internalConsoleOptions": "openOnSessionStart"
}, },
{ {
"type": "platformio-debug", "type": "platformio-debug",
"request": "launch", "request": "launch",
"name": "PIO Debug (Skip Pre-Debug)", "name": "PIO Debug (skip Pre-Debug)",
"executable": "{{ _escape_path(prog_path) }}", "executable": "{{ _escape_path(prog_path) }}",
"toolchainBinDir": "{{ _escape_path(dirname(gdb_path)) }}", "toolchainBinDir": "{{ _escape_path(dirname(gdb_path)) }}",
% if svd_path: % if svd_path:

View File

@ -179,7 +179,7 @@ def after_upgrade(ctx):
click.secho( click.secho(
"Please remove multiple PIO Cores from a system:", fg="yellow") "Please remove multiple PIO Cores from a system:", fg="yellow")
click.secho( click.secho(
"http://docs.platformio.org/page/faq.html" "https://docs.platformio.org/page/faq.html"
"#multiple-pio-cores-in-a-system", "#multiple-pio-cores-in-a-system",
fg="cyan") fg="cyan")
click.secho("*" * terminal_width, fg="yellow") click.secho("*" * terminal_width, fg="yellow")
@ -274,7 +274,8 @@ def check_platformio_upgrade():
click.secho("pip install -U platformio", fg="cyan", nl=False) click.secho("pip install -U platformio", fg="cyan", nl=False)
click.secho("` command.", fg="yellow") click.secho("` command.", fg="yellow")
click.secho("Changes: ", fg="yellow", nl=False) click.secho("Changes: ", fg="yellow", nl=False)
click.secho("http://docs.platformio.org/en/latest/history.html", fg="cyan") click.secho(
"https://docs.platformio.org/en/latest/history.html", fg="cyan")
click.echo("*" * terminal_width) click.echo("*" * terminal_width)
click.echo("") click.echo("")
@ -318,8 +319,8 @@ def check_internal_updates(ctx, what):
if not app.get_setting("auto_update_" + what): if not app.get_setting("auto_update_" + what):
click.secho("Please update them via ", fg="yellow", nl=False) click.secho("Please update them via ", fg="yellow", nl=False)
click.secho( click.secho(
"`platformio %s update`" % ("lib --global" if what == "libraries" "`platformio %s update`" %
else "platform"), ("lib --global" if what == "libraries" else "platform"),
fg="cyan", fg="cyan",
nl=False) nl=False)
click.secho(" command.\n", fg="yellow") click.secho(" command.\n", fg="yellow")

View File

@ -16,6 +16,9 @@ import os
import subprocess import subprocess
import sys import sys
from os.path import dirname, join from os.path import dirname, join
from time import sleep
import requests
from platformio import __version__, exception, util from platformio import __version__, exception, util
from platformio.managers.package import PackageManager from platformio.managers.package import PackageManager
@ -23,7 +26,7 @@ from platformio.managers.package import PackageManager
CORE_PACKAGES = { CORE_PACKAGES = {
"contrib-piohome": "^1.0.2", "contrib-piohome": "^1.0.2",
"contrib-pysite": ">=0.3.2,<2", "contrib-pysite": ">=0.3.2,<2",
"tool-pioplus": "^1.4.5", "tool-pioplus": "^1.5.0",
"tool-unity": "~1.20403.0", "tool-unity": "~1.20403.0",
"tool-scons": "~2.20501.4" "tool-scons": "~2.20501.4"
} }
@ -36,11 +39,12 @@ PIOPLUS_AUTO_UPDATES_MAX = 100
class CorePackageManager(PackageManager): class CorePackageManager(PackageManager):
def __init__(self): def __init__(self):
PackageManager.__init__(self, join(util.get_home_dir(), "packages"), [ super(CorePackageManager, self).__init__(
"https://dl.bintray.com/platformio/dl-packages/manifest.json", join(util.get_home_dir(), "packages"), [
"http%s://dl.platformio.org/packages/manifest.json" % "https://dl.bintray.com/platformio/dl-packages/manifest.json",
("" if sys.version_info < (2, 7, 9) else "s") "http%s://dl.platformio.org/packages/manifest.json" %
]) ("" if sys.version_info < (2, 7, 9) else "s")
])
def install( # pylint: disable=keyword-arg-before-vararg def install( # pylint: disable=keyword-arg-before-vararg
self, self,
@ -92,10 +96,24 @@ def update_core_packages(only_check=False, silent=False):
if not pkg_dir: if not pkg_dir:
continue continue
if not silent or pm.outdated(pkg_dir, requirements): if not silent or pm.outdated(pkg_dir, requirements):
if name == "tool-pioplus" and not only_check:
shutdown_piohome_servers()
if "windows" in util.get_systype():
sleep(1)
pm.update(name, requirements, only_check=only_check) pm.update(name, requirements, only_check=only_check)
return True return True
def shutdown_piohome_servers():
port = 8010
while port < 9000:
try:
requests.get("http://127.0.0.1:%d?__shutdown__=1" % port)
port += 1
except: # pylint: disable=bare-except
return
def pioplus_call(args, **kwargs): def pioplus_call(args, **kwargs):
if "windows" in util.get_systype() and sys.version_info < (2, 7, 6): if "windows" in util.get_systype() and sys.version_info < (2, 7, 6):
raise exception.PlatformioException( raise exception.PlatformioException(

View File

@ -32,7 +32,7 @@ class LibraryManager(BasePkgManager):
def __init__(self, package_dir=None): def __init__(self, package_dir=None):
if not package_dir: if not package_dir:
package_dir = join(util.get_home_dir(), "lib") package_dir = join(util.get_home_dir(), "lib")
BasePkgManager.__init__(self, package_dir) super(LibraryManager, self).__init__(package_dir)
@property @property
def manifest_names(self): def manifest_names(self):
@ -237,9 +237,8 @@ class LibraryManager(BasePkgManager):
if not isinstance(values, list): if not isinstance(values, list):
values = [v.strip() for v in values.split(",") if v] values = [v.strip() for v in values.split(",") if v]
for value in values: for value in values:
query.append( query.append('%s:"%s"' %
'%s:"%s"' % (key[:-1] (key[:-1] if key.endswith("s") else key, value))
if key.endswith("s") else key, value))
lib_info = None lib_info = None
result = util.get_api_result( result = util.get_api_result(
@ -337,13 +336,12 @@ class LibraryManager(BasePkgManager):
force=False): force=False):
_name, _requirements, _url = self.parse_pkg_uri(name, requirements) _name, _requirements, _url = self.parse_pkg_uri(name, requirements)
if not _url: if not _url:
name = "id=%d" % self.search_lib_id( name = "id=%d" % self.search_lib_id({
{ "name": _name,
"name": _name, "requirements": _requirements
"requirements": _requirements },
}, silent=silent,
silent=silent, interactive=interactive)
interactive=interactive)
requirements = _requirements requirements = _requirements
pkg_dir = BasePkgManager.install( pkg_dir = BasePkgManager.install(
self, self,

View File

@ -259,6 +259,69 @@ class PkgInstallerMixin(object):
raise e raise e
return None return None
@staticmethod
def parse_pkg_uri( # pylint: disable=too-many-branches
text, requirements=None):
text = str(text)
name, url = None, None
# Parse requirements
req_conditions = [
"@" in text, not requirements, ":" not in text
or text.rfind("/") < text.rfind("@")
]
if all(req_conditions):
text, requirements = text.rsplit("@", 1)
# Handle PIO Library Registry ID
if text.isdigit():
text = "id=" + text
# Parse custom name
elif "=" in text and not text.startswith("id="):
name, text = text.split("=", 1)
# Parse URL
# if valid URL with scheme vcs+protocol://
if "+" in text and text.find("+") < text.find("://"):
url = text
elif "/" in text or "\\" in text:
git_conditions = [
# Handle GitHub URL (https://github.com/user/package)
text.startswith("https://github.com/") and not text.endswith(
(".zip", ".tar.gz")),
(text.split("#", 1)[0]
if "#" in text else text).endswith(".git")
]
hg_conditions = [
# Handle Developer Mbed URL
# (https://developer.mbed.org/users/user/code/package/)
# (https://os.mbed.com/users/user/code/package/)
text.startswith("https://developer.mbed.org"),
text.startswith("https://os.mbed.com")
]
if any(git_conditions):
url = "git+" + text
elif any(hg_conditions):
url = "hg+" + text
elif "://" not in text and (isfile(text) or isdir(text)):
url = "file://" + text
elif "://" in text:
url = text
# Handle short version of GitHub URL
elif text.count("/") == 1:
url = "git+https://github.com/" + text
# Parse name from URL
if url and not name:
_url = url.split("#", 1)[0] if "#" in url else url
if _url.endswith(("\\", "/")):
_url = _url[:-1]
name = basename(_url)
if "." in name and not name.startswith("."):
name = name.rsplit(".", 1)[0]
return (name or text, requirements, url)
@staticmethod @staticmethod
def get_install_dirname(manifest): def get_install_dirname(manifest):
name = re.sub(r"[^\da-z\_\-\. ]", "_", manifest['name'], flags=re.I) name = re.sub(r"[^\da-z\_\-\. ]", "_", manifest['name'], flags=re.I)
@ -316,11 +379,13 @@ class PkgInstallerMixin(object):
manifest[key.strip()] = value.strip() manifest[key.strip()] = value.strip()
if src_manifest: if src_manifest:
if "name" not in manifest:
manifest['name'] = src_manifest['name']
if "version" in src_manifest: if "version" in src_manifest:
manifest['version'] = src_manifest['version'] manifest['version'] = src_manifest['version']
manifest['__src_url'] = src_manifest['url'] manifest['__src_url'] = src_manifest['url']
# handle a custom package name
autogen_name = self.parse_pkg_uri(manifest['__src_url'])[0]
if "name" not in manifest or autogen_name != src_manifest['name']:
manifest['name'] = src_manifest['name']
if "name" not in manifest: if "name" not in manifest:
manifest['name'] = basename(pkg_dir) manifest['name'] = basename(pkg_dir)
@ -414,6 +479,7 @@ class PkgInstallerMixin(object):
click.secho("Looking for another mirror...", fg="yellow") click.secho("Looking for another mirror...", fg="yellow")
if versions is None: if versions is None:
util.internet_on(raise_exception=True)
raise exception.UnknownPackage(name) raise exception.UnknownPackage(name)
elif not pkgdata: elif not pkgdata:
raise exception.UndefinedPackageVersion(requirements or "latest", raise exception.UndefinedPackageVersion(requirements or "latest",
@ -562,73 +628,10 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
def print_message(self, message, nl=True): def print_message(self, message, nl=True):
click.echo("%s: %s" % (self.__class__.__name__, message), nl=nl) click.echo("%s: %s" % (self.__class__.__name__, message), nl=nl)
@staticmethod
def parse_pkg_uri( # pylint: disable=too-many-branches
text, requirements=None):
text = str(text)
name, url = None, None
# Parse requirements
req_conditions = [
"@" in text, not requirements, ":" not in text
or text.rfind("/") < text.rfind("@")
]
if all(req_conditions):
text, requirements = text.rsplit("@", 1)
# Handle PIO Library Registry ID
if text.isdigit():
text = "id=" + text
# Parse custom name
elif "=" in text and not text.startswith("id="):
name, text = text.split("=", 1)
# Parse URL
# if valid URL with scheme vcs+protocol://
if "+" in text and text.find("+") < text.find("://"):
url = text
elif "/" in text or "\\" in text:
git_conditions = [
# Handle GitHub URL (https://github.com/user/package)
text.startswith("https://github.com/") and not text.endswith(
(".zip", ".tar.gz")),
(text.split("#", 1)[0]
if "#" in text else text).endswith(".git")
]
hg_conditions = [
# Handle Developer Mbed URL
# (https://developer.mbed.org/users/user/code/package/)
# (https://os.mbed.com/users/user/code/package/)
text.startswith("https://developer.mbed.org"),
text.startswith("https://os.mbed.com")
]
if any(git_conditions):
url = "git+" + text
elif any(hg_conditions):
url = "hg+" + text
elif "://" not in text and (isfile(text) or isdir(text)):
url = "file://" + text
elif "://" in text:
url = text
# Handle short version of GitHub URL
elif text.count("/") == 1:
url = "git+https://github.com/" + text
# Parse name from URL
if url and not name:
_url = url.split("#", 1)[0] if "#" in url else url
if _url.endswith(("\\", "/")):
_url = _url[:-1]
name = basename(_url)
if "." in name and not name.startswith("."):
name = name.rsplit(".", 1)[0]
return (name or text, requirements, url)
def outdated(self, pkg_dir, requirements=None): def outdated(self, pkg_dir, requirements=None):
""" """
Has 3 different results: Has 3 different results:
`None` - unknown package, VCS is fixed to commit `None` - unknown package, VCS is detached to commit
`False` - package is up-to-date `False` - package is up-to-date
`String` - a found latest version `String` - a found latest version
""" """
@ -636,7 +639,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
return None return None
latest = None latest = None
manifest = self.load_manifest(pkg_dir) manifest = self.load_manifest(pkg_dir)
# skip fixed package to a specific version # skip detached package to a specific version
if "@" in pkg_dir and "__src_url" not in manifest and not requirements: if "@" in pkg_dir and "__src_url" not in manifest and not requirements:
return None return None
@ -814,7 +817,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
elif latest is False: elif latest is False:
click.echo("[%s]" % (click.style("Up-to-date", fg="green"))) click.echo("[%s]" % (click.style("Up-to-date", fg="green")))
else: else:
click.echo("[%s]" % (click.style("Fixed", fg="yellow"))) click.echo("[%s]" % (click.style("Detached", fg="yellow")))
if only_check or not latest: if only_check or not latest:
return True return True

View File

@ -235,8 +235,8 @@ class PlatformFactory(object):
name = pm.load_manifest(platform_dir)['name'] name = pm.load_manifest(platform_dir)['name']
if not platform_dir: if not platform_dir:
raise exception.UnknownPlatform(name if not requirements else raise exception.UnknownPlatform(
"%s@%s" % (name, requirements)) name if not requirements else "%s@%s" % (name, requirements))
platform_cls = None platform_cls = None
if isfile(join(platform_dir, "platform.py")): if isfile(join(platform_dir, "platform.py")):
@ -604,7 +604,7 @@ class PlatformBase( # pylint: disable=too-many-public-methods
# enable upload tools for upload targets # enable upload tools for upload targets
if any(["upload" in t for t in targets] + ["program" in targets]): if any(["upload" in t for t in targets] + ["program" in targets]):
for name, opts in self.packages.iteritems(): for name, opts in self.packages.items():
if opts.get("type") == "uploader": if opts.get("type") == "uploader":
self.packages[name]['optional'] = False self.packages[name]['optional'] = False
# skip all packages in "nobuild" mode # skip all packages in "nobuild" mode

View File

@ -6,4 +6,4 @@
; Advanced options: extra scripting ; Advanced options: extra scripting
; ;
; Please visit documentation for the other options and examples ; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html

View File

@ -61,7 +61,7 @@ class MeasurementProtocol(TelemetryBase):
} }
def __init__(self): def __init__(self):
TelemetryBase.__init__(self) super(MeasurementProtocol, self).__init__()
self['v'] = 1 self['v'] = 1
self['tid'] = self.TID self['tid'] = self.TID
self['cid'] = app.get_cid() self['cid'] = app.get_cid()
@ -112,8 +112,8 @@ class MeasurementProtocol(TelemetryBase):
self['cd2'] = "Python/%s %s" % (platform.python_version(), self['cd2'] = "Python/%s %s" % (platform.python_version(),
platform.platform()) platform.platform())
# self['cd3'] = " ".join(_filter_args(sys.argv[1:])) # self['cd3'] = " ".join(_filter_args(sys.argv[1:]))
self['cd4'] = 1 if (not util.is_ci() self['cd4'] = 1 if (not util.is_ci() and
and (caller_id or not util.is_container())) else 0 (caller_id or not util.is_container())) else 0
if caller_id: if caller_id:
self['cd5'] = caller_id.lower() self['cd5'] = caller_id.lower()
@ -291,7 +291,7 @@ def measure_ci():
} }
} }
for key, value in envmap.iteritems(): for key, value in envmap.items():
if getenv(key, "").lower() != "true": if getenv(key, "").lower() != "true":
continue continue
event.update({"action": key, "label": value['label']}) event.update({"action": key, "label": value['label']})

View File

@ -48,7 +48,7 @@ class ArchiveBase(object):
class TARArchive(ArchiveBase): class TARArchive(ArchiveBase):
def __init__(self, archpath): def __init__(self, archpath):
ArchiveBase.__init__(self, tarfile_open(archpath)) super(TARArchive, self).__init__(tarfile_open(archpath))
def get_items(self): def get_items(self):
return self._afo.getmembers() return self._afo.getmembers()
@ -60,7 +60,7 @@ class TARArchive(ArchiveBase):
class ZIPArchive(ArchiveBase): class ZIPArchive(ArchiveBase):
def __init__(self, archpath): def __init__(self, archpath):
ArchiveBase.__init__(self, ZipFile(archpath)) super(ZIPArchive, self).__init__(ZipFile(archpath))
@staticmethod @staticmethod
def preserve_permissions(item, dest_dir): def preserve_permissions(item, dest_dir):

View File

@ -23,6 +23,7 @@ import sys
import time import time
from functools import wraps from functools import wraps
from glob import glob from glob import glob
from hashlib import sha1
from os.path import (abspath, basename, dirname, expanduser, isdir, isfile, from os.path import (abspath, basename, dirname, expanduser, isdir, isfile,
join, normpath, splitdrive) join, normpath, splitdrive)
from shutil import rmtree from shutil import rmtree
@ -77,7 +78,7 @@ class ProjectConfig(ConfigParser.ConfigParser):
class AsyncPipe(Thread): class AsyncPipe(Thread):
def __init__(self, outcallback=None): def __init__(self, outcallback=None):
Thread.__init__(self) super(AsyncPipe, self).__init__()
self.outcallback = outcallback self.outcallback = outcallback
self._fd_read, self._fd_write = os.pipe() self._fd_read, self._fd_write = os.pipe()
@ -99,7 +100,7 @@ class AsyncPipe(Thread):
if self.outcallback: if self.outcallback:
self.outcallback(line) self.outcallback(line)
else: else:
print line print(line)
self._pipe_reader.close() self._pipe_reader.close()
def close(self): def close(self):
@ -137,8 +138,12 @@ class memoized(object):
self.cache[key] = (time.time(), func(*args, **kwargs)) self.cache[key] = (time.time(), func(*args, **kwargs))
return self.cache[key][1] return self.cache[key][1]
wrapper.reset = self._reset
return wrapper return wrapper
def _reset(self):
self.cache = {}
class throttle(object): class throttle(object):
@ -309,6 +314,9 @@ def get_projectboards_dir():
def get_projectbuild_dir(force=False): def get_projectbuild_dir(force=False):
path = get_project_optional_dir("build_dir", path = get_project_optional_dir("build_dir",
join(get_project_dir(), ".pioenvs")) join(get_project_dir(), ".pioenvs"))
if "$PROJECT_HASH" in path:
path = path.replace("$PROJECT_HASH",
sha1(get_project_dir()).hexdigest()[:10])
try: try:
if not isdir(path): if not isdir(path):
os.makedirs(path) os.makedirs(path)
@ -317,7 +325,7 @@ def get_projectbuild_dir(force=False):
with open(dontmod_path, "w") as fp: with open(dontmod_path, "w") as fp:
fp.write(""" fp.write("""
[InternetShortcut] [InternetShortcut]
URL=http://docs.platformio.org/page/projectconf/section_platformio.html#build-dir URL=https://docs.platformio.org/page/projectconf/section_platformio.html#build-dir
""") """)
except Exception as e: # pylint: disable=broad-except except Exception as e: # pylint: disable=broad-except
if not force: if not force:
@ -349,12 +357,19 @@ def load_project_config(path=None):
def parse_conf_multi_values(items): def parse_conf_multi_values(items):
result = []
if not items: if not items:
return [] return result
return [ inline_comment_re = re.compile(r"\s+;.*$")
item.strip() for item in items.split("\n" if "\n" in items else ", ") for item in items.split("\n" if "\n" in items else ", "):
if item.strip() 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 change_filemtime(path, mtime): def change_filemtime(path, mtime):
@ -398,7 +413,7 @@ def exec_command(*args, **kwargs):
if isinstance(kwargs[s], AsyncPipe): if isinstance(kwargs[s], AsyncPipe):
result[s[3:]] = "\n".join(kwargs[s].get_buffer()) result[s[3:]] = "\n".join(kwargs[s].get_buffer())
for k, v in result.iteritems(): for k, v in result.items():
if v and isinstance(v, basestring): if v and isinstance(v, basestring):
result[k].strip() result[k].strip()
@ -779,6 +794,43 @@ def merge_dicts(d1, d2, path=None):
return d1 return d1
def ensure_udev_rules():
def _rules_to_set(rules_path):
result = set([])
with open(rules_path, "rb") as fp:
for line in fp.readlines():
line = line.strip()
if not line or line.startswith("#"):
continue
result.add(line)
return result
if "linux" not in get_systype():
return None
installed_rules = [
"/etc/udev/rules.d/99-platformio-udev.rules",
"/lib/udev/rules.d/99-platformio-udev.rules"
]
if not any(isfile(p) for p in installed_rules):
raise exception.MissedUdevRules
origin_path = abspath(
join(get_source_dir(), "..", "scripts", "99-platformio-udev.rules"))
if not isfile(origin_path):
return None
origin_rules = _rules_to_set(origin_path)
for rules_path in installed_rules:
if not isfile(rules_path):
continue
current_rules = _rules_to_set(rules_path)
if not origin_rules <= current_rules:
raise exception.OutdatedUdevRules(rules_path)
return True
def rmtree_(path): def rmtree_(path):
def _onerror(_, name, __): def _onerror(_, name, __):
@ -787,8 +839,9 @@ def rmtree_(path):
os.remove(name) os.remove(name)
except Exception as e: # pylint: disable=broad-except except Exception as e: # pylint: disable=broad-except
click.secho( click.secho(
"Please manually remove file `%s`" % name, fg="red", err=True) "%s \nPlease manually remove the file `%s`" % (str(e), name),
raise e fg="red",
err=True)
return rmtree(path, onerror=_onerror) return rmtree(path, onerror=_onerror)
@ -805,8 +858,7 @@ except ImportError:
magic_check_bytes = re.compile(b'([*?[])') magic_check_bytes = re.compile(b'([*?[])')
def glob_escape(pathname): def glob_escape(pathname):
"""Escape all special characters. """Escape all special characters."""
"""
# Escaping is done by wrapping any of "*?[" between square brackets. # Escaping is done by wrapping any of "*?[" between square brackets.
# Metacharacters do not work in the drive part and shouldn't be # Metacharacters do not work in the drive part and shouldn't be
# escaped. # escaped.

View File

@ -16,7 +16,7 @@
# #
# INSTALLATION # INSTALLATION
# #
# Please visit > http://docs.platformio.org/en/latest/faq.html#platformio-udev-rules # Please visit > https://docs.platformio.org/en/latest/faq.html#platformio-udev-rules
# #
##################################################################################### #####################################################################################

View File

@ -23,18 +23,28 @@ path.append("..")
from platformio import util from platformio import util
from platformio.managers.platform import PlatformFactory, PlatformManager from platformio.managers.platform import PlatformFactory, PlatformManager
RST_COPYRIGHT = """.. 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.
"""
API_PACKAGES = util.get_api_result("/packages") API_PACKAGES = util.get_api_result("/packages")
API_FRAMEWORKS = util.get_api_result("/frameworks") API_FRAMEWORKS = util.get_api_result("/frameworks")
BOARDS = PlatformManager().get_installed_boards() BOARDS = PlatformManager().get_installed_boards()
PLATFORM_MANIFESTS = PlatformManager().get_installed() PLATFORM_MANIFESTS = PlatformManager().get_installed()
DOCS_ROOT_DIR = realpath(join(dirname(realpath(__file__)), "..", "docs"))
def is_compat_platform_and_framework(platform, framework): def is_compat_platform_and_framework(platform, framework):
p = PlatformFactory.newPlatform(platform) p = PlatformFactory.newPlatform(platform)
for pkg in p.packages.keys(): return framework in (p.frameworks or {}).keys()
if pkg.startswith("framework-%s" % framework):
return True
return False
def campaign_url(url, source="platformio", medium="docs"): def campaign_url(url, source="platformio", medium="docs"):
@ -48,20 +58,17 @@ def campaign_url(url, source="platformio", medium="docs"):
query, data.fragment)) query, data.fragment))
def generate_boards(boards, extend_debug=False, skip_columns=None): def generate_boards_table(boards, skip_columns=None):
columns = [ columns = [
("ID", "``{id}``"), ("Name", ":ref:`board_{platform}_{id}`"),
("Name", "`{name} <{url}>`_"), ("Platform", ":ref:`platform_{platform}`"),
("Platform", ":ref:`{platform_title} <platform_{platform}>`"),
("Debug", "{debug}"), ("Debug", "{debug}"),
("MCU", "{mcu}"), ("MCU", "{mcu}"),
("Frequency", "{f_cpu:d}MHz"), ("Frequency", "{f_cpu:d}MHz"),
("Flash", "{rom}"), ("Flash", "{rom}"),
("RAM", "{ram}"), ("RAM", "{ram}"),
] ]
platforms = {m['name']: m['title'] for m in PLATFORM_MANIFESTS}
lines = [] lines = []
lines.append(""" lines.append("""
.. list-table:: .. list-table::
:header-rows: 1 :header-rows: 1
@ -71,36 +78,23 @@ def generate_boards(boards, extend_debug=False, skip_columns=None):
for (name, template) in columns: for (name, template) in columns:
if skip_columns and name in skip_columns: if skip_columns and name in skip_columns:
continue continue
prefix = " * - " if name == "ID" else " - " prefix = " * - " if name == "Name" else " - "
lines.append(prefix + name) lines.append(prefix + name)
for data in sorted(boards, key=lambda item: item['id']): for data in sorted(boards, key=lambda item: item['name']):
debug = [":ref:`Yes <piodebug>`" if data['debug'] else "No"] has_onboard_debug = (data['debug'] and any(
if extend_debug and data['debug']: t.get("onboard") for (_, t) in data['debug']['tools'].items()))
debug_onboard = [] debug = "No"
debug_external = [] if has_onboard_debug:
for name, options in data['debug']['tools'].items(): debug = "On-board"
attrs = [] elif data['debug']:
if options.get("default"): debug = "External"
attrs.append("default")
if options.get("onboard"):
attrs.append("on-board")
tool = ":ref:`debugging_tool_%s`" % name
if attrs:
tool = "%s (%s)" % (tool, ", ".join(attrs))
if options.get("onboard"):
debug_onboard.append(tool)
else:
debug_external.append(tool)
debug = sorted(debug_onboard) + sorted(debug_external)
variables = dict( variables = dict(
id=data['id'], id=data['id'],
name=data['name'], name=data['name'],
platform=data['platform'], platform=data['platform'],
platform_title=platforms[data['platform']], debug=debug,
debug=", ".join(debug),
url=campaign_url(data['url']),
mcu=data['mcu'].upper(), mcu=data['mcu'].upper(),
f_cpu=int(data['fcpu']) / 1000000, f_cpu=int(data['fcpu']) / 1000000,
ram=util.format_filesize(data['ram']), ram=util.format_filesize(data['ram']),
@ -109,7 +103,7 @@ def generate_boards(boards, extend_debug=False, skip_columns=None):
for (name, template) in columns: for (name, template) in columns:
if skip_columns and name in skip_columns: if skip_columns and name in skip_columns:
continue continue
prefix = " * - " if name == "ID" else " - " prefix = " * - " if name == "Name" else " - "
lines.append(prefix + template.format(**variables)) lines.append(prefix + template.format(**variables))
if lines: if lines:
@ -118,7 +112,56 @@ def generate_boards(boards, extend_debug=False, skip_columns=None):
return lines return lines
def generate_frameworks_contents(frameworks):
if not frameworks:
return []
lines = []
lines.append("""
Frameworks
----------
.. list-table::
:header-rows: 1
* - Name
- Description""")
known = set()
for framework in API_FRAMEWORKS:
known.add(framework['name'])
if framework['name'] not in frameworks:
continue
lines.append("""
* - :ref:`framework_{name}`
- {description}""".format(**framework))
assert known >= set(frameworks), "Unknown frameworks %s " % (
set(frameworks) - known)
return lines
def generate_platforms_contents(platforms):
if not platforms:
return []
lines = []
lines.append("""
Platforms
---------
.. list-table::
:header-rows: 1
* - Name
- Description""")
for name in sorted(platforms):
p = PlatformFactory.newPlatform(name)
lines.append("""
* - :ref:`platform_{name}`
- {description}""".format(name=p.name, description=p.description))
return lines
def generate_debug_contents(boards, skip_board_columns=None, extra_rst=None): def generate_debug_contents(boards, skip_board_columns=None, extra_rst=None):
if not skip_board_columns:
skip_board_columns = []
skip_board_columns.append("Debug")
lines = [] lines = []
onboard_debug = [ onboard_debug = [
b for b in boards if b['debug'] and any( b for b in boards if b['debug'] and any(
@ -143,13 +186,13 @@ Debugging
lines.append(".. include:: %s" % extra_rst) lines.append(".. include:: %s" % extra_rst)
lines.append(""" lines.append("""
Debug Tools Tools & Debug Probes
~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
Supported debugging tools are listed in "Debug" column. For more detailed Supported debugging tools are listed in "Debug" column. For more detailed
information, please scroll table by horizontal. information, please scroll table by horizontal.
You can switch between debugging :ref:`debugging_tools` using You can switch between debugging :ref:`debugging_tools` using
:ref:`projectconf_debug_tool` options. :ref:`projectconf_debug_tool` option in :ref:`projectconf`.
.. warning:: .. warning::
You will need to install debug tool drivers depending on your system. You will need to install debug tool drivers depending on your system.
@ -161,27 +204,24 @@ You can switch between debugging :ref:`debugging_tools` using
On-Board Debug Tools On-Board Debug Tools
^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
Boards listed below have on-board debug tool and **ARE READY** for debugging! Boards listed below have on-board debug probe and **ARE READY** for debugging!
You do not need to use/buy external debug tool. You do not need to use/buy external debug probe.
""") """)
lines.extend( lines.extend(
generate_boards( generate_boards_table(
onboard_debug, onboard_debug, skip_columns=skip_board_columns))
extend_debug=True,
skip_columns=skip_board_columns))
if external_debug: if external_debug:
lines.append(""" lines.append("""
External Debug Tools External Debug Tools
^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
Boards listed below are compatible with :ref:`piodebug` but **DEPEND ON** Boards listed below are compatible with :ref:`piodebug` but **DEPEND ON**
external debug tool. See "Debug" column for compatible debug tools. external debug probe. They **ARE NOT READY** for debugging.
Please click on board name for the further details.
""") """)
lines.extend( lines.extend(
generate_boards( generate_boards_table(
external_debug, external_debug, skip_columns=skip_board_columns))
extend_debug=True,
skip_columns=skip_board_columns))
return lines return lines
@ -243,23 +283,12 @@ def generate_platform(name, rst_dir):
print "Processing platform: %s" % name print "Processing platform: %s" % name
compatible_boards = [ compatible_boards = [
board for board in BOARDS if name in board['platform'] board for board in BOARDS if name == board['platform']
] ]
lines = [] lines = []
lines.append( lines.append(RST_COPYRIGHT)
""".. 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.
""")
p = PlatformFactory.newPlatform(name) p = PlatformFactory.newPlatform(name)
assert p.repository_url.endswith(".git") assert p.repository_url.endswith(".git")
github_url = p.repository_url[:-4] github_url = p.repository_url[:-4]
@ -269,7 +298,9 @@ def generate_platform(name, rst_dir):
lines.append(p.title) lines.append(p.title)
lines.append("=" * len(p.title)) lines.append("=" * len(p.title))
lines.append(":ref:`projectconf_env_platform` = ``%s``" % p.name) lines.append("")
lines.append(":Configuration:")
lines.append(" :ref:`projectconf_env_platform` = ``%s``" % p.name)
lines.append("") lines.append("")
lines.append(p.description) lines.append(p.description)
lines.append(""" lines.append("""
@ -312,8 +343,8 @@ Examples are listed from `%s development platform repository <%s>`_:
generate_debug_contents( generate_debug_contents(
compatible_boards, compatible_boards,
skip_board_columns=["Platform"], skip_board_columns=["Platform"],
extra_rst="%s_debug.rst" % name extra_rst="%s_debug.rst" % name if isfile(
if isfile(join(rst_dir, "%s_debug.rst" % name)) else None)) join(rst_dir, "%s_debug.rst" % name)) else None))
# #
# Development version of dev/platform # Development version of dev/platform
@ -362,24 +393,11 @@ Upstream
# #
# Frameworks # Frameworks
# #
_frameworks_lines = [] compatible_frameworks = []
for framework in API_FRAMEWORKS: for framework in API_FRAMEWORKS:
if not is_compat_platform_and_framework(name, framework['name']): if is_compat_platform_and_framework(name, framework['name']):
continue compatible_frameworks.append(framework['name'])
_frameworks_lines.append(""" lines.extend(generate_frameworks_contents(compatible_frameworks))
* - :ref:`framework_{name}`
- {description}""".format(**framework))
if _frameworks_lines:
lines.append("""
Frameworks
----------
.. list-table::
:header-rows: 1
* - Name
- Description""")
lines.extend(_frameworks_lines)
# #
# Boards # Boards
@ -405,7 +423,8 @@ Boards
for vendor, boards in sorted(vendors.items()): for vendor, boards in sorted(vendors.items()):
lines.append(str(vendor)) lines.append(str(vendor))
lines.append("~" * len(vendor)) lines.append("~" * len(vendor))
lines.extend(generate_boards(boards, skip_columns=["Platform"])) lines.extend(
generate_boards_table(boards, skip_columns=["Platform"]))
return "\n".join(lines) return "\n".join(lines)
@ -413,8 +432,7 @@ Boards
def update_platform_docs(): def update_platform_docs():
for manifest in PLATFORM_MANIFESTS: for manifest in PLATFORM_MANIFESTS:
name = manifest['name'] name = manifest['name']
platforms_dir = join( platforms_dir = join(DOCS_ROOT_DIR, "platforms")
dirname(realpath(__file__)), "..", "docs", "platforms")
rst_path = join(platforms_dir, "%s.rst" % name) rst_path = join(platforms_dir, "%s.rst" % name)
with open(rst_path, "w") as f: with open(rst_path, "w") as f:
f.write(generate_platform(name, platforms_dir)) f.write(generate_platform(name, platforms_dir))
@ -433,25 +451,15 @@ def generate_framework(type_, data, rst_dir=None):
lines = [] lines = []
lines.append( lines.append(RST_COPYRIGHT)
""".. 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.
""")
lines.append(".. _framework_%s:" % type_) lines.append(".. _framework_%s:" % type_)
lines.append("") lines.append("")
lines.append(data['title']) lines.append(data['title'])
lines.append("=" * len(data['title'])) lines.append("=" * len(data['title']))
lines.append(":ref:`projectconf_env_framework` = ``%s``" % type_) lines.append("")
lines.append(":Configuration:")
lines.append(" :ref:`projectconf_env_framework` = ``%s``" % type_)
lines.append("") lines.append("")
lines.append(data['description']) lines.append(data['description'])
lines.append(""" lines.append("""
@ -474,8 +482,8 @@ For more detailed information please visit `vendor site <%s>`_.
lines.extend( lines.extend(
generate_debug_contents( generate_debug_contents(
compatible_boards, compatible_boards,
extra_rst="%s_debug.rst" % type_ extra_rst="%s_debug.rst" % type_ if isfile(
if isfile(join(rst_dir, "%s_debug.rst" % type_)) else None)) join(rst_dir, "%s_debug.rst" % type_)) else None))
if compatible_platforms: if compatible_platforms:
# examples # examples
@ -492,21 +500,9 @@ Examples
"%s/tree/master/examples" % p.repository_url[:-4]))) "%s/tree/master/examples" % p.repository_url[:-4])))
# Platforms # Platforms
lines.append(""" lines.extend(
Platforms generate_platforms_contents(
--------- [manifest['name'] for manifest in compatible_platforms]))
.. list-table::
:header-rows: 1
* - Name
- Description""")
for manifest in compatible_platforms:
p = PlatformFactory.newPlatform(manifest['name'])
lines.append("""
* - :ref:`platform_{type_}`
- {description}""".format(
type_=manifest['name'], description=p.description))
# #
# Boards # Boards
@ -529,41 +525,28 @@ Boards
for vendor, boards in sorted(vendors.items()): for vendor, boards in sorted(vendors.items()):
lines.append(str(vendor)) lines.append(str(vendor))
lines.append("~" * len(vendor)) lines.append("~" * len(vendor))
lines.extend(generate_boards(boards)) lines.extend(generate_boards_table(boards))
return "\n".join(lines) return "\n".join(lines)
def update_framework_docs(): def update_framework_docs():
for framework in API_FRAMEWORKS: for framework in API_FRAMEWORKS:
name = framework['name'] name = framework['name']
frameworks_dir = join( frameworks_dir = join(DOCS_ROOT_DIR, "frameworks")
dirname(realpath(__file__)), "..", "docs", "frameworks")
rst_path = join(frameworks_dir, "%s.rst" % name) rst_path = join(frameworks_dir, "%s.rst" % name)
with open(rst_path, "w") as f: with open(rst_path, "w") as f:
f.write(generate_framework(name, framework, frameworks_dir)) f.write(generate_framework(name, framework, frameworks_dir))
def update_embedded_boards(): def update_boards():
lines = [] lines = []
lines.append( lines.append(RST_COPYRIGHT)
""".. Copyright (c) 2014-present PlatformIO <contact@platformio.org> lines.append(".. _boards:")
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.
""")
lines.append(".. _embedded_boards:")
lines.append("") lines.append("")
lines.append("Embedded Boards") lines.append("Boards")
lines.append("===============") lines.append("======")
lines.append(""" lines.append("""
Rapid Embedded Development, Continuous and IDE integration in a few Rapid Embedded Development, Continuous and IDE integration in a few
@ -576,33 +559,212 @@ popular embedded boards and IDE.
* For more detailed ``board`` information please scroll tables below by horizontal. * For more detailed ``board`` information please scroll tables below by horizontal.
""") """)
lines.append(""" platforms = {}
.. contents:: Vendors
:local:
""")
vendors = {}
for data in BOARDS: for data in BOARDS:
vendor = data['vendor'] platform = data['platform']
if vendor in vendors: if platform in platforms:
vendors[vendor].append(data) platforms[platform].append(data)
else: else:
vendors[vendor] = [data] platforms[platform] = [data]
for vendor, boards in sorted(vendors.iteritems()): for platform, boards in sorted(platforms.iteritems()):
lines.append(str(vendor)) p = PlatformFactory.newPlatform(platform)
lines.append("~" * len(vendor)) lines.append(p.title)
lines.extend(generate_boards(boards)) lines.append("-" * len(p.title))
lines.append("""
.. toctree::
:maxdepth: 1
""")
for board in sorted(boards, key=lambda item: item['name']):
lines.append(" %s/%s" % (platform, board["id"]))
lines.append("")
emboards_rst = join( emboards_rst = join(DOCS_ROOT_DIR, "boards", "index.rst")
dirname(realpath(__file__)), "..", "docs", "platforms",
"embedded_boards.rst")
with open(emboards_rst, "w") as f: with open(emboards_rst, "w") as f:
f.write("\n".join(lines)) f.write("\n".join(lines))
# individual board page
for data in BOARDS:
# if data['id'] != "m5stack-core-esp32":
# continue
rst_path = join(DOCS_ROOT_DIR, "boards", data["platform"],
"%s.rst" % data["id"])
if not isdir(dirname(rst_path)):
os.makedirs(dirname(rst_path))
update_embedded_board(rst_path, data)
def update_embedded_board(rst_path, board):
platform = PlatformFactory.newPlatform(board['platform'])
board_config = platform.board_config(board['id'])
board_manifest_url = platform.repository_url
assert board_manifest_url
if board_manifest_url.endswith(".git"):
board_manifest_url = board_manifest_url[:-4]
board_manifest_url += "/blob/master/boards/%s.json" % board['id']
variables = dict(
id=board['id'],
name=board['name'],
platform=board['platform'],
platform_description=platform.description,
url=campaign_url(board['url']),
mcu=board_config.get("build", {}).get("mcu", ""),
mcu_upper=board['mcu'].upper(),
f_cpu=board['fcpu'],
f_cpu_mhz=int(board['fcpu']) / 1000000,
ram=util.format_filesize(board['ram']),
rom=util.format_filesize(board['rom']),
vendor=board['vendor'],
board_manifest_url=board_manifest_url,
upload_protocol=board_config.get("upload.protocol", ""))
lines = [RST_COPYRIGHT]
lines.append(".. _board_{platform}_{id}:".format(**variables))
lines.append("")
lines.append(board['name'])
lines.append("=" * len(board['name']))
lines.append("""
.. contents::
System
------
Platform :ref:`platform_{platform}`: {platform_description}
.. list-table::
* - **Microcontroller**
- {mcu_upper}
* - **Frequency**
- {f_cpu_mhz}MHz
* - **Flash**
- {rom}
* - **RAM**
- {ram}
* - **Vendor**
- `{vendor} <{url}>`__
""".format(**variables))
#
# Configuration
#
lines.append("""
Configuration
-------------
Please use ``{id}`` ID for :ref:`projectconf_env_board` option in :ref:`projectconf`:
.. code-block:: ini
[env:{id}]
platform = {platform}
board = {id}
You can override default {name} settings per build environment using
``board_***`` option, where ``***`` is a JSON object path from
board manifest `{id}.json <{board_manifest_url}>`_. For example,
``board_build.mcu``, ``board_build.f_cpu``, etc.
.. code-block:: ini
[env:{id}]
platform = {platform}
board = {id}
; change microcontroller
board_build.mcu = {mcu}
; change MCU frequency
board_build.f_cpu = {f_cpu}L
""".format(**variables))
#
# Uploading
#
upload_protocols = board_config.get("upload.protocols", [])
if len(upload_protocols) > 1:
lines.append("""
Uploading
---------
%s supports the next uploading protocols:
""" % board['name'])
for protocol in upload_protocols:
lines.append("* ``%s``" % protocol)
lines.append("""
Default protocol is ``%s``""" % variables['upload_protocol'])
lines.append("""
You can change upload protocol using :ref:`projectconf_upload_protocol` option:
.. code-block:: ini
[env:{id}]
platform = {platform}
board = {id}
upload_protocol = {upload_protocol}
""".format(**variables))
#
# Debugging
#
lines.append("Debugging")
lines.append("---------")
if not board['debug']:
lines.append(
":ref:`piodebug` currently does not support {name} board.".format(
**variables))
else:
default_debug_tool = board_config.get_debug_tool_name()
has_onboard_debug = any(
t.get("onboard") for (_, t) in board['debug']['tools'].items())
lines.append("""
:ref:`piodebug` - "1-click" solution for debugging with a zero configuration.
.. warning::
You will need to install debug tool drivers depending on your system.
Please click on compatible debug tool below for the further
instructions and configuration information.
You can switch between debugging :ref:`debugging_tools` using
:ref:`projectconf_debug_tool` option in :ref:`projectconf`.
""")
if has_onboard_debug:
lines.append(
"{name} has on-board debug probe and **IS READY** for "
"debugging. You don't need to use/buy external debug probe.".
format(**variables))
else:
lines.append(
"{name} does not have on-board debug probe and **IS NOT "
"READY** for debugging. You will need to use/buy one of "
"external probe listed below.".format(**variables))
lines.append("""
.. list-table::
:header-rows: 1
* - Compatible Tools
- On-board
- Default""")
for (tool_name, tool_data) in sorted(board['debug']['tools'].items()):
lines.append(""" * - :ref:`debugging_tool_{name}`
- {onboard}
- {default}""".format(
name=tool_name,
onboard="Yes" if tool_data.get("onboard") else "",
default="Yes" if tool_name == default_debug_tool else ""))
if board['frameworks']:
lines.extend(generate_frameworks_contents(board['frameworks']))
with open(rst_path, "w") as f:
f.write("\n".join(lines))
def update_debugging(): def update_debugging():
tools_to_platforms = {} tool_to_platforms = {}
tool_to_boards = {}
vendors = {} vendors = {}
platforms = [] platforms = []
frameworks = [] frameworks = []
@ -612,9 +774,12 @@ def update_debugging():
for tool in data['debug']['tools']: for tool in data['debug']['tools']:
tool = str(tool) tool = str(tool)
if tool not in tools_to_platforms: if tool not in tool_to_platforms:
tools_to_platforms[tool] = [] tool_to_platforms[tool] = []
tools_to_platforms[tool].append(data['platform']) tool_to_platforms[tool].append(data['platform'])
if tool not in tool_to_boards:
tool_to_boards[tool] = []
tool_to_boards[tool].append(data['id'])
platforms.append(data['platform']) platforms.append(data['platform'])
frameworks.extend(data['frameworks']) frameworks.extend(data['frameworks'])
@ -624,60 +789,12 @@ def update_debugging():
else: else:
vendors[vendor] = [data] vendors[vendor] = [data]
def _update_tool_compat_platforms(content): platforms = sorted(set(platforms))
begin_tpl = ".. begin_compatible_platforms_" frameworks = sorted(set(frameworks))
end_tpl = ".. end_compatible_platforms_"
for tool, platforms in tools_to_platforms.items():
begin = begin_tpl + tool
end = end_tpl + tool
begin_index = content.index(begin)
end_index = content.index(end)
chunk = ["\n\n:Compatible Platforms:\n"]
chunk.extend([
" * :ref:`platform_%s`" % str(p)
for p in sorted(set(platforms))
])
chunk.extend(["\n"])
content = content[:begin_index + len(begin)] + "\n".join(
chunk) + content[end_index:]
return content
lines = [] lines = [".. _debugging_platforms:"]
# Platforms lines.extend(generate_platforms_contents(platforms))
lines.append(""".. _debugging_platforms: lines.extend(generate_frameworks_contents(frameworks))
Platforms
---------
.. list-table::
:header-rows: 1
* - Name
- Description""")
for manifest in PLATFORM_MANIFESTS:
if manifest['name'] not in platforms:
continue
p = PlatformFactory.newPlatform(manifest['name'])
lines.append("""
* - :ref:`platform_{type_}`
- {description}""".format(
type_=manifest['name'], description=p.description))
# Frameworks
lines.append("""
Frameworks
----------
.. list-table::
:header-rows: 1
* - Name
- Description""")
for framework in API_FRAMEWORKS:
if framework['name'] not in frameworks:
continue
lines.append("""
* - :ref:`framework_{name}`
- {description}""".format(**framework))
# Boards # Boards
lines.append(""" lines.append("""
@ -690,17 +807,52 @@ Boards
for vendor, boards in sorted(vendors.iteritems()): for vendor, boards in sorted(vendors.iteritems()):
lines.append(str(vendor)) lines.append(str(vendor))
lines.append("~" * len(vendor)) lines.append("~" * len(vendor))
lines.extend(generate_boards(boards, extend_debug=True)) lines.extend(generate_boards_table(boards))
# save
with open( with open(
join(util.get_source_dir(), "..", "docs", "plus", "debugging.rst"), join(util.get_source_dir(), "..", "docs", "plus", "debugging.rst"),
"r+") as fp: "r+") as fp:
content = _update_tool_compat_platforms(fp.read()) content = fp.read()
fp.seek(0) fp.seek(0)
fp.truncate() fp.truncate()
fp.write(content[:content.index(".. _debugging_platforms:")] + fp.write(content[:content.index(".. _debugging_platforms:")] +
"\n".join(lines)) "\n".join(lines))
# Debug tools
for tool, platforms in tool_to_platforms.items():
tool_path = join(DOCS_ROOT_DIR, "plus", "debug-tools", "%s.rst" % tool)
assert isfile(tool_path)
platforms = sorted(set(platforms))
lines = [".. begin_platforms"]
lines.extend(generate_platforms_contents(platforms))
tool_frameworks = []
for platform in platforms:
for framework in frameworks:
if is_compat_platform_and_framework(platform, framework):
tool_frameworks.append(framework)
lines.extend(generate_frameworks_contents(tool_frameworks))
lines.append("""
Boards
------
.. note::
For more detailed ``board`` information please scroll tables below by horizontal.
""")
lines.extend(
generate_boards_table(
[b for b in BOARDS if b['id'] in tool_to_boards[tool]],
skip_columns=None))
with open(tool_path, "r+") as fp:
content = fp.read()
fp.seek(0)
fp.truncate()
fp.write(content[:content.index(".. begin_platforms")] +
"\n".join(lines))
def update_project_examples(): def update_project_examples():
platform_readme_tpl = """ platform_readme_tpl = """
@ -709,7 +861,7 @@ def update_project_examples():
{description} {description}
* [Home](https://platformio.org/platforms/{name}) (home page in PlatformIO Registry) * [Home](https://platformio.org/platforms/{name}) (home page in PlatformIO Registry)
* [Documentation](http://docs.platformio.org/page/platforms/{name}.html) (advanced usage, packages, boards, frameworks, etc.) * [Documentation](https://docs.platformio.org/page/platforms/{name}.html) (advanced usage, packages, boards, frameworks, etc.)
# Examples # Examples
@ -721,7 +873,7 @@ def update_project_examples():
{description} {description}
* [Home](https://platformio.org/frameworks/{name}) (home page in PlatformIO Registry) * [Home](https://platformio.org/frameworks/{name}) (home page in PlatformIO Registry)
* [Documentation](http://docs.platformio.org/page/frameworks/{name}.html) * [Documentation](https://docs.platformio.org/page/frameworks/{name}.html)
# Examples # Examples
@ -793,7 +945,7 @@ def update_project_examples():
examples="\n".join( examples="\n".join(
framework_examples_md_lines[framework['name']]))) framework_examples_md_lines[framework['name']])))
url = campaign_url( url = campaign_url(
"http://docs.platformio.org/en/latest/frameworks/%s.html#examples" "https://docs.platformio.org/en/latest/frameworks/%s.html#examples"
% framework['name'], % framework['name'],
source="github", source="github",
medium="examples") medium="examples")
@ -826,7 +978,7 @@ def update_project_examples():
def main(): def main():
update_platform_docs() update_platform_docs()
update_framework_docs() update_framework_docs()
update_embedded_boards() update_boards()
update_debugging() update_debugging()
update_project_examples() update_project_examples()

View File

@ -15,6 +15,7 @@
import json import json
import subprocess import subprocess
import sys import sys
from platformio import util
def main(): def main():
@ -24,6 +25,14 @@ def main():
for platform in platforms: for platform in platforms:
if platform['forDesktop']: if platform['forDesktop']:
continue continue
# RISC-V GAP does not support Windows 86
if (util.get_systype() == "windows_x86"
and platform['name'] == "riscv_gap"):
continue
# unknown issue on Linux
if ("linux" in util.get_systype()
and platform['name'] == "aceinna_imu"):
continue
subprocess.check_call( subprocess.check_call(
["platformio", "platform", "install", platform['repository']]) ["platformio", "platform", "install", platform['repository']])

View File

@ -37,7 +37,7 @@ setup(
license=__license__, license=__license__,
python_requires='>=2.7, <3', python_requires='>=2.7, <3',
install_requires=install_requires, install_requires=install_requires,
packages=find_packages(), packages=find_packages() + ["scripts"],
package_data={ package_data={
"platformio": [ "platformio": [
"projectconftpl.ini", "projectconftpl.ini",
@ -45,6 +45,9 @@ setup(
"ide/tpls/*/*.tpl", "ide/tpls/*/*.tpl",
"ide/tpls/*/*/*.tpl", "ide/tpls/*/*/*.tpl",
"ide/tpls/*/.*/*.tpl" "ide/tpls/*/.*/*.tpl"
],
"scripts": [
"99-platformio-udev.rules"
] ]
}, },
entry_points={ entry_points={

View File

@ -61,7 +61,7 @@ def test_global_install_archive(clirunner, validate_cliresult,
"http://www.airspayce.com/mikem/arduino/RadioHead/RadioHead-1.62.zip", "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",
"https://github.com/bblanchon/ArduinoJson/archive/v5.8.2.zip@5.8.2", "https://github.com/bblanchon/ArduinoJson/archive/v5.8.2.zip@5.8.2",
"http://dl.platformio.org/libraries/archives/0/9540.tar.gz", "SomeLib=http://dl.platformio.org/libraries/archives/0/9540.tar.gz",
"https://github.com/Pedroalbuquerque/ESP32WebServer/archive/master.zip" "https://github.com/Pedroalbuquerque/ESP32WebServer/archive/master.zip"
]) ])
validate_cliresult(result) validate_cliresult(result)
@ -75,7 +75,7 @@ def test_global_install_archive(clirunner, validate_cliresult,
items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()]
items2 = [ items2 = [
"RadioHead-1.62", "ArduinoJson", "DallasTemperature_ID54", "RadioHead-1.62", "ArduinoJson", "SomeLib_ID54",
"OneWire_ID1", "ESP32WebServer" "OneWire_ID1", "ESP32WebServer"
] ]
assert set(items1) >= set(items2) assert set(items1) >= set(items2)
@ -158,7 +158,7 @@ def test_global_lib_list(clirunner, validate_cliresult):
items1 = [i['name'] for i in json.loads(result.output)] items1 = [i['name'] for i in json.loads(result.output)]
items2 = [ items2 = [
"ESP32WebServer", "ArduinoJson", "ArduinoJson", "ArduinoJson", "ESP32WebServer", "ArduinoJson", "ArduinoJson", "ArduinoJson",
"ArduinoJson", "AsyncMqttClient", "AsyncTCP", "DallasTemperature", "ArduinoJson", "AsyncMqttClient", "AsyncTCP", "SomeLib",
"ESPAsyncTCP", "NeoPixelBus", "OneWire", "PJON", "PJON", "ESPAsyncTCP", "NeoPixelBus", "OneWire", "PJON", "PJON",
"PubSubClient", "RFcontrol", "RadioHead-1.62", "platformio-libmirror", "PubSubClient", "RFcontrol", "RadioHead-1.62", "platformio-libmirror",
"rs485-nodeproto" "rs485-nodeproto"
@ -202,7 +202,7 @@ def test_global_lib_update(clirunner, validate_cliresult):
# update rest libraries # update rest libraries
result = clirunner.invoke(cmd_lib, ["-g", "update"]) result = clirunner.invoke(cmd_lib, ["-g", "update"])
validate_cliresult(result) validate_cliresult(result)
assert result.output.count("[Fixed]") == 6 assert result.output.count("[Detached]") == 6
assert result.output.count("[Up-to-date]") == 11 assert result.output.count("[Up-to-date]") == 11
assert "Uninstalling RFcontrol @ 77d4eb3f8a" in result.output assert "Uninstalling RFcontrol @ 77d4eb3f8a" in result.output
@ -234,7 +234,7 @@ def test_global_lib_uninstall(clirunner, validate_cliresult,
items2 = [ items2 = [
"RadioHead-1.62", "rs485-nodeproto", "platformio-libmirror", "RadioHead-1.62", "rs485-nodeproto", "platformio-libmirror",
"PubSubClient", "ArduinoJson@src-69ebddd821f771debe7ee734d3c7fa81", "PubSubClient", "ArduinoJson@src-69ebddd821f771debe7ee734d3c7fa81",
"ESPAsyncTCP_ID305", "DallasTemperature_ID54", "NeoPixelBus_ID547", "ESPAsyncTCP_ID305", "SomeLib_ID54", "NeoPixelBus_ID547",
"PJON", "AsyncMqttClient_ID346", "ArduinoJson_ID64", "PJON", "AsyncMqttClient_ID346", "ArduinoJson_ID64",
"PJON@src-79de467ebe19de18287becff0a1fb42d", "ESP32WebServer" "PJON@src-79de467ebe19de18287becff0a1fb42d", "ESP32WebServer"
] ]

View File

@ -25,7 +25,9 @@ def test_build_flags(clirunner, validate_cliresult, tmpdir):
[env:native] [env:native]
platform = native platform = native
extra_scripts = extra.py extra_scripts = extra.py
build_flags = %s build_flags =
; -DCOMMENTED_MACRO
%s ; inline comment
""" % " ".join([f[0] for f in build_flags])) """ % " ".join([f[0] for f in build_flags]))
tmpdir.join("extra.py").write(""" tmpdir.join("extra.py").write("""
@ -47,6 +49,10 @@ projenv.Append(CPPDEFINES="POST_SCRIPT_MACRO")
#error "POST_SCRIPT_MACRO" #error "POST_SCRIPT_MACRO"
#endif #endif
#ifdef COMMENTED_MACRO
#error "COMMENTED_MACRO"
#endif
int main() { int main() {
} }
""") """)

View File

@ -36,6 +36,9 @@ def pytest_generate_tests(metafunc):
p = PlatformFactory.newPlatform(manifest['__pkg_dir']) p = PlatformFactory.newPlatform(manifest['__pkg_dir'])
if not p.is_embedded(): if not p.is_embedded():
continue continue
# issue with "version `CXXABI_1.3.9' not found (required by sdcc)"
if "linux" in util.get_systype() and p.name == "intel_mcs51":
continue
examples_dir = join(p.get_dir(), "examples") examples_dir = join(p.get_dir(), "examples")
assert isdir(examples_dir) assert isdir(examples_dir)
examples_dirs.append(examples_dir) examples_dirs.append(examples_dir)