diff --git a/.coveragerc b/.coveragerc index 80716d3d..01ec788a 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/HISTORY.rst b/HISTORY.rst index 7c4fc0cc..9f73d3cd 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -4,6 +4,133 @@ Release Notes PlatformIO 3.0 -------------- +3.4.0 (2017-06-26) +~~~~~~~~~~~~~~~~~~ + +* `PIO Unified Debugger `__ + + - "1-click" solution, zero configuration + - Support for 100+ embedded boards + - Multiple architectures and development platforms + - Windows, MacOS, Linux (+ARMv6-8) + - Built-in into `PlatformIO IDE for Atom `__ and `PlatformIO IDE for VScode `__ + - Integration with `Eclipse `__ and `Sublime Text `__ + +* Filter `PIO Unit Testing `__ + tests using a new ``test_filter`` option in `Project Configuration File "platformio.ini" `__ + or `platformio test --filter `__ command + (`issue #934 `_) +* Custom ``test_transport`` for `PIO Unit Testing `__ Engine +* Configure Serial Port Monitor in `Project Configuration File "platformio.ini" `__ + (`issue #787 `_) +* New `monitor `__ + target which allows to launch Serial Monitor automatically after successful + "build" or "upload" operations + (`issue #788 `_) +* Project generator for `VIM `__ +* Multi-line support for the different options in `Project Configuration File "platformio.ini" `__, + such as: ``build_flags``, ``build_unflags``, etc. + (`issue #889 `_) +* Handle dynamic ``SRC_FILTER`` environment variable from + `library.json extra script `__ +* Notify about multiple installations of PIO Core + (`issue #961 `_) +* Improved auto-detecting of mbed-enabled media disks +* Automatically update Git-submodules for development platforms and libraries + that were installed from repository +* Add support for ``.*cc`` extension + (`issue #939 `_) +* Handle ``env_default`` in `Project Configuration File "platformio.ini" `__ + when re-initializing a project + (`issue #950 `_) +* Use root directory for PIO Home when path contains non-ascii characters + (`issue #951 `_, + `issue #952 `_) +* Don't warn about known ``boards_dir`` option + (`pull #949 `_) +* Escape non-valid file name characters when installing a new package (library) + (`issue #985 `_) +* Fixed infinite dependency installing when repository consists of multiple + libraries + (`issue #935 `_) +* Fixed linter error "unity.h does not exist" for Unit Testing + (`issue #947 `_) +* Fixed issue when `Library Dependency Finder (LDF) `__ + does not handle custom ``src_dir`` + (`issue #942 `_) +* Fixed cloning a package (library) from a private Git repository with + custom user name and SSH port + (`issue #925 `_) + +------- + +* Development platform `Atmel AVR `__ + + + ATTiny Support (1634, x313, x4, x41, x5, x61, x7, x8) + (`issue #47 `__) + + New boards: Dwenguino, nicai-systems BOB3 coding bot, NIBO 2 robot, + NIBObee robot + + AVRDude TCP upload port (``net:host:port``) + (`pull #45 `_) + + Fixed uploading for LowPowerLab Moteino + +* Development platform `Atmel SAM `__ + + + Support for `PIO Unified Debugger `__ + + Added support for MKRFox1200 board + + Updated Arduino SAMD Core to 1.6.14 + + Updated mbed framework to 5.4.5/142 + + Fixed firmware uploading Arduino Zero and USB-native boards + +* Development platform `Espressif 32 `__ + + + New boards: Adafruit Feather, FireBeetle-ESP32, IntoRobot Fig, NodeMCU-32S, Onehorse ESP32 Dev Module, and Widora AIR + + Added support for OTA (Over-The-Air) updates + + Updated ESP-IDF framework to v2.0 + + Updated core for Arduino framework + +* Development platform `Freescale Kinetis `__ + + + Support for `PIO Unified Debugger `__ + + Updated mbed framework to 5.4.5/142 + +* Development platform `Nordic nRF51 `__ + + + Support for `PIO Unified Debugger `__ + + Updated mbed framework to 5.4.5/142 + +* Development platform `NXP LPC `__ + + + Support for `PIO Unified Debugger `__ + + Updated mbed framework to 5.4.5/142 + +* Development platform `Silicon Labs EFM32 `__ + + + Support for `PIO Unified Debugger `__ + + Updated mbed framework to 5.4.5/142 + +* Development platform `ST STM32 `__ + + + Support for `PIO Unified Debugger `__ + + Added support for new boards: ST STM32F0308DISCOVERY + + Updated ``tool-stlink`` to v1.3.1 + + Updated mbed framework to 5.4.5/142 + +* Development platform `Teensy `__ + + + Updated Teensy Loader CLI to v21 + + Updated Arduino Core to v1.36 + + Updated mbed framework to 5.4.5/142 + +* Development platform `TI MSP430 `__ + + + Support for `PIO Unified Debugger `__ + +* Development platform `TI TIVA `__ + + + Support for `PIO Unified Debugger `__ + + 3.3.1 (2017-05-27) ~~~~~~~~~~~~~~~~~~ @@ -25,11 +152,11 @@ PlatformIO 3.0 command (`issue #430 `_) * List supported frameworks, SDKs with a new - `pio platform frameworks `__ command + `pio platform frameworks `__ command * Visual Studio Code extension for PlatformIO (`issue #619 `_) * Added new options ``--no-reset``, ``--monitor-rts`` and ``--monitor-dtr`` - to `pio test `__ + to `pio test `__ command (allows to avoid automatic board's auto-reset when gathering test results) * Added support for templated methods in ``*.ino to *.cpp`` converter (`pull #858 `_) @@ -167,7 +294,7 @@ PlatformIO 3.0 * Custom boards per project with ``boards_dir`` option in `Project Configuration File "platformio.ini" `__ (`issue #515 `_) -* Unix shell-style wildcards for `upload_port `_ +* Unix shell-style wildcards for `upload_port `_ (`issue #839 `_) * Refactored `Library Dependency Finder (LDF) `__ C/C++ Preprocessor for conditional syntax (``#ifdef``, ``#if``, ``#else``, @@ -294,7 +421,7 @@ PlatformIO 3.0 * Improved Project Generator when custom ``--project-option`` is passed to `platformio init `__ command -* Deprecated ``lib_force`` option, please use `lib_deps `__ instead +* Deprecated ``lib_force`` option, please use `lib_deps `__ instead * Return valid exit code from ``plaformio test`` command * Fixed Project Generator for CLion IDE using Windows OS (`issue #785 `_) @@ -372,7 +499,7 @@ PlatformIO 3.0 * Library Manager 3.0 - + Project dependencies per build environment using `lib_deps `__ option + + Project dependencies per build environment using `lib_deps `__ option (`issue #413 `_) + `Semantic Versioning `__ for library commands and dependencies @@ -396,10 +523,10 @@ PlatformIO 3.0 + Check library compatibility with project environment before building (`issue #415 `_) + Control Library Dependency Finder for compatibility using - `lib_compat_mode `__ + `lib_compat_mode `__ option + Custom library storages/directories with - `lib_extra_dirs `__ option + `lib_extra_dirs `__ option (`issue #537 `_) + Handle extra build flags, source filters and build script from `library.json `__ @@ -655,11 +782,11 @@ PlatformIO 2.0 `platformio lib search `__ command (`issue #604 `_) -* Allowed to specify default environments `env_default `__ +* Allowed to specify default environments `env_default `__ which should be processed by default with ``platformio run`` command (`issue #576 `_) * Allowed to unflag(remove) base/initial flags using - `build_unflags `__ + `build_unflags `__ option (`issue #559 `_) * Allowed multiple VID/PID pairs when detecting serial ports @@ -1107,12 +1234,12 @@ PlatformIO 2.0 ~~~~~~~~~~~~~~~~~~ * Allowed to exclude/include source files from build process using - `src_filter `__ + `src_filter `__ (`issue #240 `_) * Launch own extra script before firmware building/uploading processes (`issue #239 `_) * Specify own path to the linker script (ld) using - `build_flags `__ + `build_flags `__ option (`issue #233 `_) * Specify library compatibility with the all platforms/frameworks @@ -1216,11 +1343,11 @@ PlatformIO 2.0 (`issue #192 `_) * Control verbosity of `platformio run `_ command via ``-v/--verbose`` option * Add library dependencies for build environment using - `lib_install `_ + `lib_install `_ option in ``platformio.ini`` (`issue #134 `_) * Specify libraries which are compatible with build environment using - `lib_use `_ + `lib_use `_ option in ``platformio.ini`` (`issue #148 `_) * Add more boards to PlatformIO project with @@ -1356,7 +1483,7 @@ PlatformIO 1.0 development platform * Added `Project Configuration `__ - option named `envs_dir `__ + option named `envs_dir `__ * Disabled "prompts" automatically for *Continuous Integration* systems (`issue #103 `_) * Fixed firmware uploading for @@ -1400,7 +1527,7 @@ PlatformIO 1.0 `#48 `_, `#50 `_, `#55 `_) -* Added `src_dir `__ +* Added `src_dir `__ option to ``[platformio]`` section of `platformio.ini `__ which allows to redefine location to project's source directory @@ -1411,7 +1538,7 @@ PlatformIO 1.0 commands which allows to return the output in `JSON `_ format (`issue #42 `_) * Allowed to ignore some libs from *Library Dependency Finder* via - `lib_ignore `_ option + `lib_ignore `_ option * Improved `platformio run `__ command: asynchronous output for build process, timing and detailed information about environment configuration diff --git a/README.rst b/README.rst index 44a24151..a11a77ca 100644 --- a/README.rst +++ b/README.rst @@ -37,123 +37,47 @@ PlatformIO `Bintray `_ | `Community `_ -.. image:: http://docs.platformio.org/en/stable/_static/platformio-logo.png +.. image:: https://raw.githubusercontent.com/platformio/platformio-web/develop/app/images/platformio-ide-laptop.png :target: http://platformio.org `PlatformIO `_ is an open source ecosystem for IoT -development. Cross-platform build system and library manager. Continuous and -IDE integration. Arduino, ESP8266 and ARM mbed compatible +development. Cross-platform IDE and unified debugger. Remote unit testing and +firmware updates. -* **PlatformIO IDE** - The next-generation integrated development environment for IoT. - C/C++ Intelligent Code Completion and Smart Code Linter for the super-fast coding. - Multi-projects workflow with Multiple Panes. Themes Support with dark and light colors. - Built-in Terminal with PlatformIO Core tool and support for the powerful Serial Port Monitor. - All advanced instruments without leaving your favourite development environment. -* **Development Platforms** - Embedded and Desktop development platforms with - pre-built toolchains, debuggers, uploaders and frameworks which work under - popular host OS: Mac, Windows, Linux (+ARM) -* **Embedded Boards** - Rapid Embedded Programming, IDE and Continuous - Integration in a few steps with PlatformIO thanks to built-in project - generator for the most popular embedded boards and IDE -* **Library Manager** - Hundreds Popular Libraries are organized into single - Web 2.0 platform: list by categories, keywords, authors, compatible - platforms and frameworks; learn via examples; be up-to-date with the latest - version. +Get Started +----------- -*Atmel AVR & SAM, Espressif, Freescale Kinetis, Intel ARC32, Lattice iCE40, -Microchip PIC32, Nordic nRF51, NXP LPC, Silicon Labs EFM32, ST STM32, -TI MSP430 & Tiva, Teensy, Arduino, mbed, libOpenCM3, etc.* +* `What is PlatformIO? `_ -.. image:: http://docs.platformio.org/en/stable/_static/platformio-demo-wiring.gif - :target: http://platformio.org +Products +-------- -* `PlatformIO Plus and professional solutions `_ * `PlatformIO IDE `_ -* `Get Started `_ -* `Library Search and Registry `_ +* `PlatformIO Core `_ +* `PIO Remote™ `_ +* `PIO Unified Debugger `_ +* `PIO Unit Testing `_ +* `PIO Delivery™ `_ +* `Cloud Builder `_ + +Registry +-------- + +* `Libraries `_ * `Development Platforms `_ * `Frameworks `_ -* `Embedded Boards Explorer `_ -* `Library Manager `_ -* `User Guide `_ -* `Continuous Integration `_ -* `IDE Integration `_ -* `Articles about us `_ -* `FAQ `_ -* `Release Notes `_ +* `Embedded Boards `_ -Use whenever. *Run everywhere.* -------------------------------- -*PlatformIO* is written in pure *Python* and **doesn't depend** on any -additional libraries/tools from an operating system. It allows you to use -*PlatformIO* beginning from *PC (Mac, Linux, Win)* and ending with credit-card -sized computers (`Raspberry Pi `_, -`BeagleBone `_, -`CubieBoard `_). +Solutions +--------- -Embedded Development. *Easier Than Ever.* ------------------------------------------ -*PlatformIO* is well suited for embedded development and has pre-configured -settings for most popular `Embedded Boards `_. +* `Library Manager `_ +* `Cloud IDEs Integration `_ +* `Standalone IDEs Integration `_ +* `Continuous Integration `_ -* Colourful `command-line output `_ -* `IDE Integration `_ with - *Cloud9, Codeanywhere, Eclipse Che, Atom, CLion, CodeBlocks, Eclipse, Emacs, NetBeans, Qt Creator, Sublime Text, Vim, Visual Studio* -* Cloud compiling and `Continuous Integration `_ - with *AppVeyor, Circle CI, Drone, Shippable, Travis CI* -* Built-in `Serial Port Monitor `_ and configurable - `build -flags/-options `_ -* Automatic **firmware uploading** -* Pre-built tool chains, frameworks for the popular `development platforms `_ - -.. image:: https://raw.githubusercontent.com/platformio/platformio-web/develop/app/images/platformio-embedded-development.png - :target: http://platformio.org - :alt: PlatformIO Embedded Development Process - -The Missing Library Manager. *It's here!* ------------------------------------------ -*PlatformIO Library Manager* is the missing library manager for development -platforms which allows you to organize and have up-to-date external libraries. - -* Friendly `Command-Line Interface `_ -* Modern `Web 2.0 Library Portal `_ -* Open Source `Library Registry API `_ -* Library Crawler based on `library.json `_ - specification -* Project Dependency Manager with `Semantic Versioning `_ requirements - -.. image:: https://raw.githubusercontent.com/platformio/platformio-web/develop/app/images/platformio-library-manager.png - :target: http://platformio.org - :alt: PlatformIO Library Manager Architecture - -Smart Build System. *Fast and Reliable.* ----------------------------------------- -*PlatformIO Code Builder* is built-on a next-generation software construction -tool named `SCons `_. Think of *SCons* as an improved, -cross-platform substitute for the classic *Make* utility. - -* Reliable, automatic *dependency analysis* -* Reliable detection of *build changes* -* Improved support for *parallel builds* -* Ability to share *built files in a cache* -* Lookup for external libraries which are installed via `Library Manager `_ - -.. image:: https://raw.githubusercontent.com/platformio/platformio-web/develop/app/images/platformio-scons-builder.png - :target: http://platformio.org - :alt: PlatformIO Build System Architecture - -Single source code. *Multiple platforms.* ------------------------------------------ -*PlatformIO* allows the developer to compile the same code with different -development platforms using only *One Command* -`platformio run `_. -This happens due to -`Project Configuration File (platformio.ini) `_ -where you can setup different environments with specific options (platform -type, firmware uploading settings, pre-built framework, build flags and many -more). - -It has support for the most popular embedded platforms: +Development Platforms +--------------------- * `Atmel AVR `_ * `Atmel SAM `_ @@ -162,16 +86,20 @@ It has support for the most popular embedded platforms: * `Freescale Kinetis `_ * `Intel ARC32 `_ * `Lattice iCE40 `_ +* `Maxim 32 `_ * `Microchip PIC32 `_ * `Nordic nRF51 `_ +* `Nordic nRF52 `_ * `NXP LPC `_ -* `ST STM32 `_ * `Silicon Labs EFM32 `_ +* `ST STM32 `_ * `Teensy `_ * `TI MSP430 `_ * `TI TivaVA C `_ +* `WIZNet W7500 `_ -Frameworks: +Frameworks +---------- * `Arduino `_ * `ARTIK SDK `_ @@ -183,10 +111,9 @@ Frameworks: * `Pumbaa `_ * `Simba `_ * `SPL `_ +* `STM32Cube `_ * `WiringPi `_ -For further details, please refer to `What is PlatformIO? `_ - Contributing ------------ @@ -195,7 +122,7 @@ See `contributing guidelines +Copyright (c) 2014-present PlatformIO The PlatformIO is licensed under the permissive Apache 2.0 license, so you can use it in both commercial and personal projects with confidence. diff --git a/docs b/docs index d20acf36..58574c07 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit d20acf36318cda3594f03e7fb075810e9180d64c +Subproject commit 58574c074149656f1cfc5290122251ea6a5344c6 diff --git a/examples b/examples index 60609b12..372f45c9 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 60609b12231c46df6be2c8a0a5a7d42ca3bcc65d +Subproject commit 372f45c9d4394d1d1559057d59f5f5d22933d5d8 diff --git a/platformio/__init__.py b/platformio/__init__.py index 8ecd2706..0c26d0af 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ import sys -VERSION = (3, 3, 1) +VERSION = (3, 4, 0) __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" @@ -33,7 +33,8 @@ __copyright__ = "Copyright 2014-present PlatformIO" __apiurl__ = "https://api.platformio.org" if sys.version_info < (2, 7, 0) or sys.version_info >= (3, 0, 0): - msg = ("PlatformIO version %s does not run under Python version %s.\n" + msg = ("PlatformIO Core v%s does not run under Python version %s.\n" + "Minimum supported version is 2.7, please upgrade Python.\n" "Python 3 is not yet supported.\n") sys.stderr.write(msg % (__version__, sys.version.split()[0])) sys.exit(1) diff --git a/platformio/__main__.py b/platformio/__main__.py index 8dcd88a2..b1872fd2 100644 --- a/platformio/__main__.py +++ b/platformio/__main__.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,14 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -from os import getenv, listdir +import os +import sys from os.path import join from platform import system -from sys import exit as sys_exit from traceback import format_exc import click -import requests from platformio import __version__, exception, maintenance from platformio.util import get_source_dir @@ -29,7 +28,7 @@ class PlatformioCLI(click.MultiCommand): # pylint: disable=R0904 def list_commands(self, ctx): cmds = [] - for filename in listdir(join(get_source_dir(), "commands")): + for filename in os.listdir(join(get_source_dir(), "commands")): if filename.startswith("__init__"): continue if filename.endswith(".py"): @@ -37,16 +36,16 @@ class PlatformioCLI(click.MultiCommand): # pylint: disable=R0904 cmds.sort() return cmds - def get_command(self, ctx, name): + def get_command(self, ctx, cmd_name): mod = None try: - mod = __import__("platformio.commands." + name, None, None, + mod = __import__("platformio.commands." + cmd_name, None, None, ["cli"]) except ImportError: try: - return self._handle_obsolate_command(name) + return self._handle_obsolate_command(cmd_name) except AttributeError: - raise click.UsageError('No such command "%s"' % name, ctx) + raise click.UsageError('No such command "%s"' % cmd_name, ctx) return mod.cli @staticmethod @@ -95,7 +94,7 @@ def main(): pass # handle PLATFORMIO_FORCE_COLOR - if str(getenv("PLATFORMIO_FORCE_COLOR", "")).lower() == "true": + if str(os.getenv("PLATFORMIO_FORCE_COLOR", "")).lower() == "true": try: # pylint: disable=protected-access click._compat.isatty = lambda stream: True @@ -132,5 +131,10 @@ An unexpected error occurred. Further steps: return 0 +def debug_gdb_main(): + sys.argv = [sys.argv[0], "debug", "--interface", "gdb"] + sys.argv[1:] + return main() + + if __name__ == "__main__": - sys_exit(main()) + sys.exit(main()) diff --git a/platformio/app.py b/platformio/app.py index e6cbc0b2..d4bfdb3e 100644 --- a/platformio/app.py +++ b/platformio/app.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -64,7 +64,8 @@ DEFAULT_SETTINGS = { "description": ("Telemetry service (Yes/No)"), - "value": True + "value": + True } } @@ -142,28 +143,8 @@ class ContentCache(object): def __enter__(self): if not self._db_path or not isfile(self._db_path): return self - found = False - newlines = [] - with open(self._db_path) as fp: - for line in fp.readlines(): - if "=" not in line: - continue - line = line.strip() - expire, path = line.split("=") - if time() < int(expire) and isfile(path): - newlines.append(line) - continue - found = True - if isfile(path): - remove(path) - if not len(listdir(dirname(path))): - util.rmtree_(dirname(path)) - - if found and self._lock_dbindex(): - with open(self._db_path, "w") as fp: - fp.write("\n".join(newlines) + "\n") - self._unlock_dbindex() + self.delete() return self def __exit__(self, type_, value, traceback): @@ -187,6 +168,7 @@ class ContentCache(object): def _unlock_dbindex(self): if self._lockfile: self._lockfile.release() + return True def get_cache_path(self, key): assert len(key) > 3 @@ -210,28 +192,64 @@ class ContentCache(object): return data def set(self, key, data, valid): + cache_path = self.get_cache_path(key) + if isfile(cache_path): + self.delete(key) if not data: return if not isdir(self.cache_dir): os.makedirs(self.cache_dir) tdmap = {"s": 1, "m": 60, "h": 3600, "d": 86400} assert valid.endswith(tuple(tdmap.keys())) - cache_path = self.get_cache_path(key) expire_time = int(time() + tdmap[valid[-1]] * int(valid[:-1])) if not self._lock_dbindex(): return False - with open(self._db_path, "a") as fp: - fp.write("%s=%s\n" % (str(expire_time), cache_path)) - self._unlock_dbindex() if not isdir(dirname(cache_path)): os.makedirs(dirname(cache_path)) with open(cache_path, "wb") as fp: - if isinstance(data, dict) or isinstance(data, list): + if isinstance(data, (dict, list)): json.dump(data, fp) else: fp.write(str(data)) + with open(self._db_path, "a") as fp: + fp.write("%s=%s\n" % (str(expire_time), cache_path)) + + return self._unlock_dbindex() + + def delete(self, keys=None): + """ Keys=None, delete expired items """ + if not keys: + keys = [] + if not isinstance(keys, list): + keys = [keys] + paths_for_delete = [self.get_cache_path(k) for k in keys] + found = False + newlines = [] + with open(self._db_path) as fp: + for line in fp.readlines(): + if "=" not in line: + continue + line = line.strip() + expire, path = line.split("=") + if time() < int(expire) and isfile(path) and \ + path not in paths_for_delete: + newlines.append(line) + continue + found = True + if isfile(path): + try: + remove(path) + if not listdir(dirname(path)): + util.rmtree_(dirname(path)) + except OSError: + pass + + if found and self._lock_dbindex(): + with open(self._db_path, "w") as fp: + fp.write("\n".join(newlines) + "\n") + self._unlock_dbindex() return True @@ -274,6 +292,12 @@ def set_state_item(name, value): data[name] = value +def delete_state_item(name): + with State(lock=True) as data: + if name in data: + del data[name] + + def get_setting(name): _env_name = "PLATFORMIO_SETTING_%s" % name.upper() if _env_name in environ: @@ -310,7 +334,8 @@ def set_session_var(name, value): def is_disabled_progressbar(): return any([ - get_session_var("force_option"), util.is_ci(), + get_session_var("force_option"), + util.is_ci(), getenv("PLATFORMIO_DISABLE_PROGRESSBAR") == "true" ]) diff --git a/platformio/builder/__init__.py b/platformio/builder/__init__.py index 95899c71..b0514903 100644 --- a/platformio/builder/__init__.py +++ b/platformio/builder/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 5fbc2174..679236bc 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,6 +14,7 @@ import base64 import json +import sys from os import environ from os.path import join from time import time @@ -63,12 +64,13 @@ commonvars.AddVariables( ("UPLOAD_SPEED",), ("UPLOAD_FLAGS",), ("UPLOAD_RESETMETHOD",) + ) # yapf: disable DEFAULT_ENV_OPTIONS = dict( tools=[ "ar", "as", "gcc", "g++", "gnulink", "platformio", "pioplatform", - "piowinhooks", "piolib", "piotest", "pioupload", "piomisc" + "piowinhooks", "piolib", "pioupload", "piomisc", "pioide" ], # yapf: disable toolpath=[join(util.get_source_dir(), "builder", "tools")], variables=commonvars, @@ -77,7 +79,6 @@ DEFAULT_ENV_OPTIONS = dict( PIOVARIABLES=commonvars.keys(), ENV=environ, UNIX_TIME=int(time()), - PROGNAME="program", PIOHOME_DIR=util.get_home_dir(), PROJECT_DIR=util.get_project_dir(), PROJECTSRC_DIR=util.get_projectsrc_dir(), @@ -88,9 +89,12 @@ DEFAULT_ENV_OPTIONS = dict( BUILDSRC_DIR=join("$BUILD_DIR", "src"), BUILDTEST_DIR=join("$BUILD_DIR", "test"), LIBSOURCE_DIRS=[ - util.get_projectlib_dir(), util.get_projectlibdeps_dir(), + util.get_projectlib_dir(), + util.get_projectlibdeps_dir(), join("$PIOHOME_DIR", "lib") ], + PROGNAME="program", + PROG_PATH=join("$BUILD_DIR", "$PROGNAME$PROGSUFFIX"), PYTHONEXE=util.get_pythonexe_path()) if not int(ARGUMENTS.get("PIOVERBOSE", 0)): @@ -106,6 +110,8 @@ env = DefaultEnvironment(**DEFAULT_ENV_OPTIONS) for k in commonvars.keys(): if k in env: env[k] = base64.b64decode(env[k]) + if "\n" in env[k]: + env[k] = [v.strip() for v in env[k].split("\n") if v.strip()] if env.GetOption('clean'): env.PioClean(env.subst("$BUILD_DIR")) @@ -121,21 +127,23 @@ for var in ("BUILD_FLAGS", "SRC_BUILD_FLAGS", "SRC_FILTER", "EXTRA_SCRIPT", continue if var in ("UPLOAD_PORT", "EXTRA_SCRIPT") or not env.get(var): env[var] = environ.get(k) + elif isinstance(env[var], list): + env.Append(**{var: environ.get(k)}) else: env[var] = "%s%s%s" % (environ.get(k), ", " if var == "LIB_EXTRA_DIRS" else " ", env[var]) # Parse comma separated items for opt in ("PIOFRAMEWORK", "LIB_DEPS", "LIB_IGNORE", "LIB_EXTRA_DIRS"): - if opt not in env: + if opt not in env or isinstance(env[opt], list): continue env[opt] = [l.strip() for l in env[opt].split(", ") if l.strip()] # Configure extra library source directories for LDF if util.get_project_optional_dir("lib_extra_dirs"): + items = util.get_project_optional_dir("lib_extra_dirs") env.Prepend(LIBSOURCE_DIRS=[ - l.strip() - for l in util.get_project_optional_dir("lib_extra_dirs").split(", ") + l.strip() for l in items.split("\n" if "\n" in items else ", ") if l.strip() ]) env.Prepend(LIBSOURCE_DIRS=env.get("LIB_EXTRA_DIRS", [])) @@ -146,6 +154,7 @@ env.SConscriptChdir(0) env.SConsignFile(join("$PROJECTPIOENVS_DIR", ".sconsign.dblite")) env.SConscript("$BUILD_SCRIPT") +AlwaysBuild(env.Alias("__debug", DEFAULT_TARGETS + ["size"])) AlwaysBuild(env.Alias("__test", DEFAULT_TARGETS + ["size"])) if "UPLOAD_FLAGS" in env: @@ -159,5 +168,13 @@ if "envdump" in COMMAND_LINE_TARGETS: env.Exit(0) if "idedata" in COMMAND_LINE_TARGETS: - print "\n%s\n" % json.dumps(env.DumpIDEData()) - env.Exit(0) + try: + print "\n%s\n" % json.dumps(env.DumpIDEData()) + env.Exit(0) + except UnicodeDecodeError: + sys.stderr.write( + "\nUnicodeDecodeError: Non-ASCII characters found in build " + "environment\n" + "See explanation in FAQ > Troubleshooting > Building\n" + "http://docs.platformio.org/page/faq.html\n\n") + env.Exit(1) diff --git a/platformio/builder/tools/__init__.py b/platformio/builder/tools/__init__.py index 95899c71..b0514903 100644 --- a/platformio/builder/tools/__init__.py +++ b/platformio/builder/tools/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/builder/tools/pioide.py b/platformio/builder/tools/pioide.py new file mode 100644 index 00000000..e05b2d79 --- /dev/null +++ b/platformio/builder/tools/pioide.py @@ -0,0 +1,120 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import + +from glob import glob +from os.path import join + +from SCons.Defaults import processDefines + +from platformio import util +from platformio.managers.core import get_core_package_dir + + +def dump_includes(env): + includes = [] + + for item in env.get("CPPPATH", []): + includes.append(env.subst(item)) + + # installed libs + for lb in env.GetLibBuilders(): + includes.extend(lb.get_inc_dirs()) + + # includes from toolchains + p = env.PioPlatform() + for name in p.get_installed_packages(): + if p.get_package_type(name) != "toolchain": + continue + toolchain_dir = util.glob_escape(p.get_package_dir(name)) + toolchain_incglobs = [ + join(toolchain_dir, "*", "include*"), + join(toolchain_dir, "lib", "gcc", "*", "*", "include*") + ] + for g in toolchain_incglobs: + includes.extend(glob(g)) + + unity_dir = get_core_package_dir("tool-unity") + if unity_dir: + includes.append(unity_dir) + + return includes + + +def dump_defines(env): + defines = [] + # global symbols + for item in processDefines(env.get("CPPDEFINES", [])): + defines.append(env.subst(item).replace('\\', '')) + + # special symbol for Atmel AVR MCU + if env['PIOPLATFORM'] == "atmelavr": + defines.append( + "__AVR_%s__" % env.BoardConfig().get("build.mcu").upper() + .replace("ATMEGA", "ATmega").replace("ATTINY", "ATtiny")) + return defines + + +def DumpIDEData(env): + LINTCCOM = "$CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS" + LINTCXXCOM = "$CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS" + + data = { + "libsource_dirs": + [env.subst(l) for l in env.get("LIBSOURCE_DIRS", [])], + "defines": + dump_defines(env), + "includes": + dump_includes(env), + "cc_flags": + env.subst(LINTCCOM), + "cxx_flags": + env.subst(LINTCXXCOM), + "cc_path": + util.where_is_program(env.subst("$CC"), env.subst("${ENV['PATH']}")), + "cxx_path": + util.where_is_program(env.subst("$CXX"), env.subst("${ENV['PATH']}")), + "gdb_path": + util.where_is_program(env.subst("$GDB"), env.subst("${ENV['PATH']}")), + "prog_path": + env.subst("$PROG_PATH") + } + + env_ = env.Clone() + # https://github.com/platformio/platformio-atom-ide/issues/34 + _new_defines = [] + for item in processDefines(env_.get("CPPDEFINES", [])): + item = item.replace('\\"', '"') + if " " in item: + _new_defines.append(item.replace(" ", "\\\\ ")) + else: + _new_defines.append(item) + env_.Replace(CPPDEFINES=_new_defines) + + data.update({ + "cc_flags": env_.subst(LINTCCOM), + "cxx_flags": env_.subst(LINTCXXCOM) + }) + + return data + + +def exists(_): + return True + + +def generate(env): + env.AddMethod(DumpIDEData) + return env diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 57163ee9..8f7a1f52 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -39,8 +39,8 @@ class LibBuilderFactory(object): clsname = "PlatformIOLibBuilder" else: used_frameworks = LibBuilderFactory.get_used_frameworks(env, path) - common_frameworks = (set(env.get("PIOFRAMEWORK", [])) & - set(used_frameworks)) + common_frameworks = ( + set(env.get("PIOFRAMEWORK", [])) & set(used_frameworks)) if common_frameworks: clsname = "%sLibBuilder" % list(common_frameworks)[0].title() elif used_frameworks: @@ -65,7 +65,8 @@ class LibBuilderFactory(object): # check source files for root, _, files in os.walk(path, followlinks=True): for fname in files: - if not env.IsFileWithExt(fname, ("c", "cpp", "h", "hpp")): + if not env.IsFileWithExt( + fname, piotool.SRC_BUILD_EXT + piotool.SRC_HEADER_EXT): continue with open(join(root, fname)) as f: content = f.read() @@ -100,6 +101,9 @@ class LibBuilderBase(object): self._circular_deps = list() self._scanned_paths = list() + # reset source filter, could be overridden with extra script + self.env['SRC_FILTER'] = "" + # process extra options and append to build environment self.process_extra_options() @@ -130,8 +134,10 @@ class LibBuilderBase(object): @property def src_filter(self): return piotool.SRC_FILTER_DEFAULT + [ - "-" % os.sep, "-" % os.sep, "-" % - os.sep, "-" % os.sep + "-" % os.sep, + "-" % os.sep, + "-" % os.sep, + "-" % os.sep ] @property @@ -225,6 +231,7 @@ class LibBuilderBase(object): self.env.ProcessUnFlags(self.build_unflags) self.env.ProcessFlags(self.build_flags) if self.extra_script: + self.env.SConscriptChdir(1) self.env.SConscript( realpath(self.extra_script), exports={"env": self.env, @@ -242,8 +249,9 @@ class LibBuilderBase(object): if (key in item and not self.items_in_list(self.env[env_key], item[key])): if self.verbose: - sys.stderr.write("Skip %s incompatible dependency %s\n" - % (key[:-1], item)) + sys.stderr.write( + "Skip %s incompatible dependency %s\n" % (key[:-1], + item)) skip = True if skip: continue @@ -332,8 +340,8 @@ class LibBuilderBase(object): if _already_depends(lb): if self.verbose: sys.stderr.write("Warning! Circular dependencies detected " - "between `%s` and `%s`\n" % - (self.path, lb.path)) + "between `%s` and `%s`\n" % (self.path, + lb.path)) self._circular_deps.append(lb) elif lb not in self._depbuilders: self._depbuilders.append(lb) @@ -406,6 +414,10 @@ class ProjectAsLibBuilder(LibBuilderBase): LibBuilderBase.__init__(self, *args, **kwargs) self._is_built = True + @property + def src_dir(self): + return self.env.subst("$PROJECTSRC_DIR") + @property def lib_ldf_mode(self): mode = LibBuilderBase.lib_ldf_mode.fget(self) @@ -513,6 +525,8 @@ class PlatformIOLibBuilder(LibBuilderBase): def src_filter(self): if "srcFilter" in self._manifest.get("build", {}): return self._manifest.get("build").get("srcFilter") + elif self.env['SRC_FILTER']: + return self.env['SRC_FILTER'] elif self._is_arduino_manifest(): return ArduinoLibBuilder.src_filter.fget(self) return LibBuilderBase.src_filter.fget(self) @@ -593,14 +607,14 @@ def GetLibBuilders(env): # pylint: disable=too-many-branches if compat_mode > 1 and not lb.is_platforms_compatible( env['PIOPLATFORM']): if verbose: - sys.stderr.write("Platform incompatible library %s\n" % - lb.path) + sys.stderr.write( + "Platform incompatible library %s\n" % lb.path) return False if compat_mode > 0 and "PIOFRAMEWORK" in env and \ not lb.is_frameworks_compatible(env.get("PIOFRAMEWORK", [])): if verbose: - sys.stderr.write("Framework incompatible library %s\n" % - lb.path) + sys.stderr.write( + "Framework incompatible library %s\n" % lb.path) return False return True diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 2aa259e3..f716347f 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,16 +17,15 @@ from __future__ import absolute_import import atexit import re import sys -from glob import glob from os import environ, remove, walk -from os.path import basename, isdir, isfile, join, relpath +from os.path import basename, isdir, isfile, join, relpath, sep from tempfile import mkstemp from SCons.Action import Action -from SCons.Defaults import processDefines from SCons.Script import ARGUMENTS from platformio import util +from platformio.managers.core import get_core_package_dir class InoToCPPConverter(object): @@ -90,8 +89,8 @@ class InoToCPPConverter(object): self.env.Execute( self.env.VerboseAction( '$CXX -o "{0}" -x c++ -fpreprocessed -dD -E "{1}"'.format( - out_file, tmp_path), "Converting " + basename( - out_file[:-4]))) + out_file, + tmp_path), "Converting " + basename(out_file[:-4]))) atexit.register(_delete_file, tmp_path) return isfile(out_file) @@ -116,7 +115,7 @@ class InoToCPPConverter(object): elif stropen: newlines[len(newlines) - 1] += line[:-1] continue - elif stropen and line.endswith('";'): + elif stropen and line.endswith(('",', '";')): newlines[len(newlines) - 1] += line stropen = False newlines.append('#line %d "%s"' % @@ -140,8 +139,8 @@ class InoToCPPConverter(object): prototypes = [] reserved_keywords = set(["if", "else", "while"]) for match in self.PROTOTYPE_RE.finditer(contents): - if (set([match.group(2).strip(), match.group(3).strip()]) & - reserved_keywords): + if (set([match.group(2).strip(), + match.group(3).strip()]) & reserved_keywords): continue prototypes.append(match) return prototypes @@ -200,81 +199,6 @@ def _delete_file(path): pass -def DumpIDEData(env): - - def get_includes(env_): - includes = [] - - for item in env_.get("CPPPATH", []): - includes.append(env_.subst(item)) - - # installed libs - for lb in env.GetLibBuilders(): - includes.extend(lb.get_inc_dirs()) - - # includes from toolchains - p = env.PioPlatform() - for name in p.get_installed_packages(): - if p.get_package_type(name) != "toolchain": - continue - toolchain_dir = util.glob_escape(p.get_package_dir(name)) - toolchain_incglobs = [ - join(toolchain_dir, "*", "include*"), - join(toolchain_dir, "lib", "gcc", "*", "*", "include*") - ] - for g in toolchain_incglobs: - includes.extend(glob(g)) - - return includes - - def get_defines(env_): - defines = [] - # global symbols - for item in processDefines(env_.get("CPPDEFINES", [])): - defines.append(env_.subst(item).replace('\\', '')) - - # special symbol for Atmel AVR MCU - if env['PIOPLATFORM'] == "atmelavr": - defines.append( - "__AVR_%s__" % env.BoardConfig().get("build.mcu").upper() - .replace("ATMEGA", "ATmega").replace("ATTINY", "ATtiny")) - return defines - - LINTCCOM = "$CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS" - LINTCXXCOM = "$CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS" - env_ = env.Clone() - - data = { - "libsource_dirs": - [env_.subst(l) for l in env_.get("LIBSOURCE_DIRS", [])], - "defines": get_defines(env_), - "includes": get_includes(env_), - "cc_flags": env_.subst(LINTCCOM), - "cxx_flags": env_.subst(LINTCXXCOM), - "cc_path": util.where_is_program( - env_.subst("$CC"), env_.subst("${ENV['PATH']}")), - "cxx_path": util.where_is_program( - env_.subst("$CXX"), env_.subst("${ENV['PATH']}")) - } - - # https://github.com/platformio/platformio-atom-ide/issues/34 - _new_defines = [] - for item in processDefines(env_.get("CPPDEFINES", [])): - item = item.replace('\\"', '"') - if " " in item: - _new_defines.append(item.replace(" ", "\\\\ ")) - else: - _new_defines.append(item) - env_.Replace(CPPDEFINES=_new_defines) - - data.update({ - "cc_flags": env_.subst(LINTCCOM), - "cxx_flags": env_.subst(LINTCXXCOM) - }) - - return data - - def GetCompilerType(env): try: sysenv = environ.copy() @@ -329,8 +253,7 @@ def GetActualLDScript(env): def VerboseAction(_, act, actstr): if int(ARGUMENTS.get("PIOVERBOSE", 0)): return act - else: - return Action(act, actstr) + return Action(act, actstr) def PioClean(env, clean_dir): @@ -346,15 +269,44 @@ def PioClean(env, clean_dir): env.Exit(0) +def ProcessDebug(env): + if not env.subst("$PIODEBUGFLAGS"): + env.Replace(PIODEBUGFLAGS=["-Og", "-g3", "-ggdb"]) + env.Append( + BUILD_FLAGS=env.get("PIODEBUGFLAGS", []), + BUILD_UNFLAGS=["-Os", "-O0", "-O1", "-O2", "-O3"]) + + +def ProcessTest(env): + env.Append( + CPPDEFINES=["UNIT_TEST", "UNITY_INCLUDE_CONFIG_H"], + CPPPATH=[join("$BUILD_DIR", "UnityTestLib")]) + unitylib = env.BuildLibrary( + join("$BUILD_DIR", "UnityTestLib"), get_core_package_dir("tool-unity")) + env.Prepend(LIBS=[unitylib]) + + src_filter = None + if "PIOTEST" in env: + src_filter = "+" + src_filter += " +<%s%s>" % (env['PIOTEST'], sep) + + return env.CollectBuildFiles( + "$BUILDTEST_DIR", + "$PROJECTTEST_DIR", + src_filter=src_filter, + duplicate=False) + + def exists(_): return True def generate(env): env.AddMethod(ConvertInoToCpp) - env.AddMethod(DumpIDEData) env.AddMethod(GetCompilerType) env.AddMethod(GetActualLDScript) env.AddMethod(VerboseAction) env.AddMethod(PioClean) + env.AddMethod(ProcessDebug) + env.AddMethod(ProcessTest) return env diff --git a/platformio/builder/tools/pioplatform.py b/platformio/builder/tools/pioplatform.py index da15af18..9be56410 100644 --- a/platformio/builder/tools/pioplatform.py +++ b/platformio/builder/tools/pioplatform.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -81,7 +81,8 @@ def LoadPioPlatform(env, variables): board_config = env.BoardConfig() for k in variables.keys(): if (k in env or - not any([k.startswith("BOARD_"), k.startswith("UPLOAD_")])): + not any([k.startswith("BOARD_"), + k.startswith("UPLOAD_")])): continue _opt, _val = k.lower().split("_", 1) if _opt == "board": diff --git a/platformio/builder/tools/piotest.py b/platformio/builder/tools/piotest.py deleted file mode 100644 index 04035e9c..00000000 --- a/platformio/builder/tools/piotest.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2014-present PlatformIO -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import absolute_import - -from os.path import join, sep - -from platformio.managers.core import get_core_package_dir - - -def ProcessTest(env): - env.Append( - CPPDEFINES=["UNIT_TEST", "UNITY_INCLUDE_CONFIG_H"], - CPPPATH=[join("$BUILD_DIR", "UnityTestLib")]) - unitylib = env.BuildLibrary( - join("$BUILD_DIR", "UnityTestLib"), get_core_package_dir("tool-unity")) - env.Prepend(LIBS=[unitylib]) - - src_filter = None - if "PIOTEST" in env: - src_filter = "+" - src_filter += " +<%s%s>" % (env['PIOTEST'], sep) - - return env.CollectBuildFiles( - "$BUILDTEST_DIR", - "$PROJECTTEST_DIR", - src_filter=src_filter, - duplicate=False) - - -def exists(_): - return True - - -def generate(env): - env.AddMethod(ProcessTest) - return env diff --git a/platformio/builder/tools/pioupload.py b/platformio/builder/tools/pioupload.py index 7f2fd42e..4547858d 100644 --- a/platformio/builder/tools/pioupload.py +++ b/platformio/builder/tools/pioupload.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ from shutil import copyfile from time import sleep from SCons.Node.Alias import Alias -from serial import Serial +from serial import Serial, SerialException from platformio import util @@ -48,7 +48,6 @@ def TouchSerialPort(env, port, baudrate): s.close() except: # pylint: disable=W0702 pass - sleep(0.4) def WaitForNewSerialPort(env, before): @@ -56,12 +55,12 @@ def WaitForNewSerialPort(env, before): prev_port = env.subst("$UPLOAD_PORT") new_port = None elapsed = 0 - sleep(1) + before = [p['port'] for p in before] while elapsed < 5 and new_port is None: - now = util.get_serialports() + now = [p['port'] for p in util.get_serialports()] for p in now: if p not in before: - new_port = p['port'] + new_port = p break before = now sleep(0.25) @@ -69,10 +68,16 @@ def WaitForNewSerialPort(env, before): if not new_port: for p in now: - if prev_port == p['port']: - new_port = p['port'] + if prev_port == p: + new_port = p break + try: + s = Serial(new_port) + s.close() + except SerialException: + sleep(1) + if not new_port: sys.stderr.write("Error: Couldn't find a board on the selected port. " "Check that you have the correct port selected. " @@ -102,13 +107,17 @@ def AutodetectUploadPort(*args, **kwargs): # pylint: disable=unused-argument def _look_for_mbed_disk(): msdlabels = ("mbed", "nucleo", "frdm", "microbit") for item in util.get_logicaldisks(): - if not _is_match_pattern(item['disk']): + if item['disk'].startswith( + "/net") or not _is_match_pattern(item['disk']): continue + mbed_pages = [ + join(item['disk'], n) for n in ("mbed.htm", "mbed.html") + ] + if any([isfile(p) for p in mbed_pages]): + return item['disk'] if (item['name'] and any([l in item['name'].lower() for l in msdlabels])): return item['disk'] - if isfile(join(item['disk'], "mbed.html")): - return item['disk'] return None def _look_for_serial_port(): @@ -192,8 +201,8 @@ def CheckUploadSize(_, target, source, env): # pylint: disable=W0613,W0621 if used_size > max_size: sys.stderr.write("Error: The program size (%d bytes) is greater " - "than maximum allowed (%s bytes)\n" % - (used_size, max_size)) + "than maximum allowed (%s bytes)\n" % (used_size, + max_size)) env.Exit(1) diff --git a/platformio/builder/tools/piowinhooks.py b/platformio/builder/tools/piowinhooks.py index c1b0895a..5ac19f5d 100644 --- a/platformio/builder/tools/piowinhooks.py +++ b/platformio/builder/tools/piowinhooks.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index e23d78d0..fffb8e40 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ from SCons.Util import case_sensitive_suffixes, is_Sequence from platformio.util import glob_escape, pioversion_to_intstr -SRC_BUILD_EXT = ["c", "cpp", "S", "spp", "SPP", "sx", "s", "asm", "ASM"] +SRC_BUILD_EXT = ["c", "cc", "cpp", "S", "spp", "SPP", "sx", "s", "asm", "ASM"] SRC_HEADER_EXT = ["h", "hpp"] SRC_FILTER_DEFAULT = ["+<*>", "-<.git%s>" % sep, "-" % sep] @@ -35,9 +35,10 @@ SRC_FILTER_DEFAULT = ["+<*>", "-<.git%s>" % sep, "-" % sep] def BuildProgram(env): def _append_pio_macros(): - env.AppendUnique(CPPDEFINES=[( - "PLATFORMIO", - int("{0:02d}{1:02d}{2:02d}".format(*pioversion_to_intstr())))]) + env.AppendUnique(CPPDEFINES=[ + ("PLATFORMIO", + int("{0:02d}{1:02d}{2:02d}".format(*pioversion_to_intstr()))) + ]) _append_pio_macros() @@ -45,6 +46,9 @@ def BuildProgram(env): if not case_sensitive_suffixes(".s", ".S"): env.Replace(AS="$CC", ASCOM="$ASPPCOM") + if "__debug" in COMMAND_LINE_TARGETS: + env.ProcessDebug() + # process extra flags from board if "BOARD" in env and "build.extra_flags" in env.BoardConfig(): env.ProcessFlags(env.BoardConfig().get("build.extra_flags")) @@ -183,7 +187,7 @@ def MatchSourceFiles(env, src_dir, src_filter=None): src_dir = env.subst(src_dir) src_filter = src_filter or SRC_FILTER_DEFAULT - if isinstance(src_filter, list) or isinstance(src_filter, tuple): + if isinstance(src_filter, (list, tuple)): src_filter = " ".join(src_filter) matches = set() diff --git a/platformio/commands/__init__.py b/platformio/commands/__init__.py index 95899c71..b0514903 100644 --- a/platformio/commands/__init__.py +++ b/platformio/commands/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/account.py b/platformio/commands/account.py index 6c48539a..d728a558 100644 --- a/platformio/commands/account.py +++ b/platformio/commands/account.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -45,12 +45,16 @@ def account_logout(): @cli.command("password", short_help="Change password") -def account_password(): +@click.option("--old-password") +@click.option("--new-password") +def account_password(**kwargs): pioplus_call(sys.argv[1:]) @cli.command("token", short_help="Get or regenerate Authentication Token") +@click.option("-p", "--password") @click.option("--regenerate", is_flag=True) +@click.option("--json-output", is_flag=True) def account_token(**kwargs): pioplus_call(sys.argv[1:]) @@ -61,7 +65,8 @@ def account_forgot(**kwargs): pioplus_call(sys.argv[1:]) -@cli.command("show", short_help="PIO Account information: groups, permissions") +@cli.command("show", short_help="PIO Account information") +@click.option("--offline", is_flag=True) @click.option("--json-output", is_flag=True) def account_show(**kwargs): pioplus_call(sys.argv[1:]) diff --git a/platformio/commands/boards.py b/platformio/commands/boards.py index 5f5921c9..0d9d6015 100644 --- a/platformio/commands/boards.py +++ b/platformio/commands/boards.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index 82784eb4..0db1daa9 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/debug.py b/platformio/commands/debug.py new file mode 100644 index 00000000..e43aeed1 --- /dev/null +++ b/platformio/commands/debug.py @@ -0,0 +1,42 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +from os import getcwd + +import click + +from platformio.managers.core import pioplus_call + + +@click.command( + "debug", + context_settings=dict(ignore_unknown_options=True), + short_help="PIO Unified Debugger") +@click.option( + "-d", + "--project-dir", + default=getcwd, + type=click.Path( + exists=True, + file_okay=False, + dir_okay=True, + writable=True, + resolve_path=True)) +@click.option("--environment", "-e", metavar="") +@click.option("--verbose", "-v", is_flag=True) +@click.option("--interface", type=click.Choice(["gdb"])) +@click.argument("__unprocessed", nargs=-1, type=click.UNPROCESSED) +def cli(*args, **kwargs): # pylint: disable=unused-argument + pioplus_call(sys.argv[1:]) diff --git a/platformio/commands/device.py b/platformio/commands/device.py index cba2054c..201ae474 100644 --- a/platformio/commands/device.py +++ b/platformio/commands/device.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,12 +14,12 @@ import json import sys +from os import getcwd import click from serial.tools import miniterm -from platformio.exception import MinitermException -from platformio.util import get_serialports +from platformio import exception, util @click.group(short_help="Monitor device or list existing") @@ -32,10 +32,10 @@ def cli(): def device_list(json_output): if json_output: - click.echo(json.dumps(get_serialports())) + click.echo(json.dumps(util.get_serialports())) return - for item in get_serialports(): + for item in util.get_serialports(): click.secho(item['port'], fg="cyan") click.echo("-" * len(item['port'])) click.echo("Hardware ID: %s" % item['hwid']) @@ -45,8 +45,7 @@ def device_list(json_output): @cli.command("monitor", short_help="Monitor device (Serial)") @click.option("--port", "-p", help="Port, a number or a device name") -@click.option( - "--baud", "-b", type=int, default=9600, help="Set baud rate, default=9600") +@click.option("--baud", "-b", type=int, help="Set baud rate, default=9600") @click.option( "--parity", default="N", @@ -98,15 +97,39 @@ def device_list(json_output): "--quiet", is_flag=True, help="Diagnostics: suppress non-error messages, default=Off") -def device_monitor(**kwargs): +@click.option( + "-d", + "--project-dir", + default=getcwd, + type=click.Path( + exists=True, file_okay=False, dir_okay=True, resolve_path=True)) +@click.option( + "-e", + "--environment", + help="Load configuration from `platformio.ini` and specified environment") +def device_monitor(**kwargs): # pylint: disable=too-many-branches + try: + project_options = get_project_options(kwargs['project_dir'], + kwargs['environment']) + monitor_options = {k: v for k, v in project_options or []} + if monitor_options: + for k in ("port", "baud", "rts", "dtr"): + k2 = "monitor_%s" % k + if kwargs[k] is None and k2 in monitor_options: + kwargs[k] = monitor_options[k2] + if k != "port": + kwargs[k] = int(kwargs[k]) + except exception.NotPlatformIOProject: + pass + if not kwargs['port']: - ports = get_serialports(filter_hwid=True) + ports = util.get_serialports(filter_hwid=True) if len(ports) == 1: kwargs['port'] = ports[0]['port'] sys.argv = ["monitor"] for k, v in kwargs.iteritems(): - if k in ("port", "baud", "rts", "dtr"): + if k in ("port", "baud", "rts", "dtr", "environment", "project_dir"): continue k = "--" + k.replace("_", "-") if isinstance(v, bool): @@ -121,8 +144,31 @@ def device_monitor(**kwargs): try: miniterm.main( default_port=kwargs['port'], - default_baudrate=kwargs['baud'], + default_baudrate=kwargs['baud'] or 9600, default_rts=kwargs['rts'], default_dtr=kwargs['dtr']) except Exception as e: - raise MinitermException(e) + raise exception.MinitermException(e) + + +def get_project_options(project_dir, environment): + config = util.load_project_config(project_dir) + if not config.sections(): + return + + known_envs = [s[4:] for s in config.sections() if s.startswith("env:")] + if environment: + if environment in known_envs: + return config.items("env:%s" % environment) + raise exception.UnknownEnvNames(environment, ", ".join(known_envs)) + + if not known_envs: + return + + if config.has_option("platformio", "env_default"): + env_default = config.get("platformio", + "env_default").split(", ")[0].strip() + if env_default and env_default in known_envs: + return config.items("env:%s" % env_default) + + return config.items("env:%s" % known_envs[0]) diff --git a/platformio/commands/init.py b/platformio/commands/init.py index fb303641..564010a1 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -84,8 +84,8 @@ def cli( click.style(project_dir, fg="cyan")) click.echo("%s - Project Configuration File" % click.style( "platformio.ini", fg="cyan")) - click.echo("%s - Put your source files here" % click.style( - "src", 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.style("lib", fg="cyan")) @@ -96,21 +96,10 @@ def cli( ide is not None) if ide: - if not board: - board = get_first_board(project_dir) - if board: - board = [board] - if not board: + env_name = get_best_envname(project_dir, board) + if not env_name: raise exception.BoardNotDefined() - if len(board) > 1: - click.secho( - "Warning! You have initialised project with more than 1 board" - " for the specified IDE.\n" - "However, the IDE features (code autocompletion, syntax " - "linter) have been configured for the first board '%s' from " - "your list '%s'." % (board[0], ", ".join(board)), - fg="yellow") - pg = ProjectGenerator(project_dir, ide, board[0]) + pg = ProjectGenerator(project_dir, ide, env_name) pg.generate() if not silent: @@ -126,13 +115,20 @@ def cli( fg="green") -def get_first_board(project_dir): +def get_best_envname(project_dir, boards=None): config = util.load_project_config(project_dir) + env_default = None + if config.has_option("platformio", "env_default"): + env_default = config.get("platformio", + "env_default").split(", ")[0].strip() + if env_default: + return env_default for section in config.sections(): if not section.startswith("env:"): continue - elif config.has_option(section, "board"): - return config.get(section, "board") + elif config.has_option(section, "board") and (not boards or config.get( + section, "board") in boards): + return section[4:] return None @@ -301,7 +297,8 @@ def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix, config = util.load_project_config(project_dir) for section in config.sections(): cond = [ - section.startswith("env:"), config.has_option(section, "board") + section.startswith("env:"), + config.has_option(section, "board") ] if all(cond): used_boards.append(config.get(section, "board")) diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index 068c96b5..5a4c9fbc 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -295,14 +295,14 @@ def lib_builtin(storage, json_output): if json_output: return click.echo(json.dumps(items)) - for storage in items: - if not storage['items']: + for storage_ in items: + if not storage_['items']: continue - click.secho(storage['name'], fg="green") - click.echo("*" * len(storage['name'])) + click.secho(storage_['name'], fg="green") + click.echo("*" * len(storage_['name'])) click.echo() - for item in sorted(storage['items'], key=lambda i: i['name']): + for item in sorted(storage_['items'], key=lambda i: i['name']): print_lib_item(item) @@ -366,8 +366,9 @@ def lib_show(library, json_output): for v in lib['versions'] ])) blocks.append(("Unique Downloads", [ - "Today: %s" % lib['dlstats']['day'], "Week: %s" % - lib['dlstats']['week'], "Month: %s" % lib['dlstats']['month'] + "Today: %s" % lib['dlstats']['day'], + "Week: %s" % lib['dlstats']['week'], + "Month: %s" % lib['dlstats']['month'] ])) for (title, rows) in blocks: @@ -418,16 +419,16 @@ def lib_stats(json_output): click.echo("-" * terminal_width) def _print_lib_item(item): - click.echo(( - printitemdate_tpl if "date" in item else printitem_tpl - ).format( - name=click.style(item['name'], fg="cyan"), - date=str( - arrow.get(item['date']).humanize() if "date" in item else ""), - url=click.style( - "http://platformio.org/lib/show/%s/%s" % (item['id'], - quote(item['name'])), - fg="blue"))) + click.echo((printitemdate_tpl + if "date" in item else printitem_tpl).format( + name=click.style(item['name'], fg="cyan"), + date=str( + arrow.get(item['date']).humanize() + if "date" in item else ""), + url=click.style( + "http://platformio.org/lib/show/%s/%s" % + (item['id'], quote(item['name'])), + fg="blue"))) def _print_tag_item(name): click.echo( @@ -457,8 +458,8 @@ def lib_stats(json_output): _print_tag_item(item) click.echo() - for key, title in (("dlday", "Today"), ("dlweek", "Week"), - ("dlmonth", "Month")): + for key, title in (("dlday", "Today"), ("dlweek", "Week"), ("dlmonth", + "Month")): _print_title("Featured: " + title) _print_header(with_date=False) for item in result.get(key, []): diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index 70ac4b39..9699a4d7 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -81,7 +81,7 @@ def _get_installed_platform_data(platform, name=p.name, title=p.title, description=p.description, - version=p.version, # comment before dump + version=p.version, homepage=p.homepage, repository=p.repository_url, url=p.vendor_url, @@ -202,6 +202,7 @@ def platform_frameworks(query, json_output): ] frameworks.append(framework) + frameworks = sorted(frameworks, key=lambda manifest: manifest['name']) if json_output: click.echo(json.dumps(frameworks)) else: @@ -219,6 +220,8 @@ def platform_list(json_output): manifest['__pkg_dir'], with_boards=False, expose_packages=False)) + + platforms = sorted(platforms, key=lambda manifest: manifest['name']) if json_output: click.echo(json.dumps(platforms)) else: @@ -269,8 +272,8 @@ def platform_show(platform, json_output): # pylint: disable=too-many-branches if item['type']: click.echo("Type: %s" % item['type']) click.echo("Requirements: %s" % item['requirements']) - click.echo("Installed: %s" % ("Yes" if item.get("version") else - "No (optional)")) + click.echo("Installed: %s" % + ("Yes" if item.get("version") else "No (optional)")) if "version" in item: click.echo("Version: %s" % item['version']) if "originalVersion" in item: diff --git a/platformio/commands/remote.py b/platformio/commands/remote.py index 1945bf87..9b7ad5fb 100644 --- a/platformio/commands/remote.py +++ b/platformio/commands/remote.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 36e56ff6..fdd9cefe 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ from time import time import click from platformio import __version__, exception, telemetry, util +from platformio.commands.device import device_monitor as cmd_device_monitor from platformio.commands.lib import lib_install as cmd_lib_install from platformio.commands.lib import get_builtin_libs from platformio.commands.platform import \ @@ -78,7 +79,7 @@ def cli(ctx, environment, target, upload_port, project_dir, silent, verbose, if config.has_option("platformio", "env_default"): env_default = [ e.strip() - for e in config.get("platformio", "env_default").split(",") + for e in config.get("platformio", "env_default").split(", ") ] results = [] @@ -107,7 +108,11 @@ def cli(ctx, environment, target, upload_port, project_dir, silent, verbose, ep = EnvironmentProcessor(ctx, envname, options, target, upload_port, silent, verbose) - results.append((envname, ep.process())) + result = (envname, ep.process()) + results.append(result) + if result[1] and "monitor" in ep.get_build_targets() and \ + "nobuild" not in ep.get_build_targets(): + ctx.invoke(cmd_device_monitor) found_error = any([status is False for (_, status) in results]) @@ -122,14 +127,23 @@ def cli(ctx, environment, target, upload_port, project_dir, silent, verbose, class EnvironmentProcessor(object): - KNOWN_OPTIONS = ( - "platform", "framework", "board", "board_mcu", "board_f_cpu", - "board_f_flash", "board_flash_mode", "build_flags", "src_build_flags", - "build_unflags", "src_filter", "extra_script", "targets", - "upload_port", "upload_protocol", "upload_speed", "upload_flags", - "upload_resetmethod", "lib_install", "lib_deps", "lib_force", - "lib_ignore", "lib_extra_dirs", "lib_ldf_mode", "lib_compat_mode", - "test_ignore", "test_port", "piotest") + KNOWN_OPTIONS = ("platform", "framework", "board", "board_mcu", + "board_f_cpu", "board_f_flash", "board_flash_mode", + "build_flags", "src_build_flags", "build_unflags", + "src_filter", "extra_script", "targets", "upload_port", + "upload_protocol", "upload_speed", "upload_flags", + "upload_resetmethod", "lib_deps", "lib_ignore", + "lib_extra_dirs", "lib_ldf_mode", "lib_compat_mode", + "piotest", "test_transport", "test_ignore", "test_port", + "debug_tool", "debug_port", "debug_init_cmds", + "debug_extra_cmds", "debug_server", "debug_init_break", + "debug_load_cmd") + + IGNORE_BUILD_OPTIONS = ("test_transport", "test_filter", "test_ignore", + "test_port", "debug_tool", "debug_port", + "debug_init_cmds", "debug_extra_cmds", + "debug_server", "debug_init_break", + "debug_load_cmd") REMAPED_OPTIONS = {"framework": "pioframework", "platform": "pioplatform"} @@ -158,16 +172,17 @@ class EnvironmentProcessor(object): terminal_width, _ = click.get_terminal_size() start_time = time() - # multi-line values to one line for k, v in self.options.items(): - if "\n" in v: - self.options[k] = self.options[k].strip().replace("\n", ", ") + self.options[k] = self.options[k].strip() if not self.silent: - click.echo("[%s] Processing %s (%s)" % ( - datetime.now().strftime("%c"), click.style( - self.name, fg="cyan", bold=True), ", ".join( - ["%s: %s" % (k, v) for k, v in self.options.items()]))) + click.echo("[%s] Processing %s (%s)" % + (datetime.now().strftime("%c"), + click.style(self.name, fg="cyan", bold=True), + "; ".join([ + "%s: %s" % (k, v.replace("\n", ", ")) + for k, v in self.options.items() + ]))) click.secho("-" * terminal_width, bold=True) self.options = self._validate_options(self.options) @@ -179,10 +194,10 @@ class EnvironmentProcessor(object): if is_error or "piotest_processor" not in self.cmd_ctx.meta: print_header( - "[%s] Took %.2f seconds" % ((click.style( - "ERROR", fg="red", bold=True) if is_error else click.style( - "SUCCESS", fg="green", bold=True)), - time() - start_time), + "[%s] Took %.2f seconds" % + ((click.style("ERROR", fg="red", bold=True) + if is_error else click.style( + "SUCCESS", fg="green", bold=True)), time() - start_time), is_error=is_error) return not is_error @@ -210,41 +225,46 @@ class EnvironmentProcessor(object): # warn about unknown options if k not in self.KNOWN_OPTIONS: click.secho( - "Detected non-PlatformIO `%s` option in `[env:]` section" % - k, + "Detected non-PlatformIO `%s` option in `[env:%s]` section" + % (k, self.name), fg="yellow") result[k] = v return result - def _get_build_variables(self): + def get_build_variables(self): variables = {"pioenv": self.name} if self.upload_port: variables['upload_port'] = self.upload_port for k, v in self.options.items(): if k in self.REMAPED_OPTIONS: k = self.REMAPED_OPTIONS[k] + if k in self.IGNORE_BUILD_OPTIONS: + continue if k == "targets" or (k == "upload_port" and self.upload_port): continue variables[k] = v return variables - def _get_build_targets(self): + def get_build_targets(self): targets = [] if self.targets: targets = [t for t in self.targets] elif "targets" in self.options: - targets = self.options['targets'].split() + targets = self.options['targets'].split(", ") return targets def _run(self): if "platform" not in self.options: raise exception.UndefinedEnvPlatform(self.name) - build_vars = self._get_build_variables() - build_targets = self._get_build_targets() + build_vars = self.get_build_variables() + build_targets = self.get_build_targets() telemetry.on_run_environment(self.options, build_targets) + # skip monitor target, we call it above + if "monitor" in build_targets: + build_targets.remove("monitor") if "nobuild" not in build_targets: # install dependent libraries if "lib_install" in self.options: @@ -255,7 +275,9 @@ class EnvironmentProcessor(object): ], self.verbose) if "lib_deps" in self.options: _autoinstall_libdeps(self.cmd_ctx, [ - d.strip() for d in self.options['lib_deps'].split(", ") + d.strip() + for d in self.options['lib_deps'].split( + "\n" if "\n" in self.options['lib_deps'] else ", ") if d.strip() ], self.verbose) @@ -346,17 +368,19 @@ def print_summary(results, start_time): err=status is False) print_header( - "[%s] Took %.2f seconds" % ((click.style( - "SUCCESS", fg="green", bold=True) if successed else click.style( - "ERROR", fg="red", bold=True)), time() - start_time), + "[%s] Took %.2f seconds" % + ((click.style("SUCCESS", fg="green", bold=True) + if successed else click.style("ERROR", fg="red", bold=True)), + time() - start_time), is_error=not successed) def check_project_defopts(config): if not config.has_section("platformio"): return True - known = ("home_dir", "lib_dir", "libdeps_dir", "src_dir", "envs_dir", - "data_dir", "test_dir", "env_default", "lib_extra_dirs") + known = ("env_default", "home_dir", "lib_dir", "libdeps_dir", "src_dir", + "envs_dir", "data_dir", "test_dir", "boards_dir", + "lib_extra_dirs") unknown = set([k for k, _ in config.items("platformio")]) - set(known) if not unknown: return True diff --git a/platformio/commands/settings.py b/platformio/commands/settings.py index 08649221..a29d3997 100644 --- a/platformio/commands/settings.py +++ b/platformio/commands/settings.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/test.py b/platformio/commands/test.py index 34b30ec9..4c6414c9 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -22,7 +22,18 @@ from platformio.managers.core import pioplus_call @click.command("test", short_help="Local Unit Testing") @click.option("--environment", "-e", multiple=True, metavar="") -@click.option("--ignore", "-i", multiple=True, metavar="") +@click.option( + "--filter", + "-f", + multiple=True, + metavar="", + help="Filter tests by a pattern") +@click.option( + "--ignore", + "-i", + multiple=True, + metavar="", + help="Ignore tests by a pattern") @click.option("--upload-port") @click.option("--test-port") @click.option( diff --git a/platformio/commands/update.py b/platformio/commands/update.py index 41d0185d..65c44fac 100644 --- a/platformio/commands/update.py +++ b/platformio/commands/update.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/upgrade.py b/platformio/commands/upgrade.py index cc735393..a23c695a 100644 --- a/platformio/commands/upgrade.py +++ b/platformio/commands/upgrade.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/downloader.py b/platformio/downloader.py index 356413c2..986d3283 100644 --- a/platformio/downloader.py +++ b/platformio/downloader.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -38,8 +38,9 @@ class FileDownloader(object): disposition = self._request.headers.get("content-disposition") if disposition and "filename=" in disposition: - self._fname = disposition[disposition.index("filename=") + - 9:].replace('"', "").replace("'", "") + self._fname = disposition[ + disposition.index("filename=") + 9:].replace('"', "").replace( + "'", "") self._fname = self._fname.encode("utf8") else: self._fname = url.split("/")[-1] diff --git a/platformio/exception.py b/platformio/exception.py index 0f0530b6..8743e784 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,8 +20,7 @@ class PlatformioException(Exception): def __str__(self): # pragma: no cover if self.MESSAGE: return self.MESSAGE.format(*self.args) - else: - return Exception.__str__(self) + return Exception.__str__(self) class ReturnErrorCode(PlatformioException): diff --git a/platformio/ide/__init__.py b/platformio/ide/__init__.py index 95899c71..b0514903 100644 --- a/platformio/ide/__init__.py +++ b/platformio/ide/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/ide/projectgenerator.py b/platformio/ide/projectgenerator.py index e1efa469..c12d4731 100644 --- a/platformio/ide/projectgenerator.py +++ b/platformio/ide/projectgenerator.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,19 +15,22 @@ import json import os import re +from cStringIO import StringIO from os.path import abspath, basename, expanduser, isdir, isfile, join, relpath import bottle +import click -from platformio import app, exception, util +from platformio import exception, util +from platformio.commands.run import cli as cmd_run class ProjectGenerator(object): - def __init__(self, project_dir, ide, board): + def __init__(self, project_dir, ide, env_name): self.project_dir = project_dir self.ide = ide - self.board = board + self.env_name = env_name self._tplvars = {} with util.cd(self.project_dir): @@ -43,36 +46,38 @@ class ProjectGenerator(object): @util.memoized def get_project_env(self): - data = {"env_name": "PlatformIO"} + data = None config = util.load_project_config(self.project_dir) for section in config.sections(): if not section.startswith("env:"): continue + if self.env_name != section[4:]: + continue data = {"env_name": section[4:]} for k, v in config.items(section): data[k] = v - if self.board == data.get("board"): - break return data @util.memoized def get_project_build_data(self): data = {"defines": [], "includes": [], "cxx_path": None} envdata = self.get_project_env() - if "env_name" not in envdata: + if not envdata: return data - cmd = [util.get_pythonexe_path(), "-m", "platformio", "-f"] - if app.get_session_var("caller_id"): - cmd.extend(["-c", app.get_session_var("caller_id")]) - cmd.extend(["run", "-t", "idedata", "-e", envdata['env_name']]) - cmd.extend(["-d", self.project_dir]) - result = util.exec_command(cmd) - if result['returncode'] != 0 or '"includes":' not in result['out']: - raise exception.PlatformioException( - "\n".join([result['out'], result['err']])) + out = StringIO() + with util.capture_stdout(out): + click.get_current_context().invoke( + cmd_run, + project_dir=self.project_dir, + environment=[envdata['env_name']], + target=["idedata"]) + result = out.getvalue() - for line in result['out'].split("\n"): + if '"includes":' not in result: + raise exception.PlatformioException(result) + + for line in result.split("\n"): line = line.strip() if line.startswith('{"') and line.endswith("}"): data = json.loads(line) @@ -146,16 +151,24 @@ class ProjectGenerator(object): self._tplvars.update(self.get_project_env()) self._tplvars.update(self.get_project_build_data()) self._tplvars.update({ - "project_name": self.get_project_name(), - "src_files": self.get_src_files(), - "user_home_dir": abspath(expanduser("~")), - "project_dir": self.project_dir, - "project_src_dir": self.project_src_dir, - "systype": util.get_systype(), + "project_name": + self.get_project_name(), + "src_files": + self.get_src_files(), + "user_home_dir": + abspath(expanduser("~")), + "project_dir": + self.project_dir, + "project_src_dir": + self.project_src_dir, + "systype": + util.get_systype(), "platformio_path": self._fix_os_path(util.where_is_program("platformio")), - "env_pathsep": os.pathsep, - "env_path": self._fix_os_path(os.getenv("PATH")) + "env_pathsep": + os.pathsep, + "env_path": + self._fix_os_path(os.getenv("PATH")) }) @staticmethod diff --git a/platformio/ide/tpls/eclipse/.settings/PlatformIO Debugger.launch.tpl b/platformio/ide/tpls/eclipse/.settings/PlatformIO Debugger.launch.tpl new file mode 100644 index 00000000..e27a3061 --- /dev/null +++ b/platformio/ide/tpls/eclipse/.settings/PlatformIO Debugger.launch.tpl @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platformio/ide/tpls/sublimetext/platformio.sublime-project.tpl b/platformio/ide/tpls/sublimetext/platformio.sublime-project.tpl index f189887b..bf27d97c 100644 --- a/platformio/ide/tpls/sublimetext/platformio.sublime-project.tpl +++ b/platformio/ide/tpls/sublimetext/platformio.sublime-project.tpl @@ -93,5 +93,12 @@ { "path": "." } - ] + ], + "settings": + { + "sublimegdb_workingdir": "{{project_dir}}", + "sublimegdb_exec_cmd": "-exec-continue", + "sublimegdb_commandline": "{{platformio_path}} -f -c sublimetext debug --interface=gdb --interpreter=mi -x .pioinit" + + } } diff --git a/platformio/ide/tpls/vim/.clang_complete.tpl b/platformio/ide/tpls/vim/.clang_complete.tpl new file mode 100644 index 00000000..bc09ec0d --- /dev/null +++ b/platformio/ide/tpls/vim/.clang_complete.tpl @@ -0,0 +1,6 @@ +% for include in includes: +-I{{include}} +% end +% for define in defines: +-D{{!define}} +% end \ No newline at end of file diff --git a/platformio/ide/tpls/vim/.gcc-flags.json.tpl b/platformio/ide/tpls/vim/.gcc-flags.json.tpl new file mode 100644 index 00000000..5af2ea3a --- /dev/null +++ b/platformio/ide/tpls/vim/.gcc-flags.json.tpl @@ -0,0 +1,8 @@ +{ + "execPath": "{{ cxx_path.replace("\\", "/") }}", + "gccDefaultCFlags": "-fsyntax-only {{! cc_flags.replace(' -MMD ', ' ').replace('"', '\\"') }}", + "gccDefaultCppFlags": "-fsyntax-only {{! cxx_flags.replace(' -MMD ', ' ').replace('"', '\\"') }}", + "gccErrorLimit": 15, + "gccIncludePaths": "{{ ','.join(includes).replace("\\", "/") }}", + "gccSuppressWarnings": false +} diff --git a/platformio/ide/tpls/vim/.gitignore.tpl b/platformio/ide/tpls/vim/.gitignore.tpl new file mode 100644 index 00000000..5dac9f52 --- /dev/null +++ b/platformio/ide/tpls/vim/.gitignore.tpl @@ -0,0 +1,4 @@ +.pioenvs +.piolibdeps +.clang_complete +.gcc-flags.json diff --git a/platformio/ide/tpls/vscode/.gitignore.tpl b/platformio/ide/tpls/vscode/.gitignore.tpl new file mode 100644 index 00000000..08e91a14 --- /dev/null +++ b/platformio/ide/tpls/vscode/.gitignore.tpl @@ -0,0 +1,3 @@ +.pioenvs +.piolibdeps +.vscode diff --git a/platformio/ide/tpls/vscode/.vscode/c_cpp_properties.json.tpl b/platformio/ide/tpls/vscode/.vscode/c_cpp_properties.json.tpl new file mode 100644 index 00000000..5fea5091 --- /dev/null +++ b/platformio/ide/tpls/vscode/.vscode/c_cpp_properties.json.tpl @@ -0,0 +1,37 @@ +{ + "configurations": [ + { +% import platform +% systype = platform.system().lower() +% if systype == "windows": + "name": "Win32", +% elif systype == "darwin": + "name": "Mac", +% else: + "name": "Linux", +% end + "includePath": [ +% for include in includes: + "{{include.replace('\\\\', '/').replace('\\', '/').replace('"', '\\"')}}", +% end + "" + ], + "browse": { + "limitSymbolsToIncludedHeaders": true, + "databaseFilename": "", + "path": [ +% for include in includes: + "{{include.replace('\\\\', '/').replace('\\', '/').replace('"', '\\"')}}", +% end + "" + ] + }, + "defines": [ +% for define in defines: + "{{!define.replace('"', '\\"')}}", +% end + "" + ] + } + ] +} \ No newline at end of file diff --git a/platformio/ide/tpls/vscode/.vscode/launch.json.tpl b/platformio/ide/tpls/vscode/.vscode/launch.json.tpl new file mode 100644 index 00000000..409c1b98 --- /dev/null +++ b/platformio/ide/tpls/vscode/.vscode/launch.json.tpl @@ -0,0 +1,15 @@ +% from os.path import dirname, join +{ + "version": "0.2.0", + "configurations": [ + { + "type": "gdb", + "request": "launch", + "cwd": "${workspaceRoot}", + "name": "PlatformIO Debugger", + "target": "{{prog_path.replace('\\\\', '/').replace('\\', '/').replace('"', '\\"')}}", + "gdbpath": "{{join(dirname(platformio_path), "piodebuggdb").replace('\\\\', '/').replace('\\', '/').replace('"', '\\"')}}", + "autorun": [ "source .pioinit" ] + } + ] +} \ No newline at end of file diff --git a/platformio/ide/tpls/vscode/.vscode/tasks.json.tpl b/platformio/ide/tpls/vscode/.vscode/tasks.json.tpl new file mode 100644 index 00000000..870cb566 --- /dev/null +++ b/platformio/ide/tpls/vscode/.vscode/tasks.json.tpl @@ -0,0 +1,121 @@ +{ + "version": "0.1.0", + "runner": "terminal", + "command": "{{platformio_path}}", + "isShellCommand": false, + "args": ["-c", "vscode"], + "showOutput": "always", + "echoCommand": false, + "suppressTaskName": true, + "tasks": [ + { + "taskName": "PlatformIO: Build", + "isBuildCommand": true, + "args": ["run"], + "problemMatcher": { + "owner": "cpp", + "fileLocation": ["relative", "${workspaceRoot}"], + "pattern": { + "regexp": "^([^:\\n]+):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + }, + { + "taskName": "PlatformIO: Clean", + "args": ["run", "-t", "clean"] + }, + { + "taskName": "PlatformIO: Upload", + "args": ["run", "-t", "upload"], + "problemMatcher": { + "owner": "cpp", + "fileLocation": ["relative", "${workspaceRoot}"], + "pattern": { + "regexp": "^([^:\\n]+):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + }, + { + "taskName": "PlatformIO: Upload using Programmer", + "args": ["run", "-t", "program"], + "problemMatcher": { + "owner": "cpp", + "fileLocation": ["relative", "${workspaceRoot}"], + "pattern": { + "regexp": "^([^:\\n]+):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + }, + { + "taskName": "PlatformIO: Upload SPIFFS image", + "args": ["run", "-t", "uploadfs"], + "problemMatcher": { + "owner": "cpp", + "fileLocation": ["relative", "${workspaceRoot}"], + "pattern": { + "regexp": "^([^:\\n]+):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + }, + { + "taskName": "PlatformIO: Upload and Monitor", + "args": ["run", "-t", "upload", "-t", "monitor"], + "problemMatcher": { + "owner": "cpp", + "fileLocation": ["relative", "${workspaceRoot}"], + "pattern": { + "regexp": "^([^:\\n]+):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + }, + { + "taskName": "PlatformIO: Test", + "args": ["test"], + "problemMatcher": { + "owner": "cpp", + "fileLocation": ["relative", "${workspaceRoot}"], + "pattern": { + "regexp": "^([^:\\n]+):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + }, + { + "taskName": "PlatformIO: Update platforms and libraries", + "args": ["update"] + }, + { + "taskName": "PlatformIO: Upgrade PIO Core", + "args": ["upgrade"] + } + ] +} \ No newline at end of file diff --git a/platformio/maintenance.py b/platformio/maintenance.py index df811972..b51fbdf8 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -38,14 +38,19 @@ def in_silence(ctx=None): ctx = ctx or app.get_session_var("command_ctx") assert ctx ctx_args = ctx.args or [] - return (ctx_args and - (ctx.args[0] == "upgrade" or "--json-output" in ctx_args)) + conditions = [ + ctx.args[0] == "upgrade", "--json-output" in ctx_args, + "--version" in ctx_args + ] + return ctx_args and any(conditions) def on_platformio_start(ctx, force, caller): if not caller: if getenv("PLATFORMIO_CALLER"): caller = getenv("PLATFORMIO_CALLER") + elif getenv("VSCODE_PID") or getenv("VSCODE_NLS_CONFIG"): + caller = "vscode" elif util.is_container(): if getenv("C9_UID"): caller = "C9" @@ -90,20 +95,22 @@ class Upgrader(object): self.to_version = semantic_version.Version.coerce( util.pepver_to_semver(to_version)) - self._upgraders = [ - (semantic_version.Version("3.0.0-a.1"), self._upgrade_to_3_0_0), - (semantic_version.Version("3.0.0-b.11"), self._upgrade_to_3_0_0b11) - ] + self._upgraders = [(semantic_version.Version("3.0.0-a.1"), + self._upgrade_to_3_0_0), + (semantic_version.Version("3.0.0-b.11"), + self._upgrade_to_3_0_0b11), + (semantic_version.Version("3.4.0-a.9"), + self._update_dev_platforms)] def run(self, ctx): if self.from_version > self.to_version: return True result = [True] - for item in self._upgraders: - if self.from_version >= item[0] or self.to_version < item[0]: + for version, callback in self._upgraders: + if self.from_version >= version or self.to_version < version: continue - result.append(item[1](ctx)) + result.append(callback(ctx)) return all(result) @@ -144,14 +151,36 @@ class Upgrader(object): ctx.invoke(cmd_platform_uninstall, platforms=["espressif"]) return True + @staticmethod + def _update_dev_platforms(ctx): + ctx.invoke(cmd_platform_update) + return True + def after_upgrade(ctx): + terminal_width, _ = click.get_terminal_size() last_version = app.get_state_item("last_version", "0.0.0") if last_version == __version__: return if last_version == "0.0.0": app.set_state_item("last_version", __version__) + elif semantic_version.Version.coerce(util.pepver_to_semver( + last_version)) > semantic_version.Version.coerce( + util.pepver_to_semver(__version__)): + click.secho("*" * terminal_width, fg="yellow") + click.secho( + "Obsolete PIO Core v%s is used (previous was %s)" % (__version__, + last_version), + fg="yellow") + click.secho( + "Please remove multiple PIO Cores from a system:", fg="yellow") + click.secho( + "http://docs.platformio.org/page/faq.html" + "#multiple-pio-cores-in-a-system", + fg="cyan") + click.secho("*" * terminal_width, fg="yellow") + return else: click.secho("Please wait while upgrading PlatformIO...", fg="yellow") app.clean_cache() @@ -175,25 +204,26 @@ def after_upgrade(ctx): click.echo("") # PlatformIO banner - terminal_width, _ = click.get_terminal_size() click.echo("*" * terminal_width) - click.echo("If you like %s, please:" % (click.style( - "PlatformIO", fg="cyan"))) + click.echo("If you like %s, please:" % + (click.style("PlatformIO", fg="cyan"))) click.echo("- %s us on Twitter to stay up-to-date " - "on the latest project news > %s" % (click.style( - "follow", fg="cyan"), click.style( - "https://twitter.com/PlatformIO_Org", fg="cyan"))) - click.echo("- %s it on GitHub > %s" % - (click.style("star", fg="cyan"), click.style( - "https://github.com/platformio/platformio", fg="cyan"))) + "on the latest project news > %s" % + (click.style("follow", fg="cyan"), + click.style("https://twitter.com/PlatformIO_Org", fg="cyan"))) + click.echo( + "- %s it on GitHub > %s" % + (click.style("star", fg="cyan"), + click.style("https://github.com/platformio/platformio", fg="cyan"))) if not getenv("PLATFORMIO_IDE"): - click.echo("- %s PlatformIO IDE for IoT development > %s" % - (click.style("try", fg="cyan"), click.style( - "http://platformio.org/platformio-ide", fg="cyan"))) + click.echo( + "- %s PlatformIO IDE for IoT development > %s" % + (click.style("try", fg="cyan"), + click.style("http://platformio.org/platformio-ide", fg="cyan"))) if not util.is_ci(): - click.echo("- %s us with PlatformIO Plus > %s" % (click.style( - "support", fg="cyan"), click.style( - "https://pioplus.com", fg="cyan"))) + click.echo("- %s us with PlatformIO Plus > %s" % + (click.style("support", fg="cyan"), + click.style("https://pioplus.com", fg="cyan"))) click.echo("*" * terminal_width) click.echo("") @@ -256,8 +286,8 @@ def check_internal_updates(ctx, what): if manifest['name'] in outdated_items: continue conds = [ - pm.outdated(manifest['__pkg_dir']), what == "platforms" and - PlatformFactory.newPlatform( + pm.outdated(manifest['__pkg_dir']), + what == "platforms" and PlatformFactory.newPlatform( manifest['__pkg_dir']).are_outdated_packages() ] if any(conds): @@ -271,8 +301,8 @@ def check_internal_updates(ctx, what): click.echo("") click.echo("*" * terminal_width) click.secho( - "There are the new updates for %s (%s)" % - (what, ", ".join(outdated_items)), + "There are the new updates for %s (%s)" % (what, + ", ".join(outdated_items)), fg="yellow") if not app.get_setting("auto_update_" + what): diff --git a/platformio/managers/__init__.py b/platformio/managers/__init__.py index 95899c71..b0514903 100644 --- a/platformio/managers/__init__.py +++ b/platformio/managers/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/managers/core.py b/platformio/managers/core.py index c711fcc6..95c8fa4c 100644 --- a/platformio/managers/core.py +++ b/platformio/managers/core.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,12 +17,12 @@ import subprocess import sys from os.path import join -from platformio import exception, util +from platformio import __version__, exception, util from platformio.managers.package import PackageManager CORE_PACKAGES = { "pysite-pioplus": ">=0.3.0,<2", - "tool-pioplus": ">=0.6.10,<2", + "tool-pioplus": ">=0.9.0,<2", "tool-unity": "~1.20302.1", "tool-scons": "~3.20501.2" } @@ -41,6 +41,33 @@ class CorePackageManager(PackageManager): ("" if sys.version_info < (2, 7, 9) else "s") ]) + def install(self, name, requirements=None, *args, + **kwargs): # pylint: disable=arguments-differ + PackageManager.install(self, name, requirements, *args, **kwargs) + self.cleanup_packages() + return self.get_package_dir(name, requirements) + + def update(self, *args, **kwargs): # pylint: disable=arguments-differ + result = PackageManager.update(self, *args, **kwargs) + self.cleanup_packages() + return result + + def cleanup_packages(self): + self.cache_reset() + best_pkg_versions = {} + for name, requirements in CORE_PACKAGES.items(): + pkg_dir = self.get_package_dir(name, requirements) + if not pkg_dir: + continue + best_pkg_versions[name] = self.load_manifest(pkg_dir)['version'] + for manifest in self.get_installed(): + if manifest['name'] not in best_pkg_versions: + continue + if manifest['version'] != best_pkg_versions[manifest['name']]: + self.uninstall(manifest['__pkg_dir'], trigger_event=False) + self.cache_reset() + return True + def get_core_package_dir(name): assert name in CORE_PACKAGES @@ -63,6 +90,13 @@ def update_core_packages(only_check=False, silent=False): def pioplus_call(args, **kwargs): + if "windows" in util.get_systype() and sys.version_info < (2, 7, 6): + raise exception.PlatformioException( + "PlatformIO Core Plus v%s does not run under Python version %s.\n" + "Minimum supported version is 2.7.6, please upgrade Python.\n" + "Python 3 is not yet supported.\n" % (__version__, + sys.version.split()[0])) + pioplus_path = join(get_core_package_dir("tool-pioplus"), "pioplus") os.environ['PYTHONEXEPATH'] = util.get_pythonexe_path() os.environ['PYTHONPYSITEDIR'] = get_core_package_dir("pysite-pioplus") diff --git a/platformio/managers/lib.py b/platformio/managers/lib.py index 68bc1ce7..5ce9fe99 100644 --- a/platformio/managers/lib.py +++ b/platformio/managers/lib.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -64,7 +64,7 @@ class LibraryManager(BasePkgManager): if not manifest: return manifest - # if Arudino library.properties + # if Arduino library.properties if "sentence" in manifest: manifest['frameworks'] = ["arduino"] manifest['description'] = manifest['sentence'] @@ -226,9 +226,9 @@ class LibraryManager(BasePkgManager): cache_valid="30d") assert dl_data - return self._install_from_url( - name, dl_data['url'].replace("http://", "https://") - if app.get_setting("enable_ssl") else dl_data['url'], requirements) + return self._install_from_url(name, dl_data['url'].replace( + "http://", "https://") if app.get_setting("enable_ssl") else + dl_data['url'], requirements) def install( # pylint: disable=arguments-differ self, @@ -239,8 +239,8 @@ class LibraryManager(BasePkgManager): interactive=False): pkg_dir = None try: - _name, _requirements, _url = self.parse_pkg_input(name, - requirements) + _name, _requirements, _url = self.parse_pkg_input( + name, requirements) if not _url: name = "id=%d" % self.get_pkg_id_by_name( _name, @@ -309,8 +309,9 @@ class LibraryManager(BasePkgManager): if not isinstance(values, list): values = [v.strip() for v in values.split(",") if v] for value in values: - query.append('%s:"%s"' % (key[:-1] if key.endswith("s") else - key, value)) + query.append('%s:"%s"' % (key[:-1] + if key.endswith("s") else key, + value)) lib_info = None result = util.get_api_result( diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 6adb753e..c05b90f6 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ import codecs import hashlib import json import os +import re import shutil from os.path import basename, getsize, isdir, isfile, islink, join from tempfile import mkdtemp @@ -69,8 +70,7 @@ class PackageRepoIterator(object): if self.package in manifest: return manifest[self.package] - else: - return self.next() + return self.next() class PkgRepoMixin(object): @@ -192,12 +192,14 @@ class PkgInstallerMixin(object): @staticmethod def get_install_dirname(manifest): - name = manifest['name'] + name = re.sub(r"[^\da-z\_\-\. ]", "_", manifest['name'], flags=re.I) if "id" in manifest: name += "_ID%d" % manifest['id'] return name def get_src_manifest_path(self, pkg_dir): + if not isdir(pkg_dir): + return None for item in os.listdir(pkg_dir): if not isdir(join(pkg_dir, item)): continue @@ -224,20 +226,19 @@ class PkgInstallerMixin(object): if result: return result - manifest_path = self.get_manifest_path(pkg_dir) - if not manifest_path: - return None - - # if non-registry packages: VCS or archive - src_manifest_path = self.get_src_manifest_path(pkg_dir) + manifest = {} src_manifest = None + manifest_path = self.get_manifest_path(pkg_dir) + src_manifest_path = self.get_src_manifest_path(pkg_dir) if src_manifest_path: src_manifest = util.load_json(src_manifest_path) - manifest = {} - if manifest_path.endswith(".json"): + if not manifest_path and not src_manifest_path: + return None + + if manifest_path and manifest_path.endswith(".json"): manifest = util.load_json(manifest_path) - elif manifest_path.endswith(".properties"): + elif manifest_path and manifest_path.endswith(".properties"): with codecs.open(manifest_path, encoding="utf-8") as fp: for line in fp.readlines(): if "=" not in line: @@ -305,7 +306,8 @@ class PkgInstallerMixin(object): def get_package_dir(self, name, requirements=None, url=None): manifest = self.get_package(name, requirements, url) - return manifest.get("__pkg_dir") if manifest else None + return manifest.get("__pkg_dir") if manifest and isdir( + manifest.get("__pkg_dir")) else None def find_pkg_root(self, src_dir): if self.manifest_exists(src_dir): @@ -345,7 +347,6 @@ class PkgInstallerMixin(object): requirements=None, sha1=None, track=False): - pkg_dir = None tmp_dir = mkdtemp("-package", "_tmp_installing-", self.package_dir) src_manifest_dir = None src_manifest = {"name": name, "url": url, "requirements": requirements} @@ -369,19 +370,20 @@ class PkgInstallerMixin(object): src_manifest_dir = vcs.storage_dir src_manifest['version'] = vcs.get_current_revision() - pkg_dir = self.find_pkg_root(tmp_dir) + _tmp_dir = tmp_dir + if not src_manifest_dir: + _tmp_dir = self.find_pkg_root(tmp_dir) + src_manifest_dir = join(_tmp_dir, ".pio") # write source data to a special manifest if track: - if not src_manifest_dir: - src_manifest_dir = join(pkg_dir, ".pio") self._update_src_manifest(src_manifest, src_manifest_dir) - pkg_dir = self._install_from_tmp_dir(pkg_dir, requirements) + return self._install_from_tmp_dir(_tmp_dir, requirements) finally: if isdir(tmp_dir): util.rmtree_(tmp_dir) - return pkg_dir + return def _update_src_manifest(self, data, src_dir): if not isdir(src_dir): @@ -417,8 +419,8 @@ class PkgInstallerMixin(object): # package should satisfy requirements if requirements: mismatch_error = ( - "Package version %s doesn't satisfy requirements %s" % ( - tmp_manifest['version'], requirements)) + "Package version %s doesn't satisfy requirements %s" % + (tmp_manifest['version'], requirements)) try: assert tmp_semver and tmp_semver in semantic_version.Spec( requirements), mismatch_error @@ -497,10 +499,10 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): url_marker = "://" req_conditions = [ - not requirements, "@" in text, - (url_marker != "git@" and "://git@" not in text) or - text.count("@") > 1 - ] + not requirements, + "@" in text, + not url_marker.startswith("git") + ] # yapf: disable if all(req_conditions): text, requirements = text.rsplit("@", 1) if text.isdigit(): @@ -650,18 +652,18 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): if isdir(package): pkg_dir = package else: - name, requirements, url = self.parse_pkg_input(package, - requirements) + name, requirements, url = self.parse_pkg_input( + package, requirements) pkg_dir = self.get_package_dir(name, requirements, url) if not pkg_dir: - raise exception.UnknownPackage("%s @ %s" % - (package, requirements or "*")) + raise exception.UnknownPackage("%s @ %s" % (package, + requirements or "*")) manifest = self.load_manifest(pkg_dir) click.echo( - "Uninstalling %s @ %s: \t" % (click.style( - manifest['name'], fg="cyan"), manifest['version']), + "Uninstalling %s @ %s: \t" % + (click.style(manifest['name'], fg="cyan"), manifest['version']), nl=False) if islink(pkg_dir): @@ -673,9 +675,9 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): # unfix package with the same name pkg_dir = self.get_package_dir(manifest['name']) if pkg_dir and "@" in pkg_dir: - os.rename( - pkg_dir, - join(self.package_dir, self.get_install_dirname(manifest))) + os.rename(pkg_dir, + join(self.package_dir, + self.get_install_dirname(manifest))) self.cache_reset() click.echo("[%s]" % click.style("OK", fg="green")) @@ -698,8 +700,8 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): pkg_dir = self.get_package_dir(*self.parse_pkg_input(package)) if not pkg_dir: - raise exception.UnknownPackage("%s @ %s" % - (package, requirements or "*")) + raise exception.UnknownPackage("%s @ %s" % (package, + requirements or "*")) manifest = self.load_manifest(pkg_dir) name = manifest['name'] diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 99a38d86..015d9504 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -63,7 +63,7 @@ class PlatformManager(BasePkgManager): skip_default_package=False, trigger_event=True, silent=False, - **_): # pylint: disable=too-many-arguments + **_): # pylint: disable=too-many-arguments, arguments-differ platform_dir = BasePkgManager.install( self, name, requirements, silent=silent) p = PlatformFactory.newPlatform(platform_dir) @@ -84,8 +84,8 @@ class PlatformManager(BasePkgManager): if isdir(package): pkg_dir = package else: - name, requirements, url = self.parse_pkg_input(package, - requirements) + name, requirements, url = self.parse_pkg_input( + package, requirements) pkg_dir = self.get_package_dir(name, requirements, url) p = PlatformFactory.newPlatform(pkg_dir) @@ -108,8 +108,8 @@ class PlatformManager(BasePkgManager): if isdir(package): pkg_dir = package else: - name, requirements, url = self.parse_pkg_input(package, - requirements) + name, requirements, url = self.parse_pkg_input( + package, requirements) pkg_dir = self.get_package_dir(name, requirements, url) p = PlatformFactory.newPlatform(pkg_dir) @@ -207,8 +207,8 @@ class PlatformFactory(object): else: if not requirements and "@" in name: name, requirements = name.rsplit("@", 1) - platform_dir = PlatformManager().get_package_dir(name, - requirements) + platform_dir = PlatformManager().get_package_dir( + name, requirements) if not platform_dir: raise exception.UnknownPlatform(name if not requirements else @@ -305,9 +305,7 @@ class PlatformPackagesMixin(object): version = self.packages[name].get("version", "") if self.is_valid_requirements(version): return self.pm.get_package_dir(name, version) - else: - return self.pm.get_package_dir(*self._parse_pkg_input(name, - version)) + return self.pm.get_package_dir(*self._parse_pkg_input(name, version)) def get_package_version(self, name): pkg_dir = self.get_package_dir(name) @@ -360,7 +358,8 @@ class PlatformRunMixin(object): util.get_pythonexe_path(), join(get_core_package_dir("tool-scons"), "script", "scons"), "-Q", "-j %d" % self.get_job_nums(), "--warn=no-no-parallel-support", - "-f", join(util.get_source_dir(), "builder", "main.py") + "-f", + join(util.get_source_dir(), "builder", "main.py") ] cmd.append("PIOVERBOSE=%d" % (1 if self.verbose else 0)) cmd += targets @@ -581,8 +580,10 @@ class PlatformBase( # pylint: disable=too-many-public-methods if not isdir(libcore_dir): continue storages.append({ - "name": "%s-core-%s" % (opts['package'], item), - "path": libcore_dir + "name": + "%s-core-%s" % (opts['package'], item), + "path": + libcore_dir }) return storages @@ -645,6 +646,18 @@ class PlatformBoardConfig(object): "ram": self._manifest.get("upload", {}).get("maximum_ram_size", 0), "rom": self._manifest.get("upload", {}).get("maximum_size", 0), "frameworks": self._manifest.get("frameworks"), + "debug": self.get_debug_data(), "vendor": self._manifest['vendor'], "url": self._manifest['url'] } + + def get_debug_data(self): + if not self._manifest.get("debug", {}).get("tools"): + return + tools = {} + for name, options in self._manifest['debug']['tools'].items(): + tools[name] = {} + for key, value in options.items(): + if key in ("default", "onboard"): + tools[name][key] = value + return {"tools": tools} diff --git a/platformio/telemetry.py b/platformio/telemetry.py index 8b3fd7a1..bcf39fbe 100644 --- a/platformio/telemetry.py +++ b/platformio/telemetry.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -255,8 +255,9 @@ def measure_ci(): "label": getenv("APPVEYOR_REPO_NAME") }, "CIRCLECI": { - "label": "%s/%s" % (getenv("CIRCLE_PROJECT_USERNAME"), - getenv("CIRCLE_PROJECT_REPONAME")) + "label": + "%s/%s" % (getenv("CIRCLE_PROJECT_USERNAME"), + getenv("CIRCLE_PROJECT_REPONAME")) }, "TRAVIS": { "label": getenv("TRAVIS_REPO_SLUG") @@ -278,7 +279,10 @@ def measure_ci(): def on_run_environment(options, targets): - opts = ["%s=%s" % (opt, value) for opt, value in sorted(options.items())] + opts = [ + "%s=%s" % (opt, value.replace("\n", ", ") if "\n" in value else value) + for opt, value in sorted(options.items()) + ] targets = [t.title() for t in targets or ["run"]] on_event("Env", " ".join(targets), "&".join(opts)) diff --git a/platformio/unpacker.py b/platformio/unpacker.py index 67ca78a7..036dcc4c 100644 --- a/platformio/unpacker.py +++ b/platformio/unpacker.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/util.py b/platformio/util.py index 4d345830..ce763969 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import socket import stat import subprocess import sys +from contextlib import contextmanager from glob import glob from os.path import (abspath, basename, dirname, expanduser, isdir, isfile, join, normpath, splitdrive) @@ -46,7 +47,7 @@ class ProjectConfig(ConfigParser): VARTPL_RE = re.compile(r"\$\{([^\.\}]+)\.([^\}]+)\}") - def items(self, section, **_): + def items(self, section, **_): # pylint: disable=arguments-differ items = [] for option in ConfigParser.options(self, section): items.append((option, self.get(section, option))) @@ -130,10 +131,9 @@ class memoized(object): return self.func(*args) if args in self.cache: return self.cache[args] - else: - value = self.func(*args) - self.cache[args] = value - return value + value = self.func(*args) + self.cache[args] = value + return value def __repr__(self): '''Return the function's docstring.''' @@ -161,13 +161,21 @@ def singleton(cls): return get_instance +@contextmanager +def capture_stdout(output): + stdout = sys.stdout + sys.stdout = output + yield + sys.stdout = stdout + + def load_json(file_path): try: with open(file_path, "r") as f: return json.load(f) except ValueError: - raise exception.PlatformioException("Could not load broken JSON: %s" % - file_path) + raise exception.PlatformioException( + "Could not load broken JSON: %s" % file_path) def get_systype(): @@ -212,15 +220,19 @@ def get_project_optional_dir(name, default=None): def get_home_dir(): home_dir = get_project_optional_dir("home_dir", join(expanduser("~"), ".platformio")) - + win_home_dir = None if "windows" in get_systype(): - try: - home_dir.encode("utf8") - except UnicodeDecodeError: - home_dir = splitdrive(home_dir)[0] + "\\.platformio" + win_home_dir = splitdrive(home_dir)[0] + "\\.platformio" + if isdir(win_home_dir): + home_dir = win_home_dir if not isdir(home_dir): - os.makedirs(home_dir) + try: + os.makedirs(home_dir) + except: # pylint: disable=bare-except + if win_home_dir: + os.makedirs(win_home_dir) + home_dir = win_home_dir assert isdir(home_dir) return home_dir @@ -270,8 +282,8 @@ def get_projectsrc_dir(): def get_projecttest_dir(): - return get_project_optional_dir("test_dir", - join(get_project_dir(), "test")) + return get_project_optional_dir("test_dir", join(get_project_dir(), + "test")) def get_projectboards_dir(): @@ -299,8 +311,8 @@ URL=http://docs.platformio.org/page/projectconf.html#envs-dir def get_projectdata_dir(): - return get_project_optional_dir("data_dir", - join(get_project_dir(), "data")) + return get_project_optional_dir("data_dir", join(get_project_dir(), + "data")) def load_project_config(path=None): @@ -465,14 +477,14 @@ def _get_api_result( data=data, headers=headers, auth=auth, - verify=disable_ssl_check) + verify=not disable_ssl_check) else: r = _api_request_session().get( url, params=params, headers=headers, auth=auth, - verify=disable_ssl_check) + verify=not disable_ssl_check) result = r.json() r.raise_for_status() except requests.exceptions.HTTPError as e: @@ -483,8 +495,8 @@ def _get_api_result( else: raise exception.APIRequestError(e) except ValueError: - raise exception.APIRequestError("Invalid response: %s" % - r.text.encode("utf-8")) + raise exception.APIRequestError( + "Invalid response: %s" % r.text.encode("utf-8")) finally: if r: r.close() @@ -528,14 +540,15 @@ def get_api_result(url, params=None, data=None, auth=None, cache_valid=None): def internet_on(timeout=3): - host = "8.8.8.8" - port = 53 - try: - socket.setdefaulttimeout(timeout) - socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port)) - return True - except: # pylint: disable=bare-except - return False + socket.setdefaulttimeout(timeout) + for host in ("dl.bintray.com", "dl.platformio.org"): + try: + socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, + 80)) + return True + except: # pylint: disable=bare-except + pass + return False def get_pythonexe_path(): diff --git a/platformio/vcsclient.py b/platformio/vcsclient.py index 4b43e0a5..3ef64fe1 100644 --- a/platformio/vcsclient.py +++ b/platformio/vcsclient.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -37,8 +37,8 @@ class VCSClientFactory(object): if "#" in remote_url: remote_url, tag = remote_url.rsplit("#", 1) if not type_: - raise PlatformioException("VCS: Unknown repository type %s" % - remote_url) + raise PlatformioException( + "VCS: Unknown repository type %s" % remote_url) obj = getattr(modules[__name__], "%sClient" % type_.title())( src_dir, remote_url, tag, silent) assert isinstance(obj, VCSClientBase) @@ -103,8 +103,8 @@ class VCSClientBase(object): if result['returncode'] == 0: return result['out'].strip() raise PlatformioException( - "VCS: Could not receive an output from `%s` command (%s)" % ( - args, result)) + "VCS: Could not receive an output from `%s` command (%s)" % + (args, result)) class GitClient(VCSClientBase): @@ -152,7 +152,7 @@ class GitClient(VCSClientBase): return True def update(self): - args = ["pull"] + args = ["pull", "--recurse-submodules"] return self.run_cmd(args) def get_current_revision(self): diff --git a/scripts/98-openocd-udev.rules b/scripts/98-openocd-udev.rules new file mode 100644 index 00000000..c6ff3083 --- /dev/null +++ b/scripts/98-openocd-udev.rules @@ -0,0 +1,163 @@ +# UDEV Rules for debug adapters/boards supported by OpenOCD + +# +# INSTALLATION +# + +# +# The latest version of this file may be found at: +# https://github.com/platformio/platformio-core/blob/develop/scripts/98-openocd-udev.rules +# +# This file must be placed at: +# /etc/udev/rules.d/98-openocd-udev.rules (preferred location) +# or +# /lib/udev/rules.d/98-openocd-udev.rules (req'd on some broken systems) +# +# To install, type this command in a terminal: +# sudo cp 98-openocd-udev.rules /etc/udev/rules.d/98-openocd-udev.rules +# +# Restart "udev" management tool: +# sudo service udev restart +# or +# sudo udevadm control --reload-rules +# sudo udevadm trigger +# +# Ubuntu/Debian users may need to add own “username” to the “dialout” group if +# they are not “root”, doing this issuing a +# sudo usermod -a -G dialout $USER +# sudo usermod -a -G plugdev $USER +# +# After this file is installed, physically unplug and reconnect your adapter/board. + +ACTION!="add|change", GOTO="openocd_rules_end" +SUBSYSTEM!="usb|tty|hidraw", GOTO="openocd_rules_end" + +# Please keep this list sorted by VID:PID + +# opendous and estick +ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204f", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Original FT232/FT245 VID:PID +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Original FT2232 VID:PID +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Original FT4232 VID:PID +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Original FT232H VID:PID +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# DISTORTEC JTAG-lock-pick Tiny 2 +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8220", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# TUMPA, TUMPA Lite +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a98", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a99", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# XDS100v2 +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d0", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Xverve Signalyzer Tool (DT-USB-ST), Signalyzer LITE (DT-USB-SLITE) +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca1", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# TI/Luminary Stellaris Evaluation Board FTDI (several) +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd9", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# TI/Luminary Stellaris In-Circuit Debug Interface FTDI (ICDI) Board +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcda", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# egnite Turtelizer 2 +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bdc8", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Section5 ICEbear +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c140", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Amontec JTAGkey and JTAGkey-tiny +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# TI ICDI +ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# STLink v1 +ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3744", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# STLink v2 +ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# STLink v2-1 +ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Hilscher NXHX Boards +ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Hitex STR9-comStick +ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002c", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Hitex STM32-PerformanceStick +ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Altera USB Blaster +ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6001", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Amontec JTAGkey-HiSpeed +ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# SEGGER J-Link +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0101", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0102", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0103", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0104", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0105", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0107", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0108", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1010", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1011", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1012", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1013", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1014", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1015", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1016", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1017", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1018", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Raisonance RLink +ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Debug Board for Neo1973 +ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Olimex ARM-USB-OCD +ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Olimex ARM-USB-OCD-TINY +ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0004", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Olimex ARM-JTAG-EW +ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="001e", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Olimex ARM-USB-OCD-TINY-H +ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Olimex ARM-USB-OCD-H +ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002b", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# USBprog with OpenOCD firmware +ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board +ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Marvell Sheevaplug +ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Keil Software, Inc. ULink +ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2710", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# CMSIS-DAP compatible adapters +ATTRS{product}=="*CMSIS-DAP*", MODE="660", GROUP="plugdev", TAG+="uaccess" + +LABEL="openocd_rules_end" diff --git a/scripts/99-platformio-udev.rules b/scripts/99-platformio-udev.rules index 3e8b63a0..7adfcf0c 100644 --- a/scripts/99-platformio-udev.rules +++ b/scripts/99-platformio-udev.rules @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,6 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +# +# INSTALLATION +# + # UDEV Rules for PlatformIO supported boards, http://platformio.org/boards # # The latest version of this file may be found at: @@ -31,6 +35,11 @@ # sudo udevadm control --reload-rules # sudo udevadm trigger # +# Ubuntu/Debian users may need to add own “username” to the “dialout” group if +# they are not “root”, doing this issuing a +# sudo usermod -a -G dialout $USER +# sudo usermod -a -G plugdev $USER +# # After this file is installed, physically unplug and reconnect your board. # CP210X USB UART @@ -65,6 +74,9 @@ SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374?", MODE:="066 # USBtiny SUBSYSTEMS=="usb", ATTRS{idProduct}=="0c9f", ATTRS{idVendor}=="1781", MODE="0666" +# USBasp V2.0 +SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", MODE:="0666" + # Teensy boards ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789]?", ENV{ID_MM_DEVICE_IGNORE}="1" ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789]?", ENV{MTP_NO_PROBE}="1" diff --git a/scripts/docspregen.py b/scripts/docspregen.py index e67c9e50..8b14713d 100644 --- a/scripts/docspregen.py +++ b/scripts/docspregen.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@ def is_compat_platform_and_framework(platform, framework): return False -def generate_boards(boards): +def generate_boards(boards, extend_debug=False): def _round_memory_size(size): if size == 1: @@ -48,6 +48,8 @@ def generate_boards(boards): return int(ceil(size / b) * b) assert NotImplemented() + platforms = {m['name']: m['title'] for m in PLATFORM_MANIFESTS} + lines = [] lines.append(""" @@ -56,22 +58,44 @@ def generate_boards(boards): * - ID - Name + - Platform + - Debug - Microcontroller - Frequency - Flash - RAM""") for data in sorted(boards, key=lambda item: item['id']): + debug = [":ref:`Yes `" if data['debug'] else ""] + if extend_debug and data['debug']: + debug = [] + for name, options in data['debug']['tools'].items(): + attrs = [] + if options.get("default"): + attrs.append("default") + if options.get("onboard"): + attrs.append("on-board") + tool = ":ref:`debugging_tool_%s`" % name + if attrs: + debug.append("%s (%s)" % (tool, ", ".join(attrs))) + else: + debug.append(tool) + board_ram = float(data['ram']) / 1024 lines.append(""" * - ``{id}`` - `{name} <{url}>`_ + - :ref:`{platform_title} ` + - {debug} - {mcu} - {f_cpu:d} MHz - {rom} Kb - {ram} Kb""".format( id=data['id'], name=data['name'], + platform=data['platform'], + platform_title=platforms[data['platform']], + debug=", ".join(debug), url=data['url'], mcu=data['mcu'].upper(), f_cpu=int(data['fcpu']) / 1000000, @@ -108,29 +132,29 @@ Packages .. warning:: **Linux Users**: - * Ubuntu/Debian users may need to add own "username" to the "dialout" - group if they are not "root", doing this issuing a - ``sudo usermod -a -G dialout yourusername``. - * Install "udev" rules file `99-platformio-udev.rules `_ - (an instruction is located in the file). - * Raspberry Pi users, please read this article - `Enable serial port on Raspberry Pi `__. + * Install "udev" rules file `99-platformio-udev.rules `_ + (an instruction is located inside a file). + * Raspberry Pi users, please read this article + `Enable serial port on Raspberry Pi `__. """) if platform == "teensy": lines.append(""" - **Windows Users:** Teensy programming uses only Windows built-in HID - drivers. When Teensy is programmed to act as a USB Serial device, - Windows XP, Vista, 7 and 8 require `this serial driver - `_ - is needed to access the COM port your program uses. No special driver - installation is necessary on Windows 10. + **Windows Users:** + + Teensy programming uses only Windows built-in HID + drivers. When Teensy is programmed to act as a USB Serial device, + Windows XP, Vista, 7 and 8 require `this serial driver + `_ + is needed to access the COM port your program uses. No special driver + installation is necessary on Windows 10. """) else: lines.append(""" - **Windows Users:** Please check that you have correctly installed USB - driver from board manufacturer + **Windows Users:** + Please check that you have a correctly installed USB driver from board + manufacturer """) return "\n".join(lines) @@ -141,7 +165,7 @@ def generate_platform(name): lines = [] lines.append( - """.. Copyright 2014-present PlatformIO + """.. Copyright (c) 2014-present PlatformIO 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 @@ -152,21 +176,22 @@ def generate_platform(name): See the License for the specific language governing permissions and limitations under the License. """) + p = PlatformFactory.newPlatform(name) - lines.append(".. _platform_%s:" % name) + lines.append(".. _platform_%s:" % p.name) lines.append("") - _title = "Platform ``%s``" % name - lines.append(_title) - lines.append("=" * len(_title)) - - p = PlatformFactory.newPlatform(name) + lines.append(p.title) + lines.append("=" * len(p.title)) + lines.append(":ref:`projectconf_env_platform` = ``%s``" % p.name) + lines.append("") lines.append(p.description) lines.append(""" For more detailed information please visit `vendor site <%s>`_.""" % p.vendor_url) lines.append(""" -.. contents::""") +.. contents:: Contents + :local:""") # # Packages @@ -247,7 +272,7 @@ def generate_framework(type_, data): lines = [] lines.append( - """.. Copyright 2014-present PlatformIO + """.. Copyright (c) 2014-present PlatformIO 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 @@ -262,15 +287,18 @@ def generate_framework(type_, data): lines.append(".. _framework_%s:" % type_) lines.append("") - _title = "Framework ``%s``" % type_ - lines.append(_title) - lines.append("=" * len(_title)) + lines.append(data['title']) + lines.append("=" * len(data['title'])) + lines.append(":ref:`projectconf_env_framework` = ``%s``" % type_) + lines.append("") lines.append(data['description']) lines.append(""" For more detailed information please visit `vendor site <%s>`_. """ % data['url']) - lines.append(".. contents::") + lines.append(""" +.. contents:: Contents + :local:""") lines.append(""" Platforms @@ -371,7 +399,7 @@ def update_embedded_boards(): lines = [] lines.append( - """.. Copyright 2014-present PlatformIO + """.. Copyright (c) 2014-present PlatformIO 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 @@ -394,14 +422,16 @@ Rapid Embedded Development, Continuous and IDE integration in a few steps with PlatformIO thanks to built-in project generator for the most popular embedded boards and IDE. -* You can list pre-configured boards using :ref:`cmd_boards` command or - `PlatformIO Boards Explorer `_ -* For more detailed ``board`` information please scroll tables below by - horizontal. +.. note:: + * You can list pre-configured boards by :ref:`cmd_boards` command or + `PlatformIO Boards Explorer `_ + * For more detailed ``board`` information please scroll tables below by horizontal. """) - lines.append(".. contents::") - lines.append("") + lines.append(""" +.. contents:: Vendors + :local: + """) vendors = {} for data in BOARDS: @@ -423,11 +453,88 @@ popular embedded boards and IDE. f.write("\n".join(lines)) +def update_debugging(): + vendors = {} + platforms = [] + frameworks = [] + for data in BOARDS: + if not data['debug']: + continue + platforms.append(data['platform']) + frameworks.extend(data['frameworks']) + vendor = data['vendor'] + if vendor in vendors: + vendors[vendor].append(data) + else: + vendors[vendor] = [data] + + lines = [] + # Platforms + lines.append(""".. _debugging_platforms: + +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 + lines.append(""" +Boards +------ + +.. note:: + For more detailed ``board`` information please scroll tables below by horizontal. +""") + for vendor, boards in sorted(vendors.iteritems()): + lines.append(str(vendor)) + lines.append("~" * len(vendor)) + lines.append(generate_boards(boards, extend_debug=True)) + + with open( + join(util.get_source_dir(), "..", "docs", "plus", + "debugging.rst"), "r+") as fp: + content = fp.read() + fp.seek(0) + fp.truncate() + fp.write(content[:content.index(".. _debugging_platforms:")] + + "\n".join(lines)) + + def main(): update_create_platform_doc() update_platform_docs() update_framework_docs() update_embedded_boards() + update_debugging() if __name__ == "__main__": diff --git a/scripts/fixsymlink.py b/scripts/fixsymlink.py index 44a628fd..a73a0109 100644 --- a/scripts/fixsymlink.py +++ b/scripts/fixsymlink.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/scripts/get-platformio.py b/scripts/get-platformio.py index b70c9598..d9abf5d5 100644 --- a/scripts/get-platformio.py +++ b/scripts/get-platformio.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -112,23 +112,25 @@ def install_pip(): def install_platformio(): r = None - cmd = ["-m", "pip.__main__" if sys.version_info < (2, 7, 0) else "pip"] + cmd = ["pip", "install", "-U", "platformio"] + # cmd = [ + # "pip", "install", "-U", + # "https://github.com/platformio/platformio-core/archive/develop.zip" + # ] try: - r = exec_python_cmd(cmd + ["install", "-U", "platformio"]) + r = exec_python_cmd(cmd) assert r['returncode'] == 0 except AssertionError: - r = exec_python_cmd(cmd + ["--no-cache-dir", "install", "-U", - "platformio"]) + cmd.insert(1, "--no-cache-dir") + r = exec_python_cmd(cmd) if r: print_exec_result(r) def main(): - steps = [ - ("Fixing Windows %PATH% Environment", fix_winpython_pathenv), - ("Installing Python Package Manager", install_pip), - ("Installing PlatformIO and dependencies", install_platformio) - ] + steps = [("Fixing Windows %PATH% Environment", fix_winpython_pathenv), + ("Installing Python Package Manager", install_pip), + ("Installing PlatformIO and dependencies", install_platformio)] if not IS_WINDOWS: del steps[0] @@ -157,7 +159,7 @@ Permission denied You need the `sudo` permission to install Python packages. Try $ sudo python -c "$(curl -fsSL -https://raw.githubusercontent.com/platformio/platformio/master/scripts/get-platformio.py)" +https://raw.githubusercontent.com/platformio/platformio/develop/scripts/get-platformio.py)" """) if is_error: diff --git a/setup.py b/setup.py index ae4ad614..116656cc 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ install_requires = [ "click>=5,<6", "colorama", "lockfile>=0.9.1,<0.13", - "pyserial>=3,<4", + "pyserial>=3,<4,!=3.3", "requests>=2.4.0,<3", "semantic_version>=2.5.0" ] @@ -51,6 +51,7 @@ setup( entry_points={ "console_scripts": [ "pio = platformio.__main__:main", + "piodebuggdb = platformio.__main__:debug_gdb_main", "platformio = platformio.__main__:main" ] }, @@ -67,9 +68,8 @@ setup( "Topic :: Software Development :: Compilers" ], keywords=[ - "iot", "ide", "build", "compile", "library manager", - "embedded", "ci", "continuous integration", "arduino", "mbed", - "esp8266", "framework", "ide", "ide integration", "library.json", - "make", "cmake", "makefile", "mk", "pic32", "fpga", "artik" - ] -) + "iot", "embedded", "arduino", "mbed", "esp8266", "esp32", "fpga", + "firmware", "continuous-integration", "cloud-ide", "avr", "arm", + "ide", "unit-testing", "hardware", "verilog", "microcontroller", + "debug" + ]) diff --git a/tests/commands/test_boards.py b/tests/commands/test_boards.py index 6b216146..c44ff438 100644 --- a/tests/commands/test_boards.py +++ b/tests/commands/test_boards.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/commands/test_ci.py b/tests/commands/test_ci.py index 884e9b50..9c77582b 100644 --- a/tests/commands/test_ci.py +++ b/tests/commands/test_ci.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -25,15 +25,14 @@ def test_ci_empty(clirunner): def test_ci_boards(clirunner, validate_cliresult): result = clirunner.invoke(cmd_ci, [ - join("examples", "atmelavr-and-arduino", "arduino-internal-libs", - "src", "ChatServer.ino"), "-b", "uno", "-b", "leonardo" + join("examples", "atmelavr", "arduino-internal-libs", "src", + "ChatServer.ino"), "-b", "uno", "-b", "leonardo" ]) validate_cliresult(result) def test_ci_project_conf(clirunner, validate_cliresult): - project_dir = join("examples", "atmelavr-and-arduino", - "arduino-internal-libs") + project_dir = join("examples", "atmelavr", "arduino-internal-libs") result = clirunner.invoke(cmd_ci, [ join(project_dir, "src", "ChatServer.ino"), "--project-conf", join(project_dir, "platformio.ini") @@ -43,8 +42,7 @@ def test_ci_project_conf(clirunner, validate_cliresult): def test_ci_lib_and_board(clirunner, validate_cliresult): - example_dir = join("examples", "atmelavr-and-arduino", - "arduino-external-libs") + example_dir = join("examples", "atmelavr", "arduino-external-libs") result = clirunner.invoke(cmd_ci, [ join(example_dir, "lib", "OneWire", "examples", "DS2408_Switch", "DS2408_Switch.pde"), "-l", join(example_dir, "lib", "OneWire"), diff --git a/tests/commands/test_init.py b/tests/commands/test_init.py index 3f0cb3d7..4b7c0a94 100644 --- a/tests/commands/test_init.py +++ b/tests/commands/test_init.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -73,7 +73,7 @@ def test_init_ide_atom(clirunner, validate_cliresult, tmpdir): # switch to NodeMCU result = clirunner.invoke( - cmd_init, ["--ide", "atom", "-b", "nodemcuv2", "-b", "uno"]) + cmd_init, ["--ide", "atom", "-b", "nodemcuv2"]) validate_cliresult(result) validate_pioproject(str(tmpdir)) assert "arduinoespressif" in tmpdir.join(".clang_complete").read() diff --git a/tests/commands/test_lib.py b/tests/commands/test_lib.py index d0ae5665..31ed9809 100644 --- a/tests/commands/test_lib.py +++ b/tests/commands/test_lib.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -112,6 +112,7 @@ def test_global_install_repository(clirunner, validate_cliresult, "https://github.com/gioblu/PJON.git#6.2", "https://github.com/bblanchon/ArduinoJson.git", "https://gitlab.com/ivankravets/rs485-nodeproto.git", + "https://github.com/platformio/platformio-libmirror.git", # "https://developer.mbed.org/users/simon/code/TextLCD/", "knolleary/pubsubclient" ]) @@ -124,6 +125,14 @@ def test_global_install_repository(clirunner, validate_cliresult, ] assert set(items1) >= set(items2) + # check lib with duplicate URL + result = clirunner.invoke(cmd_lib, [ + "-g", "install", + "https://github.com/platformio/platformio-libmirror.git" + ]) + validate_cliresult(result) + assert "is already installed" in result.output + def test_global_lib_list(clirunner, validate_cliresult, isolated_pio_home): result = clirunner.invoke(cmd_lib, ["-g", "list"]) @@ -141,7 +150,8 @@ def test_global_lib_list(clirunner, validate_cliresult, isolated_pio_home): items2 = [ "OneWire", "DHT22", "PJON", "ESPAsyncTCP", "ArduinoJson", "PubSubClient", "rs485-nodeproto", "Adafruit ST7735 Library", - "RadioHead-1.62", "DallasTemperature", "NeoPixelBus", "IRremoteESP8266" + "RadioHead-1.62", "DallasTemperature", "NeoPixelBus", + "IRremoteESP8266", "platformio-libmirror" ] assert set(items1) == set(items2) @@ -175,7 +185,7 @@ def test_global_lib_update(clirunner, validate_cliresult, isolated_pio_home): validate_cliresult(result) validate_cliresult(result) assert result.output.count("[Skip]") == 5 - assert result.output.count("[Up-to-date]") == 9 + assert result.output.count("[Up-to-date]") == 10 assert "Uninstalling ArduinoJson @ 5.7.3" in result.output assert "Uninstalling IRremoteESP8266 @ fee16e880b" in result.output @@ -208,7 +218,7 @@ def test_global_lib_uninstall(clirunner, validate_cliresult, "ArduinoJson", "ArduinoJson_ID64@5.6.7", "DallasTemperature_ID54", "DHT22_ID58", "ESPAsyncTCP_ID305", "NeoPixelBus_ID547", "PJON", "PJON@src-79de467ebe19de18287becff0a1fb42d", "PubSubClient", - "RadioHead-1.62", "rs485-nodeproto" + "RadioHead-1.62", "rs485-nodeproto", "platformio-libmirror" ] assert set(items1) == set(items2) diff --git a/tests/commands/test_platform.py b/tests/commands/test_platform.py index fe29ce58..bdc50916 100644 --- a/tests/commands/test_platform.py +++ b/tests/commands/test_platform.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/commands/test_settings.py b/tests/commands/test_settings.py index bec21889..c6cd33da 100644 --- a/tests/commands/test_settings.py +++ b/tests/commands/test_settings.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/commands/test_test.py b/tests/commands/test_test.py index e7086290..6346c788 100644 --- a/tests/commands/test_test.py +++ b/tests/commands/test_test.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,10 +20,11 @@ from platformio import util def test_local_env(): - result = util.exec_command(["platformio", "test", "-d", - join("examples", "unit-testing", "calculator"), - "-e", "native"]) + result = util.exec_command([ + "platformio", "test", "-d", + join("examples", "unit-testing", "calculator"), "-e", "native" + ]) if result['returncode'] != 1: pytest.fail(result) - assert all( - [s in result['out'] for s in ("PASSED", "IGNORED", "FAILED")]) + assert all([s in result['out'] + for s in ("PASSED", "IGNORED", "FAILED")]), result['out'] diff --git a/tests/commands/test_update.py b/tests/commands/test_update.py index f17f5bbd..b8309fb8 100644 --- a/tests/commands/test_update.py +++ b/tests/commands/test_update.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/conftest.py b/tests/conftest.py index 46670a44..b407b328 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,11 +15,8 @@ import os import pytest -import requests from click.testing import CliRunner -requests.packages.urllib3.disable_warnings() - @pytest.fixture(scope="module") def clirunner(): diff --git a/tests/test_examples.py b/tests/test_examples.py index 42ff2b5e..86bc7741 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/test_ino2cpp.py b/tests/test_ino2cpp.py index 337eee72..0ef6e194 100644 --- a/tests/test_ino2cpp.py +++ b/tests/test_ino2cpp.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/test_maintenance.py b/tests/test_maintenance.py index fd71acf1..9fd7fd6b 100644 --- a/tests/test_maintenance.py +++ b/tests/test_maintenance.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/test_managers.py b/tests/test_managers.py index a9320def..1f58e03e 100644 --- a/tests/test_managers.py +++ b/tests/test_managers.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -127,6 +127,11 @@ def test_pkg_input_parser(): "git+ssh://git@gitlab.private-server.com/user/package#1.2.0", ("package", None, "git+ssh://git@gitlab.private-server.com/user/package#1.2.0") + ], + [ + "git+ssh://user@gitlab.private-server.com:1234/package#1.2.0", + ("package", None, + "git+ssh://user@gitlab.private-server.com:1234/package#1.2.0") ] ] for params, result in items: diff --git a/tests/test_pkgmanifest.py b/tests/test_pkgmanifest.py index f70dccde..a34d6864 100644 --- a/tests/test_pkgmanifest.py +++ b/tests/test_pkgmanifest.py @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tox.ini b/tox.ini index 0c09acce..7ced7a1c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,4 +1,4 @@ -# Copyright 2014-present PlatformIO +# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -21,10 +21,9 @@ usedevelop = True deps = isort flake8 - yapf + yapf<0.17 pylint pytest - show commands = python --version [testenv:docs]