diff --git a/.pylintrc b/.pylintrc index 939f8928a4..5e3b1e69d2 100644 --- a/.pylintrc +++ b/.pylintrc @@ -38,7 +38,7 @@ load-plugins= # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" -disable=C0103,C0111,E0611,F0401,I0011,R0801,R0903 +disable=C0103,C0111,E0611,F0401,I0011,R0801,R0903,R0922 [REPORTS] diff --git a/HISTORY.rst b/HISTORY.rst index 0643a43a1d..e9e35f6915 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,18 +1,40 @@ Release History =============== +0.9.0 (2014-12-01) +------------------ + +* Implemented `platformio settings `_ command +* Improved `platformio init `_ command. + Added new option ``--project-dir`` where you can specify another path to + directory where new project will be initialized (`issue #31 `_) +* Added *Migration Manager* which simplifies process with upgrading to a + major release +* Added *Telemetry Service* which should help us make *PlatformIO* better +* Implemented *PlatformIO AppState Manager* which allow to have multiple + ``.platformio`` states. +* Refactored *Package Manager* +* Download Manager: fixed SHA1 verification within *Cygwin Environment* + (`issue #26 `_) +* Fixed bug with code builder and built-in Arduino libraries + (`issue #28 `_) + 0.8.0 (2014-10-19) ------------------ -* Avoided trademark issues in ``library.json`` with new fields: - ``frameworks``, ``platforms`` and ``dependencies`` (`issue #17 `_) +* Avoided trademark issues in `library.json `_ + with the new fields: `frameworks `_, + `platforms `_ + and `dependencies `_ + (`issue #17 `_) * Switched logic from "Library Name" to "Library Registry ID" for all - ``platformio lib`` commands (install, uninstall, update and etc.) -* Renamed ``author`` field to ``authors`` and allowed to setup multiple authors - per library in ``library.json`` -* Added option to specify "maintainer" status in ``authors`` field -* New filters/options for ``platformio lib search`` command: ``--framework`` - and ``--platform`` + `platformio lib `_ + commands (install, uninstall, update and etc.) +* Renamed ``author`` field to `authors `_ + and allowed to setup multiple authors per library in `library.json `_ +* Added option to specify "maintainer" status in `authors `_ field +* New filters/options for `platformio lib search `_ + command: ``--framework`` and ``--platform`` 0.7.1 (2014-10-06) ------------------ @@ -25,14 +47,15 @@ Release History 0.7.0 (2014-09-24) ------------------ -* Implemented new ``[platformio]`` section for Configuration File with ``home_dir`` +* Implemented new `[platformio] `_ + section for Configuration File with `home_dir `_ option (`issue #14 `_) * Implemented *Library Manager* (`issue #6 `_) 0.6.0 (2014-08-09) ------------------ -* Implemented ``serialports monitor`` (`issue #10 `_) +* Implemented `platformio serialports monitor `_ (`issue #10 `_) * Fixed an issue ``ImportError: No module named platformio.util`` (`issue #9 `_) * Fixed bug with auto-conversation from Arduino \*.ino to \*.cpp @@ -44,27 +67,31 @@ Release History * Added auto-conversation from \*.ino to valid \*.cpp for Arduino/Energia frameworks (`issue #7 `_) * Added `Arduino example `_ - with external library (Adafruit CC3000) -* Implemented ``platformio upgrade`` command and "auto-check" for the latest + with external library (*Adafruit CC3000*) +* Implemented `platformio upgrade `_ + command and "auto-check" for the latest version (`issue #8 `_) -* Fixed an issue with "auto-reset" for Raspduino board +* Fixed an issue with "auto-reset" for *Raspduino* board * Fixed a bug with nested libs building 0.4.0 (2014-07-31) ------------------ -* Implemented ``serialports`` command +* Implemented `platformio serialports `_ command * Allowed to put special build flags only for ``src`` files via - ``srcbuild_flags`` environment option + `srcbuild_flags `_ + environment option * Allowed to override some of settings via system environment variables such as: ``$PIOSRCBUILD_FLAGS`` and ``$PIOENVS_DIR`` -* Added ``--upload-port`` option for ``platformio run`` command +* Added ``--upload-port`` option for `platformio run `_ command * Implemented (especially for `SmartAnthill `_) - ``platformio run -t uploadlazy`` target (no dependencies to framework libs, - ELF and etc.) -* Allowed to skip default packages via ``platformio install --skip-default-package`` flag -* Added tools for Raspberry Pi platform -* Added support for Microduino and Raspduino boards in ``atmelavr`` platform + `platformio run -t uploadlazy `_ + target (no dependencies to framework libs, ELF and etc.) +* Allowed to skip default packages via `platformio install --skip-default-package `_ + option +* Added tools for *Raspberry Pi* platform +* Added support for *Microduino* and *Raspduino* boards in + `atmelavr `_ platform 0.3.1 (2014-06-21) diff --git a/README.rst b/README.rst index 2fad2c4c8e..a92a43d63c 100644 --- a/README.rst +++ b/README.rst @@ -17,61 +17,107 @@ PlatformIO :target: https://pypi.python.org/pypi/platformio/ :alt: License -`Website `_ | +`Website + Library Search `_ | `Documentation `_ | `Project Examples `_ | -`Bugs/Questions `_ | `Blog `_ | -`Twitter `_ +`Twitter `_ -**PlatformIO** is a cross-platform code builder and library manager for -*Arduino, MSP430, ARM*. +.. image:: https://raw.githubusercontent.com/ivankravets/platformio/develop/docs/_static/platformio-logo.png + :target: http://platformio.ikravets.com -* `Website + Library Search `_ -* `Quickstart `_ -* `Installation `_ -* `Project Configuration File `_ -* `Platforms & Embedded Boards `_ +`PlatformIO `_ is a cross-platform code builder +and the missing library manager. + +* `Get Started `_ +* `Web 2.0 Library Search `_ +* `Development Platforms `_ +* `Embedded Boards `_ +* `Library Manager `_ * `User Guide `_ * `IDE Integration `_ * `Release History `_ -You have no need to install any *IDE* or compile any tool chains. *PlatformIO* +You have **no need** to install any *IDE* or compile any tool chains. *PlatformIO* has pre-built different development platforms including: compiler, debugger, uploader (for embedded boards) and many other useful tools. -**PlatformIO** allows developer to compile the same code with different -platforms using only one command +Use whenever. *Run everywhere.* +------------------------------- +*PlatformIO* is written in pure *Python* and **doesn't depend** on any +additional libraries/tools from an operation system. It allows you to use +*PlatformIO* beginning from *PC (Mac, Linux, Win)* and ending with credit-card +sized computers (like *Raspberry Pi*). + +Embedded Development. *Easier Than Ever.* +----------------------------------------- +*PlatformIO* is well suited for embedded development and has pre-configured +settings for most popular `Embedded Boards `_. + +* Colourful `command-line output `_ +* Built-in `Serial Port Monitor `_ +* Configurable `build -flags/-options `_ +* Automatic **firmware uploading** +* Integration with `development environments (IDE) `_ +* Ready for **cloud compilers** +* Pre-built tool chains, frameworks for the popular `Hardware Platforms `_ + +.. image:: https://raw.githubusercontent.com/ivankravets/platformio-web/develop/app/images/platformio-embedded-development.png + :target: http://platformio.ikravets.com + :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 Search `_ +* Open Source `Library Registry API `_ +* Library Crawler based on `library.json `_ + specification +* Library **dependency management** +* Automatic library updating + +.. image:: https://raw.githubusercontent.com/ivankravets/platformio-web/develop/app/images/platformio-library-manager.png + :target: http://platformio.ikravets.com + :alt: PlatformIO Library Manager Architecture + +Smart Code Builder. *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/ivankravets/platformio-web/develop/app/images/platformio-scons-builder.png + :target: http://platformio.ikravets.com + :alt: PlatformIO Code Builder Architecture + +Single source code. *Multiple platforms.* +----------------------------------------- +*PlatformIO* allows developer to compile the same code with different +development platforms using the *Only One Command* `platformio run `_. This happens due to -`Project Configuration File `_ -where you can setup different environments with specific -options: platform type, firmware uploading settings, pre-built framework -and many more. - -.. image:: examples/platformio-examples.png - :target: https://github.com/ivankravets/platformio/raw/develop/examples/platformio-examples.png - :alt: Examples - :width: 730px - -**PlatformIO** is well suited for **embedded development**. It can: - -* Automatically analyse dependency -* Reliably detect build changes -* Build framework or library source code to static library -* Build *ELF* (executable and linkable firmware) -* Convert *ELF* to *HEX* or *BIN* file -* Extract *EEPROM* data -* Upload firmware to your device +`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 many popular embedded platforms like these: -* ``atmelavr`` `Atmel AVR `_ - (including `Arduino `_ based boards) -* ``timsp430`` `TI MSP430 `_ - (including `MSP430 LaunchPads `_) -* ``titiva`` `TI TIVA C `_ - (including `TIVA C Series LaunchPads `_) +* ``atmelavr`` `Atmel AVR `_ + (including *Arduino*-based boards, *Microduino, Raspduino, Teensy*) +* ``timsp430`` `TI MSP430 `_ + (including *MSP430* LaunchPads) +* ``titiva`` `TI TIVA C `_ + (including *TIVA C* Series LaunchPads) Licence @@ -80,4 +126,3 @@ Licence Copyright (C) 2014 Ivan Kravets Licenced under the MIT Licence. - diff --git a/docs/_static/ide-platformio-arduino.png b/docs/_static/ide-platformio-arduino.png new file mode 100644 index 0000000000..67d1e9e031 Binary files /dev/null and b/docs/_static/ide-platformio-arduino.png differ diff --git a/docs/_static/ide-platformio-eclipse.png b/docs/_static/ide-platformio-eclipse.png new file mode 100644 index 0000000000..8a8dde024c Binary files /dev/null and b/docs/_static/ide-platformio-eclipse.png differ diff --git a/docs/_static/ide-platformio-energia.png b/docs/_static/ide-platformio-energia.png new file mode 100644 index 0000000000..877a6c530d Binary files /dev/null and b/docs/_static/ide-platformio-energia.png differ diff --git a/docs/_static/ide-platformio-vim.png b/docs/_static/ide-platformio-vim.png new file mode 100644 index 0000000000..8020b2770a Binary files /dev/null and b/docs/_static/ide-platformio-vim.png differ diff --git a/docs/_static/platformio-logo.png b/docs/_static/platformio-logo.png new file mode 100644 index 0000000000..62bde5cafc Binary files /dev/null and b/docs/_static/platformio-logo.png differ diff --git a/docs/ide.rst b/docs/ide.rst index e28ca0f7ad..ad6fa16780 100644 --- a/docs/ide.rst +++ b/docs/ide.rst @@ -6,20 +6,33 @@ IDE Integration Arduino IDE ----------- -`Integration of PlatformIO library manager to Arduino IDE `_ +.. image:: _static/ide-platformio-arduino.png + :target: http://www.ikravets.com/computer-life/platformio/2014/10/07/integration-of-platformio-library-manager-to-arduino-and-energia-ides + +* `Integration of PlatformIO library manager to Arduino IDE `_ Eclipse ------- -`Building and debugging Atmel AVR (Arduino-based) project using Eclipse IDE+PlatformIO `_ + + +.. image:: _static/ide-platformio-eclipse.png + :target: http://www.ikravets.com/computer-life/programming/2014/06/20/building-and-debugging-atmel-avr-arduino-based-project-using-eclipse-ideplatformio + +* `Building and debugging Atmel AVR (Arduino-based) project using Eclipse IDE+PlatformIO `_ Energia IDE ----------- -`Integration of PlatformIO library manager to Energia IDE `_ +.. image:: _static/ide-platformio-energia.png + :target: http://www.ikravets.com/computer-life/platformio/2014/10/07/integration-of-platformio-library-manager-to-arduino-and-energia-ides + +* `Integration of PlatformIO library manager to Energia IDE `_ VIM --- +.. image:: _static/ide-platformio-vim.png + Recommended bundles: * Syntax highlight - `Arduino-syntax-file `_ diff --git a/docs/index.rst b/docs/index.rst index a7b2254e8a..b72528a6fb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,12 +1,15 @@ -PlatformIO: A cross-platform code builder and library manager for Arduino, MSP430, ARM -====================================================================================== +PlatformIO: A cross-platform code builder and the missing library manager +========================================================================= + +.. image:: _static/platformio-logo.png + :target: http://platformio.ikravets.com `Website + Library Search `_ | `Project Examples `_ | `Source Code `_ | -`Bugs/Questions `_ | +`Issues `_ | `Blog `_ | -`Twitter `_ +`Twitter `_ You have no need to install any *IDE* or compile any tool chains. *PlatformIO* has pre-built different development platforms including: compiler, debugger, @@ -27,9 +30,7 @@ instruments. * Automatically analyse dependency * Reliably detect build changes * Build framework or library source code to static library -* Build *ELF* (executable and linkable firmware) -* Convert *ELF* to *HEX* or *BIN* file -* Extract *EEPROM* data +* Lookup for external libraries which are installed via :ref:`librarymanager` * Upload firmware to your device diff --git a/docs/installation.rst b/docs/installation.rst index d0f875bb31..e0df7b680d 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -3,31 +3,51 @@ Installation ============ -*PlatformIO* is written in `Python `_ and works with -versions 2.6 and 2.7 on Unix/Linux, OS X, Windows and Credit-card ARM-based -computers (Raspberry Pi). +*PlatformIO* is written in `Python `_ and works +on *Mac OS X*, *Linux*, *Windows OS* and Credit-card *ARM*-based +computers (*Raspberry Pi*). + +System requirements +------------------- + +* **Operating systems:** + * Mac OS X + * Linux + * Windows +* `Python 2.6 or Python 2.7 `_ All commands below should be executed in `Command-line `_ -application in your *OS*: +application: -* *Unix/Linux/OS X* this is *Terminal* application. +* *Mac OS X / Linux* this is *Terminal* application. * *Windows* this is `Command Prompt `_ (``cmd.exe``) application. +Please *choose one of* the following: -Super-Quick ------------ +Super-Quick (Mac / Linux) +------------------------- -To install or upgrade *PlatformIO*, download -`get-platformio.py `_ script. +To install or upgrade *PlatformIO* paste that at a *Terminal* prompt +(you might need to run ``sudo`` first): + +.. code-block:: bash -Then run the following (which may require administrator access): + python -c "$(curl -fsSL https://raw.githubusercontent.com/ivankravets/platformio/master/scripts/get-platformio.py)" + + +Installer Script (Mac / Linux / Windows) +---------------------------------------- + +To install or upgrade *PlatformIO*, download +`get-platformio.py `_ +script. Then run the following (you might need to run ``sudo`` first): .. code-block:: bash - $ [sudo] python get-platformio.py + python get-platformio.py On *Windows OS* it may look like: diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index 2befb7df7b..fe6e573f0c 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -1,21 +1,20 @@ -.. _library_config: .. |PIOAPICR| replace:: *PlatformIO Library Registry Crawler* +.. _library_config: library.json ============ -*PlatformIO*-suitable library should be defined by a manifest file -``library.json`` in a `JSON-style `_. -A data in ``library.json`` should be represented via -`associative array `_ -(name/value pairs). An order doesn't matter. +``library.json`` is a manifest file of development library. -The allowable fields (names from pairs) are described below. The fields -(:ref:`libjson_name`, :ref:`libjson_description`, :ref:`libjson_keywords` -and :ref:`libjson_authors`) -will be displayed in the search results at the :ref:`cmd_lib_search` (*CLI*) -and at the `WebSite `_. -Also, they can be used for searching for libraries. +Initially it was +developed for :ref:`librarymanager`, but later was accepted by worldwide embedded +community like a **standard library specification**. + +A data in ``library.json`` should be represented +in `JSON-style `_ via +`associative array `_ +(name/value pairs). An order doesn't matter. The allowable fields +(names from pairs) are described below. .. contents:: @@ -130,7 +129,7 @@ Example: "repository": { - "name": "git", + "type": "git", "url": "https://github.com/foo/bar.git" } diff --git a/docs/librarymanager/creating.rst b/docs/librarymanager/creating.rst index 890d358846..e5590f59d9 100644 --- a/docs/librarymanager/creating.rst +++ b/docs/librarymanager/creating.rst @@ -36,14 +36,14 @@ you **need to specify** only these fields in the :ref:`library_config`: * :ref:`libjson_repository` |PIOAPICR| will populate the rest fields, like :ref:`libjson_version` or -:ref:`libjson_author` with an actual information from *GitHub*. +:ref:`libjson_authors` with an actual information from *GitHub*. Example: .. code-block:: javascript { - "name": "Arduino-IRremote", + "name": "IRremote", "keywords": "infrared, ir, remote", "description": "Send and receive infrared signals with multiple protocols", "repository": @@ -62,7 +62,7 @@ The list of **required** fields in the :ref:`library_config` will look like: * :ref:`libjson_name` * :ref:`libjson_keywords` * :ref:`libjson_description` -* :ref:`libjson_author` +* :ref:`libjson_authors` * :ref:`libjson_repository` Example: @@ -70,10 +70,10 @@ Example: .. code-block:: javascript { - "name": "Arduino-XBee", + "name": "XBee", "keywords": "xbee, protocol, radio", "description": "Arduino library for communicating with XBees in API mode", - "author": + "authors": { "name": "Andrew Rapp", "email": "andrew.rapp@gmail.com", @@ -97,17 +97,17 @@ of **required** fields in the :ref:`library_config` will look like: * :ref:`libjson_name` * :ref:`libjson_keywords` * :ref:`libjson_description` -* :ref:`libjson_author` +* :ref:`libjson_authors` * :ref:`libjson_version` * :ref:`libjson_downloadurl` .. code-block:: javascript { - "name": "Arduino-OneWire", + "name": "OneWire", "keywords": "onewire, 1-wire, bus, sensor, temperature, ibutton", "description": "Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc)", - "author": + "authors": { "name": "Paul Stoffregen", "url": "http://www.pjrc.com/teensy/td_libs_OneWire.html" diff --git a/docs/librarymanager/index.rst b/docs/librarymanager/index.rst index 1820396949..5dcc323a6f 100644 --- a/docs/librarymanager/index.rst +++ b/docs/librarymanager/index.rst @@ -5,11 +5,11 @@ Library Manager .. - *"A missing library manager for embedded platforms (Atmel AVR, MSP430 and ARM)"* [#]_ + *"The missing library manager for development platforms"* [#]_ *PlatformIO Library Manager* allows you to organize external embedded libraries. -You can search for new libraries via :ref:`Command Line ` -or `WebSite `_ interfaces. +You can search for new libraries via :ref:`Command Line interface ` +or `Web 2.0 Library Search `_. You don't need to bother for finding the latest version of library. Due to :ref:`cmd_lib_update` command you will have up-to-date external libraries. @@ -17,8 +17,9 @@ You don't need to bother for finding the latest version of library. Due to .. toctree:: :maxdepth: 2 - creating config + creating + User Guide <../userguide/lib/index.rst> .. [#] Inspired by `npm `_ and `bower `_ package managers for web. diff --git a/docs/projectconf.rst b/docs/projectconf.rst index d63996e85d..a9f275bd39 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -246,10 +246,6 @@ Examples framework = arduino board = uno - upload_port = /dev/ttyUSB0 - # for Windows OS - # upload_port = COM3 - # enable auto-uploading targets = upload @@ -265,10 +261,6 @@ Examples framework = arduino board = 168pa8m - upload_port = /dev/ttyUSB0 - # for Windows OS - # upload_port = COM3 - # enable auto-uploading targets = upload diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 6ad1551c78..f211fdb213 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -3,6 +3,10 @@ Quickstart ========== +.. note:: + Please read `Get Started `_ + article from the official WebSite. + First, :ref:`Install PlatformIO `. Print all available development platforms for installing diff --git a/docs/userguide/cmd_init.rst b/docs/userguide/cmd_init.rst index 78ef1164f6..280c6900bf 100644 --- a/docs/userguide/cmd_init.rst +++ b/docs/userguide/cmd_init.rst @@ -10,7 +10,7 @@ Usage .. code-block:: bash - platformio init + platformio init [OPTIONS] Description @@ -21,22 +21,50 @@ Initialize new PlatformIO based project. This command will create: -* ``.pioenvs`` - a temporary working directory. -* ``lib`` - a directory for project specific libraries. PlatformIO will - compile them to static libraries and link to executable file -* ``src`` - a source directory. Put your source code here. * :ref:`projectconf` +* ``src`` - a source directory. Put your source code here +* ``lib`` - a directory for the project specific libraries. PlatformIO will + compile them to static libraries and link to executable file + +Options +------- + +.. option:: + --project-dir, -d + +Specified path to the directory where *PlatformIO* will initialize new project. Examples -------- +1. Create new project in the current working directory + .. code-block:: bash - # Change directory to the future project - $ cd /path/to/empty/directory $ platformio init - Project has been initialized! - Please put your source code to `src` directory, external libraries to `lib` - and setup environments in `platformio.ini` file. - Then process project with `platformio run` command. + The current working directory *** will be used for the new project. + You can specify another project directory via + `platformio init -d %PATH_TO_PROJECT_DIR%` command. + + The next files/directories will be created in *** + platformio.ini - Project Configuration File + src - a source directory. Put your source code here + lib - a directory for the project specific libraries + Do you want to continue? [y/N]: y + Project has been successfully initialized! + Now you can process it with `platformio run` command. + + +2. Create new project in the specified directory + +.. code-block:: bash + + $ platformio init -d %PATH_TO_DIR% + The next files/directories will be created in *** + platformio.ini - Project Configuration File + src - a source directory. Put your source code here + lib - a directory for the project specific libraries + Do you want to continue? [y/N]: y + Project has been successfully initialized! + Now you can process it with `platformio run` command. diff --git a/docs/userguide/cmd_search.rst b/docs/userguide/cmd_search.rst index 7edd9568cb..a411c2e7d4 100644 --- a/docs/userguide/cmd_search.rst +++ b/docs/userguide/cmd_search.rst @@ -11,7 +11,7 @@ Usage .. code-block:: bash # Print all available development platforms - platformio search all + platformio search # Filter platforms by "Query" platformio search QUERY diff --git a/docs/userguide/cmd_settings.rst b/docs/userguide/cmd_settings.rst new file mode 100644 index 0000000000..b914d46cc1 --- /dev/null +++ b/docs/userguide/cmd_settings.rst @@ -0,0 +1,114 @@ +.. _cmd_settings: + +platformio settings +=================== + +Manage PlatformIO settings + +.. contents:: + +platformio settings get +----------------------- + +Usage +~~~~~ + +.. code-block:: bash + + platformio settings get [NAME] + + +Description +~~~~~~~~~~~ + +Get/List existing settings + + +Examples +~~~~~~~~ + +1. List all settings and current their values + +.. code-block:: bash + + $ platformio settings get + Name Value [Default] Description + ------------------------------------------------------------------------------------------ + auto_update_libraries Yes Automatically update libraries (Yes/No) + auto_update_platforms Yes Automatically update platforms (Yes/No) + check_libraries_interval 7 Check for the library updates interval (days) + check_platformio_interval 3 Check for the new PlatformIO interval (days) + check_platforms_interval 7 Check for the platforms updates interval (days) + + +2. Show specified setting + +.. code-block:: bash + + $ platformio settings get auto_update_platforms + Name Value [Default] Description + ------------------------------------------------------------------------------------------ + auto_update_platforms Yes Automatically update platforms (Yes/No) + + +platformio settings set +----------------------- + +Usage +~~~~~ + +.. code-block:: bash + + platformio settings set NAME VALUE + + +Description +~~~~~~~~~~~ + +Set new value for the setting + +Examples +~~~~~~~~ + +Change to check for the new PlatformIO each day + +.. code-block:: bash + + $ platformio settings set check_platformio_interval 1 + The new value for the setting has been set! + Name Value [Default] Description + ------------------------------------------------------------------------------------------ + check_platformio_interval 1 [3] Check for the new PlatformIO interval (days) + + +platformio settings reset +------------------------- + +Usage +~~~~~ + +.. code-block:: bash + + platformio settings reset + + +Description +~~~~~~~~~~~ + +Reset settings to default + +Examples +~~~~~~~~ + +.. code-block:: bash + + $ platformio settings reset + The settings have been reseted! + + Name Value [Default] Description + ------------------------------------------------------------------------------------------ + auto_update_libraries Yes Automatically update libraries (Yes/No) + auto_update_platforms Yes Automatically update platforms (Yes/No) + check_libraries_interval 7 Check for the library updates interval (days) + check_platformio_interval 3 Check for the new PlatformIO interval (days) + check_platforms_interval 7 Check for the platform updates interval (days) diff --git a/docs/userguide/index.rst b/docs/userguide/index.rst index 3cadb2f55e..59eab5a8c9 100644 --- a/docs/userguide/index.rst +++ b/docs/userguide/index.rst @@ -21,6 +21,7 @@ To print all available commands and options use: cmd_run cmd_search cmd_serialports + cmd_settings cmd_show cmd_uninstall cmd_update diff --git a/docs/userguide/lib/cmd_install.rst b/docs/userguide/lib/cmd_install.rst index 4ba8755ec6..b31a6b0438 100644 --- a/docs/userguide/lib/cmd_install.rst +++ b/docs/userguide/lib/cmd_install.rst @@ -35,38 +35,38 @@ Examples .. code-block:: bash - # IRremote: http://platformio.ikravets.com/#!/lib/show/4 + # IRremote: http://platformio.ikravets.com/#!/lib/show/4/IRremote $ platformio lib install 4 - Installing library [ 4 ]: - Downloading [####################################] 100% - Unpacking [####################################] 100% - The library #4 'IRremote' has been successfully installed! + # Installing library [ 4 ]: + # Downloading [####################################] 100% + # Unpacking [####################################] 100% + # The library #4 'IRremote' has been successfully installed! 2. Install specified version of library .. code-block:: bash - # XBee: http://platformio.ikravets.com/#!/lib/show/6 + # XBee: http://platformio.ikravets.com/#!/lib/show/6/XBee $ platformio lib install 6 --version=0.5 - Installing library [ 6 ]: - Downloading [####################################] 100% - Unpacking [####################################] 100% - The library #6 'XBee' has been successfully installed! + # Installing library [ 6 ]: + # Downloading [####################################] 100% + # Unpacking [####################################] 100% + # The library #6 'XBee' has been successfully installed! 3. Install library with dependencies .. code-block:: bash - # Adafruit-ST7735: http://platformio.ikravets.com/#!/lib/show/12 + # Adafruit-ST7735: http://platformio.ikravets.com/#!/lib/show/12/Adafruit-ST7735 $ platformio lib install 12 - Installing library [ 12 ]: - Downloading [####################################] 100% - Unpacking [####################################] 100% - The library #12 'Adafruit-ST7735' has been successfully installed! - Installing dependencies: - Installing library [ 13 ]: - Downloading [####################################] 100% - Unpacking [####################################] 100% - The library #13 'Adafruit-GFX' has been successfully installed! + # Installing library [ 12 ]: + # Downloading [####################################] 100% + # Unpacking [####################################] 100% + # The library #12 'Adafruit-ST7735' has been successfully installed! + # Installing dependencies: + # Installing library [ 13 ]: + # Downloading [####################################] 100% + # Unpacking [####################################] 100% + # The library #13 'Adafruit-GFX' has been successfully installed! diff --git a/docs/userguide/lib/cmd_list.rst b/docs/userguide/lib/cmd_list.rst index a5ea681e2a..5ab7e0dcc3 100644 --- a/docs/userguide/lib/cmd_list.rst +++ b/docs/userguide/lib/cmd_list.rst @@ -25,15 +25,15 @@ Examples .. code-block:: bash $ platformio lib list - - [ ID ] Name Compatibility "Authors": Description - ------------------------------------------------------------------------------------- - [ 23 ] Adafruit-L3GD20-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the L3GD20 Gyroscope - [ 12 ] Adafruit-ST7735 arduino, atmelavr "Adafruit Industries": A library for the Adafruit 1.8" SPI display - [ 31 ] Adafruit-Unified-Sensor arduino, atmelavr "Adafruit Industries": Adafruit Unified Sensor Driver - [ 26 ] Adafruit-LSM303DLHC-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for Adafruit's LSM303 Breakout (Accelerometer + Magnetometer) - [ 6 ] XBee arduino, atmelavr "Andrew Rapp": Arduino library for communicating with XBees in API mode - [ 13 ] Adafruit-GFX arduino, atmelavr "Adafruit Industries": A core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.) - [ 4 ] IRremote arduino, atmelavr "Ken Shirriff": Send and receive infrared signals with multiple protocols - [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) - ... + # + # [ ID ] Name Compatibility "Authors": Description + # ------------------------------------------------------------------------------------- + # [ 23 ] Adafruit-L3GD20-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the L3GD20 Gyroscope + # [ 12 ] Adafruit-ST7735 arduino, atmelavr "Adafruit Industries": A library for the Adafruit 1.8" SPI display + # [ 31 ] Adafruit-Unified-Sensor arduino, atmelavr "Adafruit Industries": Adafruit Unified Sensor Driver + # [ 26 ] Adafruit-LSM303DLHC-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for Adafruit's LSM303 Breakout (Accelerometer + Magnetometer) + # [ 6 ] XBee arduino, atmelavr "Andrew Rapp": Arduino library for communicating with XBees in API mode + # [ 13 ] Adafruit-GFX arduino, atmelavr "Adafruit Industries": A core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.) + # [ 4 ] IRremote arduino, atmelavr "Ken Shirriff": Send and receive infrared signals with multiple protocols + # [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) + # ... diff --git a/docs/userguide/lib/cmd_search.rst b/docs/userguide/lib/cmd_search.rst index e9bae79e97..3156c0eee0 100644 --- a/docs/userguide/lib/cmd_search.rst +++ b/docs/userguide/lib/cmd_search.rst @@ -16,8 +16,8 @@ Usage Description ----------- -Search for library in *PlatformIO Library Registry* by -:ref:`library_config` fields in the boolean mode. +Search for library in `PlatformIO Library Registry `_ +by :ref:`library_config` fields in the boolean mode. The boolean search capability supports the following operators: @@ -90,102 +90,102 @@ Examples .. code-block:: bash - $ platformio lib search "" - Found N libraries: - - [ ID ] Name Compatibility "Authors": Description - ------------------------------------------------------------------------------------- - [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) - [ 13 ] Adafruit-GFX arduino, atmelavr "Adafruit Industries": A core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.) - [ 23 ] Adafruit-L3GD20-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the L3GD20 Gyroscope - [ 26 ] Adafruit-LSM303DLHC-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for Adafruit's LSM303 Breakout (Accelerometer + Magnetometer) - [ 12 ] Adafruit-ST7735 arduino, atmelavr "Adafruit Industries": A library for the Adafruit 1.8" SPI display - [ 31 ] Adafruit-Unified-Sensor arduino, atmelavr "Adafruit Industries": Adafruit Unified Sensor Driver - [ 4 ] IRremote arduino, atmelavr "Ken Shirriff": Send and receive infrared signals with multiple protocols - [ 1 ] OneWire arduino, atmelavr "Paul Stoffregen": Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) - [ 6 ] XBee arduino, atmelavr "Andrew Rapp": Arduino library for communicating with XBees in API mode - [ 15 ] Adafruit-ADXL345-Unified arduino, atmelavr "Adafruit Industries": Unified driver for the ADXL345 Accelerometer - Show next libraries? [y/N]: - ... - -2. Search for "1-Wire" library + $ platformio lib search + # Found N libraries: + # + # [ ID ] Name Compatibility "Authors": Description + # ------------------------------------------------------------------------------------- + # [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) + # [ 13 ] Adafruit-GFX arduino, atmelavr "Adafruit Industries": A core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.) + # [ 23 ] Adafruit-L3GD20-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the L3GD20 Gyroscope + # [ 26 ] Adafruit-LSM303DLHC-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for Adafruit's LSM303 Breakout (Accelerometer + Magnetometer) + # [ 12 ] Adafruit-ST7735 arduino, atmelavr "Adafruit Industries": A library for the Adafruit 1.8" SPI display + # [ 31 ] Adafruit-Unified-Sensor arduino, atmelavr "Adafruit Industries": Adafruit Unified Sensor Driver + # [ 4 ] IRremote arduino, atmelavr "Ken Shirriff": Send and receive infrared signals with multiple protocols + # [ 1 ] OneWire arduino, atmelavr "Paul Stoffregen": Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) + # [ 6 ] XBee arduino, atmelavr "Andrew Rapp": Arduino library for communicating with XBees in API mode + # [ 15 ] Adafruit-ADXL345-Unified arduino, atmelavr "Adafruit Industries": Unified driver for the ADXL345 Accelerometer + # Show next libraries? [y/N]: + # ... + +2. Search for `1-Wire libraries `_ .. code-block:: bash - $ platformio lib search 1-wire - Found N libraries: + $ platformio lib search "1-wire" + # Found N libraries: + # + # [ ID ] Name Compatibility "Authors": Description + # ------------------------------------------------------------------------------------- + # [ 1 ] OneWire arduino, atmelavr "Paul Stoffregen": Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) + # ... - [ ID ] Name Compatibility "Authors": Description - ------------------------------------------------------------------------------------- - [ 1 ] OneWire arduino, atmelavr "Paul Stoffregen": Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) - ... - -3. Search for Arduino-based "I2C" libraries operator. +3. Search for `Arduino-based "I2C" libraries `_ .. code-block:: bash - $ platformio lib search "i2c" --framework=arduino - Found N libraries: - - [ ID ] Name Compatibility "Authors": Description - ------------------------------------------------------------------------------------- - [ 11 ] I2Cdevlib-Core arduino, atmelavr "Jeff Rowberg": The I2C Device Library (I2Cdevlib) is a collection of uniform and well-documented classes to provide simple and intuitive interfaces to I2C devices. - [ 24 ] Adafruit-L3GD20 arduino, atmelavr "Adafruit Industries": Driver for Adafruit's L3GD20 I2C Gyroscope Breakout - [ 10 ] I2Cdevlib-AK8975 arduino, atmelavr "Jeff Rowberg": AK8975 is 3-axis electronic compass IC with high sensitive Hall sensor technology - [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) - ... + $ platformio lib search "i2c" --framework="arduino" + # Found N libraries: + # + # [ ID ] Name Compatibility "Authors": Description + # ------------------------------------------------------------------------------------- + # [ 11 ] I2Cdevlib-Core arduino, atmelavr "Jeff Rowberg": The I2C Device Library (I2Cdevlib) is a collection of uniform and well-documented classes to provide simple and intuitive interfaces to I2C devices. + # [ 24 ] Adafruit-L3GD20 arduino, atmelavr "Adafruit Industries": Driver for Adafruit's L3GD20 I2C Gyroscope Breakout + # [ 10 ] I2Cdevlib-AK8975 arduino, atmelavr "Jeff Rowberg": AK8975 is 3-axis electronic compass IC with high sensitive Hall sensor technology + # [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) + # ... -4. Search for libraries by "web" and "http" keywords. The ``""`` here is for - "empty" query argument. +4. Search for `libraries by "web" and "http" keywords `_. .. code-block:: bash - $ platformio lib search "" --keyword=web --keyword=http - Found N libraries: + $ platformio lib search --keyword="web" --keyword="http" + # Found N libraries: + # + # [ ID ] Name Compatibility "Authors": Description + # ------------------------------------------------------------------------------------- + # [ 5 ] Webduino arduino, atmelavr "Ben Combee": An extensible web server library (for use with the Arduino WizNet Ethernet Shield) + # [ 17 ] Adafruit-CC3000 arduino, atmelavr "Adafruit Industries": Library code for Adafruit's CC3000 Wi-Fi/WiFi breakouts + # ... - [ ID ] Name Compatibility "Authors": Description - ------------------------------------------------------------------------------------- - [ 5 ] Webduino arduino, atmelavr "Ben Combee": An extensible web server library (for use with the Arduino WizNet Ethernet Shield) - [ 17 ] Adafruit-CC3000 arduino, atmelavr "Adafruit Industries": Library code for Adafruit's CC3000 Wi-Fi/WiFi breakouts - ... - -5. Search for libraries from "Adafruit Industries" author. +5. Search for `libraries from "Adafruit Industries" author `_ .. code-block:: bash - $ platformio lib search "" --author="Adafruit Industries" - Found N libraries: - - [ ID ] Name Compatibility "Authors": Description - ------------------------------------------------------------------------------------- - [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) - [ 13 ] Adafruit-GFX arduino, atmelavr "Adafruit Industries": A core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.) - [ 23 ] Adafruit-L3GD20-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the L3GD20 Gyroscope - [ 26 ] Adafruit-LSM303DLHC-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for Adafruit's LSM303 Breakout (Accelerometer + Magnetometer) - ... - -6. Search for libraries that are compatible with Dallas temperature sensors + $ platformio lib search --author="Adafruit Industries" + # Found N libraries: + # + # [ ID ] Name Compatibility "Authors": Description + # ------------------------------------------------------------------------------------- + # [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) + # [ 13 ] Adafruit-GFX arduino, atmelavr "Adafruit Industries": A core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.) + # [ 23 ] Adafruit-L3GD20-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the L3GD20 Gyroscope + # [ 26 ] Adafruit-LSM303DLHC-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for Adafruit's LSM303 Breakout (Accelerometer + Magnetometer) + # ... + +6. Search for `libraries that are compatible with Dallas temperature sensors `_ like DS18B20, DS18S20 and etc. .. code-block:: bash $ platformio lib search "DS*" - Found N libraries: - - [ ID ] Name Compatibility "Authors": Description - ------------------------------------------------------------------------------------- - [ 1 ] OneWire arduino, atmelavr "Paul Stoffregen": Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) - ... + # Found N libraries: + # + # [ ID ] Name Compatibility "Authors": Description + # ------------------------------------------------------------------------------------- + # [ 1 ] OneWire arduino, atmelavr "Paul Stoffregen": Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) + # ... -7. Search for Arduino-based *X10* or *XBee* libraries. The search query that is - described below can be interpreted like ``arduino x10 OR arduino xbee``. +7. Search for `Arduino-based *X10* or *XBee* libraries `_. + The search query that is described below can be interpreted like + ``arduino x10 OR arduino xbee`` .. code-block:: bash - $ platformio lib search --framework=arduino "+(x10 xbee)" - Found 2 libraries: - - [ ID ] Name Compatibility "Authors": Description - ------------------------------------------------------------------------------------- - [ 36 ] X10 arduino, atmelavr "Doug Clinton": Sending X10 signals over AC power lines (PL513, TW523 and etc) - [ 6 ] XBee arduino, atmelavr "Andrew Rapp": Arduino library for communicating with XBees in API mode + $ platformio lib search "+(x10 xbee)" --framework="arduino" + # Found 2 libraries: + # + # [ ID ] Name Compatibility "Authors": Description + # ------------------------------------------------------------------------------------- + # [ 36 ] X10 arduino, atmelavr "Doug Clinton": Sending X10 signals over AC power lines (PL513, TW523 and etc) + # [ 6 ] XBee arduino, atmelavr "Andrew Rapp": Arduino library for communicating with XBees in API mode diff --git a/docs/userguide/lib/cmd_show.rst b/docs/userguide/lib/cmd_show.rst index a323669fd5..669acac666 100644 --- a/docs/userguide/lib/cmd_show.rst +++ b/docs/userguide/lib/cmd_show.rst @@ -24,14 +24,14 @@ Examples .. code-block:: bash - # OneWire: http://platformio.ikravets.com/#!/lib/show/1 + # OneWire: http://platformio.ikravets.com/#!/lib/show/1/OneWire $ platformio lib show 1 - OneWire - ------- - Authors: Paul Stoffregen http://www.pjrc.com/teensy/td_libs_OneWire.html - Keywords: onewire, 1-wire, bus, sensor, temperature, ibutton - Frameworks: arduino - Platforms: atmelavr - Version: 2.2 - - Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) + # OneWire + # ------- + # Authors: Paul Stoffregen http://www.pjrc.com/teensy/td_libs_OneWire.html (maintainer), Jim Studt, Jason Dangel , Derek Yerger, Tom Pollard , Robin James + # Keywords: onewire, 1-wire, bus, sensor, temperature, ibutton + # Frameworks: arduino + # Platforms: atmelavr + # Version: 2.2 + # + # Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) diff --git a/docs/userguide/lib/cmd_uninstall.rst b/docs/userguide/lib/cmd_uninstall.rst index ed226e3e39..b98025edbf 100644 --- a/docs/userguide/lib/cmd_uninstall.rst +++ b/docs/userguide/lib/cmd_uninstall.rst @@ -24,6 +24,6 @@ Examples .. code-block:: bash - # XBee: http://platformio.ikravets.com/#!/lib/show/6 + # XBee: http://platformio.ikravets.com/#!/lib/show/6/XBee $ platformio lib uninstall 6 - The library #6 'XBee' has been successfully uninstalled! + # The library #6 'XBee' has been successfully uninstalled! diff --git a/docs/userguide/lib/cmd_update.rst b/docs/userguide/lib/cmd_update.rst index f1da7f9d25..f719fa138e 100644 --- a/docs/userguide/lib/cmd_update.rst +++ b/docs/userguide/lib/cmd_update.rst @@ -25,19 +25,19 @@ Examples .. code-block:: bash $ platformio lib update - Updating [ 23 ] Adafruit-L3GD20-Unified library: - Versions: Current=63de2eb9ea, Latest=63de2eb9ea [Up-to-date] - Updating [ 12 ] Adafruit-ST7735 library: - Versions: Current=e880eb1687, Latest=e880eb1687 [Up-to-date] - Updating [ 31 ] Adafruit-Unified-Sensor library: - Versions: Current=88ae805bce, Latest=88ae805bce [Up-to-date] - Updating [ 26 ] Adafruit-LSM303DLHC-Unified library: - Versions: Current=59767208a8, Latest=59767208a8 [Up-to-date] - Updating [ 13 ] Adafruit-GFX library: - Versions: Current=a9e5bc4707, Latest=a9e5bc4707 [Up-to-date] - Updating [ 1 ] OneWire library: - Versions: Current=2.2, Latest=2.2 [Up-to-date] - Updating [ 4 ] IRremote library: - Versions: Current=f2dafe5030, Latest=f2dafe5030 [Up-to-date] - Updating [ 14 ] Adafruit-9DOF-Unified library: - Versions: Current=b2f07242ac, Latest=b2f07242ac [Up-to-date] + # Updating [ 23 ] Adafruit-L3GD20-Unified library: + # Versions: Current=63de2eb9ea, Latest=63de2eb9ea [Up-to-date] + # Updating [ 12 ] Adafruit-ST7735 library: + # Versions: Current=e880eb1687, Latest=e880eb1687 [Up-to-date] + # Updating [ 31 ] Adafruit-Unified-Sensor library: + # Versions: Current=88ae805bce, Latest=88ae805bce [Up-to-date] + # Updating [ 26 ] Adafruit-LSM303DLHC-Unified library: + # Versions: Current=59767208a8, Latest=59767208a8 [Up-to-date] + # Updating [ 13 ] Adafruit-GFX library: + # Versions: Current=a9e5bc4707, Latest=a9e5bc4707 [Up-to-date] + # Updating [ 1 ] OneWire library: + # Versions: Current=2.2, Latest=2.2 [Up-to-date] + # Updating [ 4 ] IRremote library: + # Versions: Current=f2dafe5030, Latest=f2dafe5030 [Up-to-date] + # Updating [ 14 ] Adafruit-9DOF-Unified library: + # Versions: Current=b2f07242ac, Latest=b2f07242ac [Up-to-date] diff --git a/platformio/__init__.py b/platformio/__init__.py index 1ffc750da4..c139218e78 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -1,12 +1,12 @@ # Copyright (C) Ivan Kravets # See LICENSE for details. -VERSION = (0, 8, 0) +VERSION = (0, 9, 0) __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" -__description__ = ("A cross-platform code builder and library manager for " - "Arduino, MSP430, ARM") +__description__ = ("A cross-platform code builder and " + "the missing library manager") __url__ = "http://platformio.ikravets.com" __author__ = "Ivan Kravets" @@ -16,4 +16,3 @@ __copyright__ = "Copyright (C) 2014 Ivan Kravets" __apiurl__ = "http://api.platformio.ikravets.com" -__pkgmanifesturl__ = "http://dl.platformio.ikravets.com/packages/manifest.json" diff --git a/platformio/__main__.py b/platformio/__main__.py index ab1cceb3fa..92dba96761 100644 --- a/platformio/__main__.py +++ b/platformio/__main__.py @@ -1,21 +1,19 @@ # Copyright (C) Ivan Kravets # See LICENSE for details. -from os import listdir, makedirs -from os.path import getmtime, isdir, isfile, join +from os import listdir +from os.path import join from sys import exit as sys_exit -from time import time from traceback import format_exc -from click import command, MultiCommand, secho, version_option +import click -from platformio import __version__ -from platformio.commands.upgrade import get_latest_version +from platformio import __version__, maintenance from platformio.exception import PlatformioException, UnknownCLICommand -from platformio.util import get_home_dir, get_source_dir +from platformio.util import get_source_dir -class PlatformioCLI(MultiCommand): # pylint: disable=R0904 +class PlatformioCLI(click.MultiCommand): # pylint: disable=R0904 def list_commands(self, ctx): cmds = [] @@ -28,6 +26,7 @@ def list_commands(self, ctx): return cmds def get_command(self, ctx, name): + mod = None try: mod = __import__("platformio.commands." + name, None, None, ["cli"]) @@ -36,35 +35,27 @@ def get_command(self, ctx, name): return mod.cli -@command(cls=PlatformioCLI) -@version_option(__version__, prog_name="PlatformIO") -def cli(): - pass +@click.command(cls=PlatformioCLI) +@click.version_option(__version__, prog_name="PlatformIO") +@click.pass_context +def cli(ctx): + maintenance.on_platformio_start(ctx) -def autocheck_latest_version(): - check_interval = 3600 * 24 * 7 # 1 week - checkfile = join(get_home_dir(), ".pioupgrade") - if isfile(checkfile) and getmtime(checkfile) > (time() - check_interval): - return False - if not isdir(get_home_dir()): - makedirs(get_home_dir()) - with open(checkfile, "w") as f: - f.write(str(time())) - return get_latest_version() != __version__ +@cli.resultcallback() +@click.pass_context +def process_result(ctx, result): + maintenance.on_platformio_end(ctx, result) def main(): try: - if autocheck_latest_version(): - secho("\nThere is a new version of PlatformIO available.\n" - "Please upgrade it via `platformio upgrade` command.\n", - fg="yellow") - - cli() + cli(None) except Exception as e: # pylint: disable=W0703 + maintenance.on_platformio_exception(e) if isinstance(e, PlatformioException): - sys_exit("Error: " + str(e)) + click.echo("Error: " + str(e)) + sys_exit(1) else: print format_exc() diff --git a/platformio/app.py b/platformio/app.py new file mode 100644 index 0000000000..3f24617a9d --- /dev/null +++ b/platformio/app.py @@ -0,0 +1,111 @@ +# Copyright (C) Ivan Kravets +# See LICENSE for details. + +import json +from os.path import isfile, join + +from platformio import __version__ +from platformio.exception import InvalidSettingName, InvalidSettingValue +from platformio.util import get_home_dir + +DEFAULT_SETTINGS = { + "check_platformio_interval": { + "description": "Check for the new PlatformIO interval (days)", + "value": 3 + }, + "check_platforms_interval": { + "description": "Check for the platform updates interval (days)", + "value": 7 + }, + "check_libraries_interval": { + "description": "Check for the library updates interval (days)", + "value": 7 + }, + "auto_update_platforms": { + "description": "Automatically update platforms (Yes/No)", + "value": True + }, + "auto_update_libraries": { + "description": "Automatically update libraries (Yes/No)", + "value": True + }, + "enable_telemetry": { + "description": ("Shares commands, platforms and libraries usage" + " to help us make PlatformIO better (Yes/No)"), + "value": True + } +} + + +class State(object): + + def __init__(self, path=None): + self.path = path + if not self.path: + self.path = join(get_home_dir(), "appstate.json") + self._state = {} + + def __enter__(self): + try: + if isfile(self.path): + with open(self.path, "r") as fp: + self._state = json.load(fp) + except ValueError: + self._state = {} + return self._state + + def __exit__(self, type_, value, traceback): + with open(self.path, "w") as fp: + if "dev" in __version__: + json.dump(self._state, fp, indent=4) + else: + json.dump(self._state, fp) + + +def get_state_item(name, default=None): + with State() as data: + return data.get(name, default) + + +def set_state_item(name, value): + with State() as data: + data[name] = value + + +def get_setting(name): + if name not in DEFAULT_SETTINGS: + raise InvalidSettingName(name) + + with State() as data: + if "settings" in data and name in data['settings']: + return data['settings'][name] + + return DEFAULT_SETTINGS[name]['value'] + + +def set_setting(name, value): + if name not in DEFAULT_SETTINGS: + raise InvalidSettingName(name) + + defdata = DEFAULT_SETTINGS[name] + try: + if "validator" in defdata: + value = defdata['validator']() + elif (isinstance(defdata['value'], bool) + and not isinstance(value, bool)): + value = str(value).lower() in ("yes", "y", "1") + elif isinstance(defdata['value'], int): + value = int(value) + except Exception: + raise InvalidSettingValue(value, name) + + with State() as data: + if "settings" not in data: + data['settings'] = {} + data['settings'][name] = value + + +def reset_settings(): + with State() as data: + if "settings" in data: + del data['settings'] diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 07fd7725b6..5fcfbed3d1 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -11,10 +11,10 @@ break from platformio.util import get_home_dir -from os.path import isdir, join +from os.path import join -from SCons.Script import (DefaultEnvironment, Exit, SConscript, - SConscriptChdir, Variables) +from SCons.Script import (DefaultEnvironment, SConscript, SConscriptChdir, + Variables) from platformio.util import (get_lib_dir, get_pioenvs_dir, get_project_dir, get_source_dir) @@ -24,8 +24,16 @@ # allow common variables from INI file commonvars = Variables(None) commonvars.AddVariables( + ("BUILD_SCRIPT",), ("PIOENV",), ("PLATFORM",), + + # package aliases + ("PIOPACKAGE_TOOLCHAIN",), + ("PIOPACKAGE_UPLOADER",), + ("PIOPACKAGE_FRAMEWORK",), + + # options ("FRAMEWORK",), ("BUILD_FLAGS",), ("SRCBUILD_FLAGS",), @@ -46,14 +54,13 @@ toolpath=[join("$PIOBUILDER_DIR", "tools")], variables=commonvars, - PIOBUILDER_DIR=join(get_source_dir(), "builder"), + PIOHOME_DIR=get_home_dir(), PROJECT_DIR=get_project_dir(), PIOENVS_DIR=get_pioenvs_dir(), - PLATFORMIOHOME_DIR=get_home_dir(), - PLATFORM_DIR=join("$PLATFORMIOHOME_DIR", "$PLATFORM"), - PLATFORMFW_DIR=join("$PLATFORM_DIR", "frameworks", "$FRAMEWORK"), - PLATFORMTOOLS_DIR=join("$PLATFORM_DIR", "tools"), + PIOBUILDER_DIR=join(get_source_dir(), "builder"), + PIOPACKAGES_DIR=join("$PIOHOME_DIR", "packages"), + PLATFORMFW_DIR=join("$PIOPACKAGES_DIR", "$PIOPACKAGE_FRAMEWORK"), BUILD_DIR=join("$PIOENVS_DIR", "$PIOENV"), LIBSOURCE_DIRS=[ @@ -64,14 +71,10 @@ ) env = DefaultEnvironment() - -if not isdir(env['PLATFORMIOHOME_DIR']): - Exit("You haven't installed any platforms yet. Please use " - "`platformio install` command") -elif not isdir(env.subst("$PLATFORM_DIR")): - Exit("An '%s' platform hasn't been installed yet. Please use " - "`platformio install %s` command" % (env['PLATFORM'], - env['PLATFORM'])) +env.PrependENVPath( + "PATH", + env.subst(join("$PIOPACKAGES_DIR", "$PIOPACKAGE_TOOLCHAIN", "bin")) +) SConscriptChdir(0) -SConscript(env.subst(join("$PIOBUILDER_DIR", "scripts", "${PLATFORM}.py"))) +SConscript(env.subst("$BUILD_SCRIPT")) diff --git a/platformio/builder/scripts/atmelavr.py b/platformio/builder/scripts/atmelavr.py index e3806c2389..cfdd2de93e 100644 --- a/platformio/builder/scripts/atmelavr.py +++ b/platformio/builder/scripts/atmelavr.py @@ -53,13 +53,13 @@ "-mmcu=$BOARD_MCU" ], - UPLOADER=join("$PLATFORMTOOLS_DIR", "avrdude", "avrdude"), + UPLOADER=join("$PIOPACKAGES_DIR", "tool-avrdude", "avrdude"), UPLOADERFLAGS=[ "-V", # do not verify "-q", # suppress progress output "-D", # disable auto erase for flash memory "-p", "$BOARD_MCU", - "-C", join("$PLATFORMTOOLS_DIR", "avrdude", "avrdude.conf"), + "-C", join("$PIOPACKAGES_DIR", "tool-avrdude", "avrdude.conf"), "-c", "$UPLOAD_PROTOCOL", "-b", "$UPLOAD_SPEED", "-P", "$UPLOAD_PORT" diff --git a/platformio/builder/scripts/frameworks/arduino.py b/platformio/builder/scripts/frameworks/arduino.py index 18bd7ae3ca..d6f8dbf180 100644 --- a/platformio/builder/scripts/frameworks/arduino.py +++ b/platformio/builder/scripts/frameworks/arduino.py @@ -31,18 +31,19 @@ # include board variant env.VariantDir( - join("$BUILD_DIR", "variant"), + join("$BUILD_DIR", "FrameworkArduinoVariant"), join("$PLATFORMFW_DIR", "variants", BOARD_OPTIONS['build.variant']) ) env.Append( CPPDEFINES=[ + "ARDUINO_ARCH_AVR", # @TODO Should be dynamic "ARDUINO=%d" % ARDUINO_VERSION, "ARDUINO_%s" % BOARD_OPTIONS['build.board'] ] + ARDUINO_USBDEFINES, CPPPATH=[ - join("$BUILD_DIR", "core"), - join("$BUILD_DIR", "variant") + join("$BUILD_DIR", "FrameworkArduino"), + join("$BUILD_DIR", "FrameworkArduinoVariant") ] ) @@ -63,7 +64,7 @@ # libs.append(env.BuildLibrary( - join("$BUILD_DIR", "core"), + join("$BUILD_DIR", "FrameworkArduino"), join("$PLATFORMFW_DIR", "cores", BOARD_OPTIONS['build.core']) )) diff --git a/platformio/builder/scripts/frameworks/energia.py b/platformio/builder/scripts/frameworks/energia.py index e86a7b5d8e..e2bb8a531a 100644 --- a/platformio/builder/scripts/frameworks/energia.py +++ b/platformio/builder/scripts/frameworks/energia.py @@ -22,7 +22,7 @@ # include board variant env.VariantDir( - join("$BUILD_DIR", "variant"), + join("$BUILD_DIR", "FrameworkEnergiaVariant"), join("$PLATFORMFW_DIR", "variants", BOARD_OPTIONS['build.variant']) ) @@ -32,8 +32,8 @@ "ENERGIA=%d" % ENERGIA_VERSION ], CPPPATH=[ - join("$BUILD_DIR", "core"), - join("$BUILD_DIR", "variant") + join("$BUILD_DIR", "FrameworkEnergia"), + join("$BUILD_DIR", "FrameworkEnergiaVariant") ] ) @@ -60,7 +60,7 @@ # libs.append(env.BuildLibrary( - join("$BUILD_DIR", "core"), + join("$BUILD_DIR", "FrameworkEnergia"), join("$PLATFORMFW_DIR", "cores", BOARD_OPTIONS['build.core']) )) diff --git a/platformio/builder/scripts/timsp430.py b/platformio/builder/scripts/timsp430.py index cd81bce787..98ac204f63 100644 --- a/platformio/builder/scripts/timsp430.py +++ b/platformio/builder/scripts/timsp430.py @@ -51,7 +51,7 @@ "-Wl,-gc-sections,-u,main" ], - UPLOADER=join("$PLATFORMTOOLS_DIR", "mspdebug", "mspdebug"), + UPLOADER=join("$PIOPACKAGES_DIR", "tool-mspdebug", "mspdebug"), UPLOADERFLAGS=[ "$UPLOAD_PROTOCOL" if system() != "Windows" else "tilib", "--force-reset" diff --git a/platformio/builder/scripts/titiva.py b/platformio/builder/scripts/titiva.py index 8dacd75f78..046d11b0b9 100644 --- a/platformio/builder/scripts/titiva.py +++ b/platformio/builder/scripts/titiva.py @@ -71,7 +71,7 @@ "-fsingle-precision-constant" ], - UPLOADER=join("$PLATFORMTOOLS_DIR", "lm4flash", "lm4flash"), + UPLOADER=join("$PIOPACKAGES_DIR", "tool-lm4flash", "lm4flash"), UPLOADCMD="$UPLOADER $SOURCES" ) diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 19302a1a0a..3304598b12 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -14,11 +14,6 @@ def ProcessGeneral(env): if "BUILD_FLAGS" in env: env.MergeFlags(env['BUILD_FLAGS']) - env.PrependENVPath( - "PATH", - join(env.subst("$PLATFORMTOOLS_DIR"), "toolchain", "bin") - ) - if "FRAMEWORK" in env: if env['FRAMEWORK'] in ("arduino", "energia"): env.ConvertInotoCpp() @@ -72,9 +67,9 @@ def BuildDependentLibraries(env, src_dir): deplibs = env.GetDependentLibraries(src_dir) env.Append(CPPPATH=[join("$BUILD_DIR", l) for (l, _) in deplibs]) - for (libname, lsd_dir) in deplibs: + for (libname, inc_dir) in deplibs: lib = env.BuildLibrary( - join("$BUILD_DIR", libname), join(lsd_dir, libname)) + join("$BUILD_DIR", libname), inc_dir) env.Clean(libname, lib) libs.append(lib) return libs @@ -98,19 +93,24 @@ def GetDependentLibraries(env, src_dir): def ParseIncludesRecurive(env, regexp, source_file, includes): matches = regexp.findall(source_file.get_text_contents()) - for inc_name in matches: - if inc_name in includes: + for inc_fname in matches: + if inc_fname in includes: continue for lsd_dir in env['LIBSOURCE_DIRS']: lsd_dir = env.subst(lsd_dir) if not isdir(lsd_dir): continue for libname in listdir(lsd_dir): - inc_path = join(lsd_dir, libname, inc_name) - if not isfile(inc_path): + inc_dir = join(lsd_dir, libname) + inc_file = join(inc_dir, inc_fname) + if not isfile(inc_file): + # if source code is in "src" dir + inc_dir = join(lsd_dir, libname, "src") + inc_file = join(inc_dir, inc_fname) + if not isfile(inc_file): continue - includes[inc_name] = (len(includes) + 1, libname, lsd_dir) - env.ParseIncludesRecurive(regexp, env.File(inc_path), includes) + includes[inc_fname] = (len(includes) + 1, libname, inc_dir) + env.ParseIncludesRecurive(regexp, env.File(inc_file), includes) def VariantDirRecursive(env, variant_dir, src_dir, duplicate=True): diff --git a/platformio/commands/init.py b/platformio/commands/init.py index 418783b2ca..8c540e54d5 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -1,30 +1,58 @@ # Copyright (C) Ivan Kravets # See LICENSE for details. -from os import makedirs +from os import getcwd, makedirs from os.path import isdir, isfile, join from shutil import copyfile -from click import command, secho +import click from platformio.exception import ProjectInitialized from platformio.util import get_source_dir -@command("init", short_help="Initialize new PlatformIO based project") -def cli(): +@click.command("init", short_help="Initialize new PlatformIO based project") +@click.option("--project-dir", "-d", default=getcwd(), + type=click.Path(exists=True, file_okay=False, dir_okay=True, + writable=True, resolve_path=True)) +def cli(project_dir): - if isfile("platformio.ini") and isdir("src"): + project_file = join(project_dir, "platformio.ini") + src_dir = join(project_dir, "src") + lib_dir = join(project_dir, "lib") + if all([isfile(project_file), isdir(src_dir), isdir(lib_dir)]): raise ProjectInitialized() - for d in ("lib", "src"): - if not isdir(d): - makedirs(d) - if not isfile("platformio.ini"): - copyfile(join(get_source_dir(), "projectconftpl.ini"), - "platformio.ini") - secho("Project has been initialized!\n" - "Please put your source code to `src` directory, " - "external libraries to `lib` and " - "setup environments in `platformio.ini` file.\n" - "Then process project with `platformio run` command.", - fg="green") + + if project_dir == getcwd(): + click.secho("The current working directory", fg="yellow", nl=False) + click.secho(" %s " % project_dir, fg="blue", nl=False) + click.secho( + "will be used for the new project.\n" + "You can specify another project directory via\n" + "`platformio init -d %PATH_TO_PROJECT_DIR%` command.\n", + fg="yellow" + ) + + click.echo("The next files/directories will be created in %s" % + click.style(project_dir, fg="blue")) + click.echo("%s - Project Configuration File" % + click.style("platformio.ini", fg="cyan")) + click.echo("%s - a source directory. Put your source code here" % + click.style("src", fg="cyan")) + click.echo("%s - a directory for the project specific libraries" % + click.style("lib", fg="cyan")) + + if click.confirm("Do you want to continue?"): + for d in (src_dir, lib_dir): + if not isdir(d): + makedirs(d) + if not isfile(project_file): + copyfile(join(get_source_dir(), "projectconftpl.ini"), + project_file) + click.secho( + "Project has been successfully initialized!\n" + "Now you can process it with `platformio run` command.", + fg="green" + ) + else: + click.secho("Aborted by user", fg="red") diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index 0d6d4f1f85..c2350bb489 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -8,7 +8,6 @@ from platformio.libmanager import LibraryManager from platformio.util import get_api_result, get_lib_dir - LIBLIST_TPL = ("[{id:^14}] {name:<25} {compatibility:<30} " "\"{authornames}\": {description}") @@ -47,8 +46,11 @@ def cli(): @click.option("-k", "--keyword", multiple=True) @click.option("-f", "--framework", multiple=True) @click.option("-p", "--platform", multiple=True) -@click.argument("query") +@click.argument("query", required=False) def lib_search(query, **filters): + if not query: + query = "" + for key, values in filters.iteritems(): for value in values: query += ' %s:"%s"' % (key, value) @@ -77,15 +79,12 @@ def lib_search(query, **filters): @cli.command("install", short_help="Install library") -@click.argument("ids", type=click.INT, nargs=-1, metavar="[LIBRARY_ID]") +@click.argument("libid", type=click.INT, nargs=-1, metavar="[LIBRARY_ID]") @click.option("-v", "--version") -def lib_install_cli(ids, version): - lib_install(ids, version) - - -def lib_install(ids, version=None): +@click.pass_context +def lib_install(ctx, libid, version): lm = LibraryManager(get_lib_dir()) - for id_ in ids: + for id_ in libid: click.echo( "Installing library [ %s ]:" % click.style(str(id_), fg="green")) try: @@ -104,7 +103,7 @@ def lib_install(ids, version=None): _dependencies = [_dependencies] for item in _dependencies: try: - lib_install_dependency(item) + lib_install_dependency(ctx, item) except AssertionError: raise LibInstallDependencyError(str(item)) @@ -112,7 +111,7 @@ def lib_install(ids, version=None): click.secho("Already installed", fg="yellow") -def lib_install_dependency(data): +def lib_install_dependency(ctx, data): assert isinstance(data, dict) query = [] for key in data.keys(): @@ -127,18 +126,14 @@ def lib_install_dependency(data): result = get_api_result("/lib/search", dict(query=" ".join(query))) assert result['total'] == 1 - lib_install([result['items'][0]['id']]) + ctx.invoke(lib_install, libid=[result['items'][0]['id']]) @cli.command("uninstall", short_help="Uninstall libraries") -@click.argument("ids", type=click.INT, nargs=-1) -def lib_uninstall_cli(ids): - lib_uninstall(ids) - - -def lib_uninstall(ids): +@click.argument("libid", type=click.INT, nargs=-1) +def lib_uninstall(libid): lm = LibraryManager(get_lib_dir()) - for id_ in ids: + for id_ in libid: info = lm.get_info(id_) if lm.uninstall(id_): click.secho("The library #%s '%s' has been successfully " @@ -193,15 +188,10 @@ def lib_show(libid): @cli.command("update", short_help="Update installed libraries") -def lib_update(): +@click.pass_context +def lib_update(ctx): lm = LibraryManager(get_lib_dir()) - - lib_ids = [str(item['id']) for item in lm.get_installed().values()] - if not lib_ids: - return - - versions = get_api_result("/lib/version/" + str(",".join(lib_ids))) - for id_ in lib_ids: + for id_, latest_version in (lm.get_latest_versions() or {}).items(): info = lm.get_info(int(id_)) click.echo("Updating [ %s ] %s library:" % ( @@ -209,8 +199,6 @@ def lib_update(): click.style(info['name'], fg="cyan"))) current_version = info['version'] - latest_version = versions[id_] - if latest_version is None: click.secho("Unknown library", fg="red") continue @@ -224,8 +212,8 @@ def lib_update(): else: click.echo("[%s]" % (click.style("Out-of-date", fg="red"))) - lib_uninstall([int(id_)]) - lib_install([int(id_)]) + ctx.invoke(lib_uninstall, libid=[int(id_)]) + ctx.invoke(lib_install, libid=[int(id_)]) @cli.command("register", short_help="Register new library") diff --git a/platformio/commands/list.py b/platformio/commands/list.py index 990429bfdf..7b00e22629 100644 --- a/platformio/commands/list.py +++ b/platformio/commands/list.py @@ -3,14 +3,19 @@ from click import command, echo, style -from platformio.pkgmanager import PackageManager +from platformio.platforms.base import PlatformFactory @command("list", short_help="List installed platforms") def cli(): - for name, pkgs in PackageManager.get_installed().items(): + installed_platforms = PlatformFactory.get_platforms( + installed=True).keys() + installed_platforms.sort() + + for platform in installed_platforms: + p = PlatformFactory().newPlatform(platform) echo("{name:<20} with packages: {pkgs}".format( - name=style(name, fg="cyan"), - pkgs=", ".join(pkgs.keys()) + name=style(p.get_name(), fg="cyan"), + pkgs=", ".join(p.get_installed_packages()) )) diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 4ed95befcf..400a6f3a4a 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -3,6 +3,7 @@ from click import command, echo, option, secho, style +from platformio import telemetry from platformio.exception import (InvalidEnvName, ProjectEnvsNotAvaialable, UndefinedEnvPlatform, UnknownEnvNames) from platformio.platforms.base import PlatformFactory @@ -56,6 +57,8 @@ def cli(environment, target, upload_port): if not config.has_option(section, "platform"): raise UndefinedEnvPlatform(envname) + telemetry.on_run_environment(config.items(section), envtargets) + p = PlatformFactory().newPlatform(config.get(section, "platform")) result = p.run(variables, envtargets) secho(result['out'], fg="green") diff --git a/platformio/commands/search.py b/platformio/commands/search.py index 2457b05e3c..ec814be411 100644 --- a/platformio/commands/search.py +++ b/platformio/commands/search.py @@ -4,19 +4,21 @@ from click import argument, command, echo, style from platformio.platforms.base import PlatformFactory -from platformio.util import get_platforms @command("search", short_help="Search for development platforms") -@argument("query") +@argument("query", required=False) def cli(query): - for platform in get_platforms(): + for platform in PlatformFactory.get_platforms().keys(): p = PlatformFactory().newPlatform(platform) name = p.get_name() shinfo = p.get_short_info() + if query == "all": + query = "" + search_data = "%s %s" % (name, shinfo) - if query != "all" and query.lower() not in search_data.lower(): + if query and query.lower() not in search_data.lower(): continue echo("{name:<20} - {info}".format(name=style(name, fg="cyan"), diff --git a/platformio/commands/settings.py b/platformio/commands/settings.py new file mode 100644 index 0000000000..f239559f8e --- /dev/null +++ b/platformio/commands/settings.py @@ -0,0 +1,68 @@ +# Copyright (C) Ivan Kravets +# See LICENSE for details. + +import click + +from platformio import app + + +@click.group(short_help="Manage PlatformIO settings") +def cli(): + pass + + +@cli.command("get", short_help="Get existing setting/-s") +@click.argument("name", required=False) +def settings_get(name): + + list_tpl = "{name:<40} {value:<35} {description}" + + click.echo(list_tpl.format( + name=click.style("Name", fg="cyan"), + value=(click.style("Value", fg="green") + + click.style(" [Default]", fg="yellow")), + description="Description" + )) + click.echo("-" * 90) + + for _name, _data in sorted(app.DEFAULT_SETTINGS.items()): + if name and name != _name: + continue + _value = app.get_setting(_name) + + _value_str = str(_value) + if isinstance(_value, bool): + _value_str = "Yes" if _value else "No" + _value_str = click.style(_value_str, fg="green") + + if _value != _data['value']: + _defvalue_str = str(_data['value']) + if isinstance(_data['value'], bool): + _defvalue_str = "Yes" if _data['value'] else "No" + _value_str += click.style(" [%s]" % _defvalue_str, fg="yellow") + else: + _value_str += click.style(" ", fg="yellow") + + click.echo(list_tpl.format( + name=click.style(_name, fg="cyan"), + value=_value_str, + description=_data['description'] + )) + + +@cli.command("set", short_help="Set new value for the setting") +@click.argument("name") +@click.argument("value") +@click.pass_context +def settings_set(ctx, name, value): + app.set_setting(name, value) + click.secho("The new value for the setting has been set!", fg="green") + ctx.invoke(settings_get, name=name) + + +@cli.command("reset", short_help="Reset settings to default") +@click.pass_context +def settings_reset(ctx): + app.reset_settings() + click.secho("The settings have been reseted!", fg="green") + ctx.invoke(settings_get) diff --git a/platformio/commands/show.py b/platformio/commands/show.py index 38cb4212fb..5d2a9d8342 100644 --- a/platformio/commands/show.py +++ b/platformio/commands/show.py @@ -1,7 +1,7 @@ # Copyright (C) Ivan Kravets # See LICENSE for details. -from os.path import join +from datetime import datetime from click import argument, command, echo, style @@ -13,20 +13,25 @@ @command("show", short_help="Show details about installed platforms") @argument("platform") def cli(platform): - p = PlatformFactory().newPlatform(platform) - if platform not in PackageManager.get_installed(): + + installed_platforms = PlatformFactory.get_platforms( + installed=True).keys() + + if platform not in installed_platforms: raise PlatformNotInstalledYet(platform) - # print info about platform + p = PlatformFactory().newPlatform(platform) echo("{name:<20} - {info}".format(name=style(p.get_name(), fg="cyan"), info=p.get_short_info())) - pm = PackageManager(platform) - for name, data in pm.get_installed(platform).items(): + installed_packages = PackageManager.get_installed() + for name in p.get_installed_packages(): + data = installed_packages[name] pkgalias = p.get_pkg_alias(name) echo("----------") echo("Package: %s" % style(name, fg="yellow")) if pkgalias: echo("Alias: %s" % pkgalias) - echo("Location: %s" % join(pm.get_platform_dir(), data['path'])) echo("Version: %d" % int(data['version'])) + echo("Installed: %s" % datetime.fromtimestamp( + data['time']).strftime("%Y-%m-%d %H:%M:%S")) diff --git a/platformio/commands/uninstall.py b/platformio/commands/uninstall.py index 7276591130..7d25eabb1f 100644 --- a/platformio/commands/uninstall.py +++ b/platformio/commands/uninstall.py @@ -3,8 +3,6 @@ from click import argument, command, secho -from platformio.exception import PlatformNotInstalledYet -from platformio.pkgmanager import PackageManager from platformio.platforms.base import PlatformFactory @@ -13,10 +11,6 @@ def cli(platforms): for platform in platforms: - - if platform not in PackageManager.get_installed(): - raise PlatformNotInstalledYet(platform) - p = PlatformFactory().newPlatform(platform) if p.uninstall(): secho("The platform '%s' has been successfully " diff --git a/platformio/commands/update.py b/platformio/commands/update.py index 8fad8523ab..2ecd8d3f71 100644 --- a/platformio/commands/update.py +++ b/platformio/commands/update.py @@ -3,14 +3,17 @@ from click import command, echo, style -from platformio.pkgmanager import PackageManager from platformio.platforms.base import PlatformFactory @command("update", short_help="Update installed platforms") def cli(): - for platform in PackageManager.get_installed().keys(): + installed_platforms = PlatformFactory.get_platforms( + installed=True).keys() + installed_platforms.sort() + + for platform in installed_platforms: echo("\nPlatform %s" % style(platform, fg="cyan")) echo("--------") p = PlatformFactory().newPlatform(platform) diff --git a/platformio/downloader.py b/platformio/downloader.py index 3887af3cb4..5b58fdb734 100644 --- a/platformio/downloader.py +++ b/platformio/downloader.py @@ -67,17 +67,17 @@ def verify(self, sha1=None): dlsha1 = None try: - res = check_output(["sha1sum", self._destination]) - dlsha1 = res[:40] + dlsha1 = check_output(["sha1sum", self._destination]) except OSError: try: - res = check_output(["shasum", "-a", "1", self._destination]) - dlsha1 = res[:40] + dlsha1 = check_output(["shasum", "-a", "1", self._destination]) except OSError: pass - if dlsha1 and sha1 != dlsha1: - raise FDSHASumMismatch(dlsha1, self._fname, sha1) + if dlsha1: + dlsha1 = dlsha1[1:41] if dlsha1.startswith("\\") else dlsha1[:40] + if sha1 != dlsha1: + raise FDSHASumMismatch(dlsha1, self._fname, sha1) def _preserve_filemtime(self, lmdate): timedata = parsedate_tz(lmdate) diff --git a/platformio/exception.py b/platformio/exception.py index e0b508e599..63cb3aa044 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -124,3 +124,23 @@ class LibNotInstalledError(PlatformioException): class LibInstallDependencyError(PlatformioException): MESSAGE = "Error has been occurred for library dependency '%s'" + + +class BuildScriptNotFound(PlatformioException): + + MESSAGE = "Invalid path '%s' to build script" + + +class InvalidSettingName(PlatformioException): + + MESSAGE = "Invalid setting with the name '%s'" + + +class InvalidSettingValue(PlatformioException): + + MESSAGE = "Invalid value '%s' for the setting '%s'" + + +class UpgraderFailed(PlatformioException): + + MESSAGE = "An error occurred while upgrading PlatformIO" diff --git a/platformio/libmanager.py b/platformio/libmanager.py index 72657bf709..b669a74ba9 100644 --- a/platformio/libmanager.py +++ b/platformio/libmanager.py @@ -8,6 +8,7 @@ from shutil import rmtree from tempfile import gettempdir +from platformio import telemetry from platformio.downloader import FileDownloader from platformio.exception import LibAlreadyInstalledError, LibNotInstalledError from platformio.unpacker import FileUnpacker @@ -44,6 +45,20 @@ def get_installed(self): items[dirname] = json.load(f) return items + def get_latest_versions(self): + lib_ids = [str(item['id']) for item in self.get_installed().values()] + if not lib_ids: + return None + return get_api_result("/lib/version/" + str(",".join(lib_ids))) + + def get_outdated(self): + outdated = [] + for id_, latest_version in (self.get_latest_versions() or {}).items(): + info = self.get_info(int(id_)) + if latest_version != info['version']: + outdated.append(info['name']) + return outdated + def get_info(self, id_): for item in self.get_installed().values(): if "id" in item and item['id'] == id_: @@ -76,11 +91,21 @@ def install(self, id_, version=None): info = self.get_info(id_) rename(tmplib_dir, join(self.lib_dir, "%s_ID%d" % ( re.sub(r"[^\da-z]+", "_", info['name'], flags=re.I), id_))) + + telemetry.on_event( + category="LibraryManager", action="Install", + label="#%d %s" % (id_, info['name']) + ) + return True def uninstall(self, id_): for libdir, item in self.get_installed().iteritems(): if "id" in item and item['id'] == id_: rmtree(join(self.lib_dir, libdir)) + telemetry.on_event( + category="LibraryManager", action="Uninstall", + label="#%d %s" % (id_, item['name']) + ) return True raise LibNotInstalledError(id_) diff --git a/platformio/maintenance.py b/platformio/maintenance.py new file mode 100644 index 0000000000..63e1966446 --- /dev/null +++ b/platformio/maintenance.py @@ -0,0 +1,187 @@ +# Copyright (C) Ivan Kravets +# See LICENSE for details. + +import re +from os import remove +from os.path import isdir, isfile, join +from shutil import rmtree +from time import time + +import click + +from platformio import __version__, app, telemetry +from platformio.commands.install import cli as cli_install +from platformio.commands.lib import lib_update as cli_libraries_update +from platformio.commands.update import cli as cli_platforms_update +from platformio.commands.upgrade import get_latest_version +from platformio.exception import UpgraderFailed +from platformio.libmanager import LibraryManager +from platformio.platforms.base import PlatformFactory +from platformio.util import get_home_dir, get_lib_dir + + +def on_platformio_start(ctx): + telemetry.on_command(ctx) + after_upgrade(ctx) + check_platformio_upgrade() + check_internal_updates(ctx, "platforms") + check_internal_updates(ctx, "libraries") + + +def on_platformio_end(ctx, result): # pylint: disable=W0613 + pass + + +def on_platformio_exception(e): + telemetry.on_exception(e) + + +class Upgrader(object): + + def __init__(self, from_version, to_version): + self.from_version = self.version_to_int(from_version) + self.to_version = self.version_to_int(to_version) + + @staticmethod + def version_to_int(version): + return int(re.sub(r"[^\d]+", "", version)) + + def run(self, ctx): + if self.from_version > self.to_version: + return True + + result = [True] + for v in (90, ): + if self.from_version >= v: + continue + result.append(getattr(self, "_upgrade_to_%d" % v)(ctx)) + + return all(result) + + def _upgrade_to_90(self, ctx): # pylint: disable=R0201 + prev_platforms = [] + + # remove platform's folder (obsoleted package structure) + for name in PlatformFactory.get_platforms().keys(): + pdir = join(get_home_dir(), name) + if not isdir(pdir): + continue + prev_platforms.append(name) + rmtree(pdir) + + # remove unused files + for fname in (".pioupgrade", "installed.json"): + if isfile(join(get_home_dir(), fname)): + remove(join(get_home_dir(), fname)) + + if prev_platforms: + ctx.invoke(cli_install, platforms=prev_platforms) + + return True + + +def after_upgrade(ctx): + if app.get_state_item("last_version", None) == __version__: + return + + # promotion + click.echo("\nIf 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/platformiotool", fg="blue")) + ) + click.echo("- %s us a star on GitHub > %s" % ( + click.style("give", fg="cyan"), + click.style("https://github.com/ivankravets/platformio", fg="blue") + )) + click.secho("Thanks a lot!\n", fg="green", blink=True) + + if not isdir(get_home_dir()): + return + + click.secho("Please wait while upgrading PlatformIO ...", + fg="yellow") + + last_version = app.get_state_item("last_version", "0.0.0") + u = Upgrader(last_version, __version__) + if u.run(ctx): + app.set_state_item("last_version", __version__) + click.secho("PlatformIO has been successfully upgraded to %s!\n" % + __version__, fg="green") + + telemetry.on_event(category="Auto", action="Upgrade", + label="%s > %s" % (last_version, __version__)) + else: + raise UpgraderFailed() + click.echo("") + + +def check_platformio_upgrade(): + last_check = app.get_state_item("last_check", {}) + interval = int(app.get_setting("check_platformio_interval")) * 3600 * 24 + if (time() - interval) < last_check.get("platformio_upgrade", 0): + return + + last_check['platformio_upgrade'] = int(time()) + app.set_state_item("last_check", last_check) + + latest_version = get_latest_version() + if (latest_version == __version__ or + Upgrader.version_to_int(latest_version) < + Upgrader.version_to_int(__version__)): + return + + click.secho("There is a new version %s of PlatformIO available.\n" + "Please upgrade it via " % latest_version, + fg="yellow", nl=False) + click.secho("`platformio upgrade`", fg="cyan", nl=False) + click.secho(" command.\nChanges: ", fg="yellow", nl=False) + click.secho("http://docs.platformio.ikravets.com/en/latest/history.html\n", + fg="blue") + + +def check_internal_updates(ctx, what): + last_check = app.get_state_item("last_check", {}) + interval = int(app.get_setting("check_%s_interval" % what)) * 3600 * 24 + if (time() - interval) < last_check.get(what + "_update", 0): + return + + last_check[what + '_update'] = int(time()) + app.set_state_item("last_check", last_check) + + outdated_items = [] + if what == "platforms": + for platform in PlatformFactory.get_platforms(installed=True).keys(): + p = PlatformFactory().newPlatform(platform) + if p.is_outdated(): + outdated_items.append(platform) + elif what == "libraries": + lm = LibraryManager(get_lib_dir()) + outdated_items = lm.get_outdated() + + if not outdated_items: + return + + click.secho("There are the new updates for %s (%s)" % + (what, ", ".join(outdated_items)), fg="yellow") + + if not app.get_setting("auto_update_" + what): + click.secho("Please update them via ", fg="yellow", nl=False) + click.secho("`platformio %supdate`" % + ("lib " if what == "libraries" else ""), + fg="cyan", nl=False) + click.secho(" command.\n", fg="yellow") + else: + click.secho("Please wait while updating %s ..." % what, fg="yellow") + if what == "platforms": + ctx.invoke(cli_platforms_update) + elif what == "libraries": + ctx.invoke(cli_libraries_update) + click.echo() + + telemetry.on_event(category="Auto", action="Update", + label=what.title()) diff --git a/platformio/pkgmanager.py b/platformio/pkgmanager.py index 2bdffff093..462f02b0a4 100644 --- a/platformio/pkgmanager.py +++ b/platformio/pkgmanager.py @@ -1,40 +1,37 @@ # Copyright (C) Ivan Kravets # See LICENSE for details. -import json from os import makedirs, remove -from os.path import isdir, isfile, join +from os.path import isdir, join from shutil import rmtree +from time import time from click import echo, secho, style -from requests import get -from requests.utils import default_user_agent -from platformio import __pkgmanifesturl__, __version__ +from platformio import telemetry +from platformio.app import get_state_item, set_state_item from platformio.downloader import FileDownloader from platformio.exception import (InvalidPackageVersion, NonSystemPackage, UnknownPackage) from platformio.unpacker import FileUnpacker -from platformio.util import get_home_dir, get_systype +from platformio.util import get_api_result, get_home_dir, get_systype class PackageManager(object): - DBFILE_PATH = join(get_home_dir(), "installed.json") + def __init__(self): + self._package_dir = join(get_home_dir(), "packages") + if not isdir(self._package_dir): + makedirs(self._package_dir) + assert isdir(self._package_dir) - def __init__(self, platform_name): - self._platform_name = platform_name - - @staticmethod - def get_manifest(): + @classmethod + def get_manifest(cls): try: - return PackageManager._cached_manifest + return cls._cached_manifest except AttributeError: - headers = {"User-Agent": "PlatformIO/%s %s" % ( - __version__, default_user_agent())} - PackageManager._cached_manifest = get(__pkgmanifesturl__, - headers=headers).json() - return PackageManager._cached_manifest + cls._cached_manifest = get_api_result("/packages") + return cls._cached_manifest @staticmethod def download(url, dest_dir, sha1=None): @@ -49,20 +46,18 @@ def unpack(pkgpath, dest_dir): return fu.start() @staticmethod - def get_installed(platform=None): - data = {} - if isfile(PackageManager.DBFILE_PATH): - with open(PackageManager.DBFILE_PATH) as fp: - data = json.load(fp) - return data.get(platform, None) if platform else data + def get_installed(): + return get_state_item("installed_packages", {}) - def get_platform_dir(self): - return join(get_home_dir(), self._platform_name) + def get_outdated(self): + outdated = [] + for name, data in self.get_installed().items(): + if data['version'] != self.get_info(name)['version']: + outdated.append(name) + return outdated def is_installed(self, name): - installed = self.get_installed() - return (self._platform_name in installed and name in - installed[self._platform_name]) + return name in self.get_installed() def get_info(self, name, version=None): manifest = self.get_manifest() @@ -84,35 +79,47 @@ def get_info(self, name, version=None): else: return sorted(builds, key=lambda s: s['version'])[-1] - def install(self, name, path): + def install(self, name): echo("Installing %s package:" % style(name, fg="cyan")) if self.is_installed(name): secho("Already installed", fg="yellow") - return + return False info = self.get_info(name) - pkg_dir = join(self.get_platform_dir(), path) + pkg_dir = join(self._package_dir, name) if not isdir(pkg_dir): makedirs(pkg_dir) dlpath = self.download(info['url'], pkg_dir, info['sha1']) if self.unpack(dlpath, pkg_dir): - self._register(name, info['version'], path) + self._register(name, info['version']) # remove archive remove(dlpath) - def uninstall(self, name, path): + telemetry.on_event( + category="PackageManager", action="Install", label=name) + + def uninstall(self, name): echo("Uninstalling %s package: \t" % style(name, fg="cyan"), nl=False) - rmtree(join(self.get_platform_dir(), path)) + + if not self.is_installed(name): + secho("Not installed", fg="yellow") + return False + + rmtree(join(self._package_dir, name)) self._unregister(name) echo("[%s]" % style("OK", fg="green")) + # report usage + telemetry.on_event( + category="PackageManager", action="Uninstall", label=name) + def update(self, name): echo("Updating %s package:" % style(name, fg="yellow")) - installed = self.get_installed(self._platform_name) + installed = self.get_installed() current_version = installed[name]['version'] latest_version = self.get_info(name)['version'] @@ -125,36 +132,21 @@ def update(self, name): else: echo("[%s]" % (style("Out-of-date", fg="red"))) - self.uninstall(name, installed[name]['path']) - self.install(name, installed[name]['path']) + self.uninstall(name) + self.install(name) - def register_platform(self, name): - data = self.get_installed() - if name not in data: - data[name] = {} - self._update_db(data) - return data + telemetry.on_event( + category="PackageManager", action="Update", label=name) - def unregister_platform(self, name): + def _register(self, name, version): data = self.get_installed() - del data[name] - self._update_db(data) - - def _register(self, name, version, path): - data = self.get_installed() - if self._platform_name not in data: - data = self.register_platform(self._platform_name) - data[self._platform_name][name] = { + data[name] = { "version": version, - "path": path + "time": int(time()) } - self._update_db(data) + set_state_item("installed_packages", data) def _unregister(self, name): data = self.get_installed() - del data[self._platform_name][name] - self._update_db(data) - - def _update_db(self, data): - with open(self.DBFILE_PATH, "w") as fp: - json.dump(data, fp) + del data[name] + set_state_item("installed_packages", data) diff --git a/platformio/platforms/atmelavr.py b/platformio/platforms/atmelavr.py index 4ba6e1173e..360b3d1029 100644 --- a/platformio/platforms/atmelavr.py +++ b/platformio/platforms/atmelavr.py @@ -1,8 +1,6 @@ # Copyright (C) Ivan Kravets # See LICENSE for details. -from os.path import join - from platformio.platforms.base import BasePlatform @@ -15,26 +13,21 @@ class AtmelavrPlatform(BasePlatform): PACKAGES = { "toolchain-atmelavr": { - "path": join("tools", "toolchain"), "alias": "toolchain", "default": True }, "tool-avrdude": { - "path": join("tools", "avrdude"), "alias": "uploader", "default": True }, "framework-arduinoavr": { - "path": join("frameworks", "arduino"), + "alias": "framework", "default": True } } - def get_name(self): - return "atmelavr" - def after_run(self, result): # fix STDERR "flash written" for avrdude if "flash written" in result['err']: diff --git a/platformio/platforms/base.py b/platformio/platforms/base.py index cbca3fea0e..03ef4b38de 100644 --- a/platformio/platforms/base.py +++ b/platformio/platforms/base.py @@ -1,29 +1,76 @@ # Copyright (C) Ivan Kravets # See LICENSE for details. -from os.path import join -from shutil import rmtree +from imp import load_source +from os import listdir +from os.path import isdir, isfile, join -from platformio.exception import UnknownPackage, UnknownPlatform +from platformio.app import get_state_item, set_state_item +from platformio.exception import (BuildScriptNotFound, PlatformNotInstalledYet, + UnknownPackage, UnknownPlatform) from platformio.pkgmanager import PackageManager -from platformio.util import exec_command, get_platforms, get_source_dir +from platformio.util import exec_command, get_home_dir, get_source_dir class PlatformFactory(object): @staticmethod - def newPlatform(name): - clsname = "%sPlatform" % name.title() + def get_clsname(name): + return "%sPlatform" % name.title() + + @staticmethod + def load_module(name, path): + module = None try: - assert name in get_platforms() - mod = __import__("platformio.platforms." + name.lower(), - None, None, [clsname]) - except (AssertionError, ImportError): + module = load_source( + "platformio.platforms.%s" % name, path) + except ImportError: + raise UnknownPlatform(name) + return module + + @classmethod + def get_platforms(cls, installed=False): + platforms = {} + for d in (get_home_dir(), get_source_dir()): + pdir = join(d, "platforms") + if not isdir(pdir): + continue + for p in listdir(pdir): + if p in ("__init__.py", "base.py") or not p.endswith(".py"): + continue + name = p[:-3] + path = join(pdir, p) + try: + isplatform = hasattr( + cls.load_module(name, path), + cls.get_clsname(name) + ) + if isplatform: + platforms[name] = path + except UnknownPlatform: + pass + + if not installed: + return platforms + + installed_platforms = {} + for name in get_state_item("installed_platforms", []): + if name in platforms: + installed_platforms[name] = platforms[name] + return installed_platforms + + @classmethod + def newPlatform(cls, name): + platforms = cls.get_platforms() + if name not in platforms: raise UnknownPlatform(name) - obj = getattr(mod, clsname)() - assert isinstance(obj, BasePlatform) - return obj + _instance = getattr( + cls.load_module(name, platforms[name]), + cls.get_clsname(name) + )() + assert isinstance(_instance, BasePlatform) + return _instance class BasePlatform(object): @@ -31,6 +78,13 @@ class BasePlatform(object): PACKAGES = {} def get_name(self): + return self.__class__.__name__[:-8].lower() + + def get_build_script(self): + builtin = join(get_source_dir(), "builder", "scripts", "%s.py" % + self.get_name()) + if isfile(builtin): + return builtin raise NotImplementedError() def get_short_info(self): @@ -40,6 +94,9 @@ def get_short_info(self): else: raise NotImplementedError() + def get_packages(self): + return self.PACKAGES + def get_pkg_alias(self, pkgname): return self.PACKAGES[pkgname].get("alias", None) @@ -47,62 +104,116 @@ def pkg_aliases_to_names(self, aliases): names = [] for alias in aliases: name = alias - # lookup by packages alias - if name not in self.PACKAGES: - for _name, _opts in self.PACKAGES.items(): - if _opts.get("alias", None) == alias: - name = _name - break + # lookup by package aliases + for _name, _opts in self.get_packages().items(): + if _opts.get("alias", None) == alias: + name = _name + break names.append(name) return names + def get_installed_packages(self): + pm = PackageManager() + return [n for n in self.get_packages().keys() if pm.is_installed(n)] + def install(self, with_packages, without_packages, skip_default_packages): with_packages = set(self.pkg_aliases_to_names(with_packages)) without_packages = set(self.pkg_aliases_to_names(without_packages)) upkgs = with_packages | without_packages - ppkgs = set(self.PACKAGES.keys()) + ppkgs = set(self.get_packages().keys()) if not upkgs.issubset(ppkgs): raise UnknownPackage(", ".join(upkgs - ppkgs)) requirements = [] - for name, opts in self.PACKAGES.items(): + for name, opts in self.get_packages().items(): if name in without_packages: continue elif (name in with_packages or (not skip_default_packages and opts['default'])): - requirements.append((name, opts['path'])) + requirements.append(name) + + pm = PackageManager() + for name in requirements: + pm.install(name) + + # register installed platform + data = get_state_item("installed_platforms", []) + if self.get_name() not in data: + data.append(self.get_name()) + set_state_item("installed_platforms", data) - pm = PackageManager(self.get_name()) - for (package, path) in requirements: - pm.install(package, path) return len(requirements) def uninstall(self): platform = self.get_name() - pm = PackageManager(platform) + installed_platforms = PlatformFactory.get_platforms( + installed=True).keys() - for package, data in pm.get_installed(platform).items(): - pm.uninstall(package, data['path']) + if platform not in installed_platforms: + raise PlatformNotInstalledYet(platform) + + deppkgs = set() + for item in installed_platforms: + if item == platform: + continue + p = PlatformFactory().newPlatform(item) + deppkgs = deppkgs.union(set(p.get_packages().keys())) + + pm = PackageManager() + for name in self.get_packages().keys(): + if not pm.is_installed(name) or name in deppkgs: + continue + pm.uninstall(name) + + # unregister installed platform + installed_platforms.remove(platform) + set_state_item("installed_platforms", installed_platforms) - pm.unregister_platform(platform) - rmtree(pm.get_platform_dir()) return True def update(self): - platform = self.get_name() - pm = PackageManager(platform) - for package in pm.get_installed(platform).keys(): - pm.update(package) + pm = PackageManager() + for name in self.get_installed_packages(): + pm.update(name) + + def is_outdated(self): + pm = PackageManager() + obsolated = pm.get_outdated() + return not set(self.get_packages().keys()).isdisjoint(set(obsolated)) def run(self, variables, targets): assert isinstance(variables, list) assert isinstance(targets, list) + installed_platforms = PlatformFactory.get_platforms( + installed=True).keys() + installed_packages = PackageManager.get_installed() + + if self.get_name() not in installed_platforms: + raise PlatformNotInstalledYet(self.get_name()) + if "clean" in targets: targets.remove("clean") targets.append("-c") + if not any([v.startswith("BUILD_SCRIPT=") for v in variables]): + variables.append("BUILD_SCRIPT=%s" % self.get_build_script()) + + for v in variables: + if not v.startswith("BUILD_SCRIPT="): + continue + _, path = v.split("=", 2) + if not isfile(path): + raise BuildScriptNotFound(path) + + # append aliases of installed packages + for name, options in self.get_packages().items(): + if name not in installed_packages: + continue + variables.append( + "PIOPACKAGE_%s=%s" % (options['alias'].upper(), name)) + result = exec_command([ "scons", "-Q", diff --git a/platformio/platforms/timsp430.py b/platformio/platforms/timsp430.py index 7058af1691..51894687ef 100644 --- a/platformio/platforms/timsp430.py +++ b/platformio/platforms/timsp430.py @@ -1,8 +1,6 @@ # Copyright (C) Ivan Kravets # See LICENSE for details. -from os.path import join - from platformio.platforms.base import BasePlatform @@ -15,22 +13,17 @@ class Timsp430Platform(BasePlatform): PACKAGES = { "toolchain-timsp430": { - "path": join("tools", "toolchain"), "alias": "toolchain", "default": True }, "tool-mspdebug": { - "path": join("tools", "mspdebug"), "alias": "uploader", "default": True }, "framework-energiamsp430": { - "path": join("frameworks", "energia"), + "alias": "framework", "default": True } } - - def get_name(self): - return "timsp430" diff --git a/platformio/platforms/titiva.py b/platformio/platforms/titiva.py index ed89cb4465..2b34869f95 100644 --- a/platformio/platforms/titiva.py +++ b/platformio/platforms/titiva.py @@ -1,8 +1,6 @@ # Copyright (C) Ivan Kravets # See LICENSE for details. -from os.path import join - from platformio.platforms.base import BasePlatform @@ -15,22 +13,17 @@ class TitivaPlatform(BasePlatform): PACKAGES = { "toolchain-gccarmnoneeabi": { - "path": join("tools", "toolchain"), "alias": "toolchain", "default": True }, "tool-lm4flash": { - "path": join("tools", "lm4flash"), "alias": "uploader", "default": True }, "framework-energiativa": { - "path": join("frameworks", "energia"), + "alias": "framework", "default": True } } - - def get_name(self): - return "titiva" diff --git a/platformio/projectconftpl.ini b/platformio/projectconftpl.ini index 6064784fca..21525446c3 100644 --- a/platformio/projectconftpl.ini +++ b/platformio/projectconftpl.ini @@ -1,6 +1,3 @@ -# Copyright (C) Ivan Kravets -# See LICENSE for details. - # # Project Configuration File # diff --git a/platformio/telemetry.py b/platformio/telemetry.py new file mode 100644 index 0000000000..d6e95e667e --- /dev/null +++ b/platformio/telemetry.py @@ -0,0 +1,202 @@ +# Copyright (C) Ivan Kravets +# See LICENSE for details. + +import platform +import re +import uuid +from sys import argv as sys_argv +from time import time + +import click +import requests + +from platformio import __version__, app +from platformio.util import exec_command, get_systype + + +class TelemetryBase(object): + + MACHINE_ID = str(uuid.uuid5(uuid.NAMESPACE_OID, str(uuid.getnode()))) + + def __init__(self): + self._params = {} + + def __getitem__(self, name): + return self._params.get(name, None) + + def __setitem__(self, name, value): + self._params[name] = value + + def __delitem__(self, name): + if name in self._params: + del self._params[name] + + def send(self, hittype): + raise NotImplementedError() + + +class MeasurementProtocol(TelemetryBase): + + TRACKING_ID = "UA-1768265-9" + PARAMS_MAP = { + "screen_name": "cd", + "event_category": "ec", + "event_action": "ea", + "event_label": "el", + "event_value": "ev" + } + + def __init__(self): + TelemetryBase.__init__(self) + self['v'] = 1 + self['tid'] = self.TRACKING_ID + self['cid'] = self.MACHINE_ID + + self['sr'] = "%dx%d" % click.get_terminal_size() + self._prefill_screen_name() + self._prefill_appinfo() + self._prefill_custom_data() + + @classmethod + def session_instance(cls): + try: + return cls._session_instance + except AttributeError: + cls._session_instance = requests.Session() + return cls._session_instance + + def __getitem__(self, name): + if name in self.PARAMS_MAP: + name = self.PARAMS_MAP[name] + return TelemetryBase.__getitem__(self, name) + + def __setitem__(self, name, value): + if name in self.PARAMS_MAP: + name = self.PARAMS_MAP[name] + TelemetryBase.__setitem__(self, name, value) + + def _prefill_appinfo(self): + self['av'] = __version__ + + # gather dependent packages + dpdata = [] + dpdata.append("Click/%s" % click.__version__) + # dpdata.append("Requests/%s" % requests.__version__) + try: + result = exec_command(["scons", "--version"]) + match = re.search(r"engine: v([\d\.]+)", result['out']) + if match: + dpdata.append("SCons/%s" % match.group(1)) + except: # pylint: disable=W0702 + pass + self['an'] = " ".join(dpdata) + + def _prefill_custom_data(self): + self['cd1'] = get_systype() + self['cd2'] = "Python/%s %s" % (platform.python_version(), + platform.platform()) + + def _prefill_screen_name(self): + args = [str(s).lower() for s in sys_argv[1:]] + if not args: + return + + if args[0] in ("lib", "settings"): + cmd_path = args[:2] + else: + cmd_path = args[:1] + + self['screen_name'] = " ".join([p.title() for p in cmd_path]) + self['cd3'] = " ".join(args) + + def send(self, hittype): + self['t'] = hittype + + # correct queue time + if "qt" in self._params and isinstance(self['qt'], float): + self['qt'] = int((time() - self['qt']) * 1000) + + try: + r = self.session_instance().post( + "https://ssl.google-analytics.com/collect", + data=self._params + ) + r.raise_for_status() + except: # pylint: disable=W0702 + backup_report(self._params) + return False + return True + + +def on_command(ctx): # pylint: disable=W0613 + mp = MeasurementProtocol() + if mp.send("screenview"): + resend_backuped_reports() + + +def on_run_environment(options, targets): + opts = ["%s=%s" % (opt, value) for opt, value in sorted(options)] + targets = [t.title() for t in targets or ["run"]] + on_event("Env", " ".join(targets), " ".join(opts)) + + +def on_event(category, action, label=None, value=None, screen_name=None): + mp = MeasurementProtocol() + mp['event_category'] = category[:150] + mp['event_action'] = action[:500] + if label: + mp['event_label'] = label[:500] + if value: + mp['event_value'] = int(value) + if screen_name: + mp['screen_name'] = screen_name[:2048] + return mp.send("event") + + +def on_exception(e): + mp = MeasurementProtocol() + mp['exd'] = "%s: %s" % (type(e).__name__, e) + mp['exf'] = 1 + return mp.send("exception") + + +def backup_report(params): + KEEP_MAX_REPORTS = 1000 + tm = app.get_state_item("telemetry", {}) + if "backup" not in tm: + tm['backup'] = [] + + # skip static options + for key in params.keys(): + if key in ("v", "tid", "cid", "cd1", "cd2", "sr", "an"): + del params[key] + + # store time in UNIX format + if "qt" not in params: + params['qt'] = time() + elif not isinstance(params['qt'], float): + params['qt'] = time() - (params['qt'] / 1000) + + tm['backup'].append(params) + tm['backup'] = tm['backup'][KEEP_MAX_REPORTS*-1:] + app.set_state_item("telemetry", tm) + + +def resend_backuped_reports(): + MAX_RESEND_REPORTS = 10 + + resent_nums = 0 + while resent_nums < MAX_RESEND_REPORTS: + tm = app.get_state_item("telemetry", {}) + if "backup" not in tm or not tm['backup']: + break + + report = tm['backup'].pop() + app.set_state_item("telemetry", tm) + resent_nums += 1 + + mp = MeasurementProtocol() + for key, value in report.items(): + mp[key] = value + if not mp.send(report['t']): + break diff --git a/platformio/util.py b/platformio/util.py index dfa314b766..cd5fd3af52 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -2,15 +2,13 @@ # See LICENSE for details. from os import name as os_name -from os import getcwd, getenv, listdir, utime -from os.path import dirname, expanduser, isfile, join, realpath +from os import getcwd, getenv, makedirs, utime +from os.path import dirname, expanduser, isdir, isfile, join, realpath from platform import system, uname from subprocess import PIPE, Popen from time import sleep -from requests import get, post -from requests.exceptions import ConnectionError, HTTPError -from requests.utils import default_user_agent +import requests from serial import Serial from platformio import __apiurl__, __version__ @@ -31,14 +29,24 @@ def get_systype(): def get_home_dir(): + home_dir = None + try: config = get_project_config() if (config.has_section("platformio") and config.has_option("platformio", "home_dir")): - return config.get("platformio", "home_dir") + home_dir = config.get("platformio", "home_dir") except NotPlatformProject: pass - return expanduser("~/.platformio") + + if not home_dir: + home_dir = expanduser("~/.platformio") + + if not isdir(home_dir): + makedirs(home_dir) + + assert isdir(home_dir) + return home_dir def get_lib_dir(): @@ -77,15 +85,6 @@ def get_project_config(): return cp -def get_platforms(): - platforms = [] - for p in listdir(join(get_source_dir(), "platforms")): - if p in ("__init__.py", "base.py") or not p.endswith(".py"): - continue - platforms.append(p[:-3]) - return platforms - - def change_filemtime(path, time): utime(path, (time, time)) @@ -121,22 +120,29 @@ def get_serialports(): def get_api_result(path, params=None, data=None): result = None r = None + try: headers = {"User-Agent": "PlatformIO/%s %s" % ( - __version__, default_user_agent())} - if data: - r = post(__apiurl__ + path, params=params, data=data, - headers=headers) + __version__, requests.utils.default_user_agent())} + # if packages - redirect to SF + if path == "/packages": + r = requests.get( + "https://sourceforge.net/projects/platformio-storage/files/" + "packages/manifest.json/download", + params=params, headers=headers) + elif data: + r = requests.post(__apiurl__ + path, params=params, data=data, + headers=headers) else: - r = get(__apiurl__ + path, params=params, headers=headers) + r = requests.get(__apiurl__ + path, params=params, headers=headers) result = r.json() r.raise_for_status() - except HTTPError as e: + except requests.exceptions.HTTPError as e: if result and "errors" in result: raise APIRequestError(result['errors'][0]['title']) else: raise APIRequestError(e) - except ConnectionError: + except requests.exceptions.ConnectionError: raise APIRequestError( "Could not connect to PlatformIO Registry Service") except ValueError: diff --git a/tox.ini b/tox.ini index 28baf1c180..5bb7965ce1 100644 --- a/tox.ini +++ b/tox.ini @@ -23,8 +23,8 @@ deps = sphinx_rtd_theme commands = sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html - sphinx-build -W -b latex -d {envtmpdir}/doctrees docs docs/_build/latex - /bin/bash -c "if [[ $CI != \\"true\\" ]]; then sphinx-build -W -b linkcheck docs docs/_build/html; fi" + sphinx-build -W -b latex -d {envtmpdir}/doctrees docs docs/_build/latex + /bin/bash -c "if [[ $CI != \\"true\\" ]]; then sphinx-build -W -b linkcheck docs docs/_build/html; fi" [testenv:lint] deps =