Compare commits

..

1304 Commits

Author SHA1 Message Date
Ivan Kravets
54f14c64b5 Merge branch 'release/v4.0.2' 2019-08-23 16:24:28 +03:00
Ivan Kravets
20a9522542 Bump version to 4.0.2 2019-08-23 16:17:11 +03:00
Ivan Kravets
f8d957a705 Sync docs 2019-08-23 16:10:47 +03:00
Ivan Kravets
2eecbf966c Fixed an issue with a broken LDF when checking for framework compatibility // Resolve #2940 2019-08-23 15:45:45 +03:00
Ivan Kravets
cef778731e Merge branch 'release/v4.0.1' 2019-08-22 14:25:40 +03:00
Ivan Kravets
adde5e6a7e Merge tag 'v4.0.1' into develop
Bump version to 4.0.1
2019-08-22 14:25:40 +03:00
Ivan Kravets
37863df67e Bump version to 4.0.1 2019-08-22 14:25:27 +03:00
Ivan Kravets
0e56a155f8 Fixed an issue when printing settings and file path contains non-ASCII chars // Resolve #2934 2019-08-22 14:21:54 +03:00
Ivan Kravets
c6de3ebea0 Refactor "humanize_duration_time" to "00:00:00.000" format 2019-08-20 16:49:18 +03:00
Ivan Kravets
a25c1155c2 Docs: Add support for Teensy 4.0 2019-08-19 18:16:53 +03:00
Ivan Kravets
42ee6fe96e Fixed an issue when library.json had priority over project configuration for LDF // Resolve #2867 2019-08-19 15:54:07 +03:00
Ivan Kravets
a33fd6de27 Bump version to 4.0.1rc2 2019-08-19 14:44:04 +03:00
Ivan Kravets
a2830dd527 Automatically normalize file system paths to UNIX-style for Project Generator // Resolve #2857 2019-08-19 14:43:39 +03:00
Ivan Kravets
f46e1b7a3a Fix broken reference to VSCode Settings docs 2019-08-19 12:57:40 +03:00
Ivan Kravets
bf59dda01b Better handling of fs.rmtree errors on Windows // Issue #2916 2019-08-19 12:48:57 +03:00
Ivan Kravets
1dc15326c9 Export ProjectConfig instance to templates generator // Issue #2824 2019-08-18 11:06:52 +03:00
Ivan Kravets
1a3720cfb9 Ability to set "databaseFilename" for VSCode and C/C++ extension // Resolve #2825 2019-08-18 00:40:59 +03:00
Ivan Kravets
5ea3f2bbc6 Use board ID when InternetIsOffline for getting resent projects // Resolve #2866 2019-08-17 23:58:05 +03:00
Ivan Kravets
08103cfc59 Improve settings printing 2019-08-17 23:57:12 +03:00
Ivan Kravets
78e88b6115 Update changelog 2019-08-17 22:31:41 +03:00
Ivan Kravets
26bb74afd5 Bump version to 4.0.1rc1 2019-08-17 22:03:52 +03:00
Simon Arlott
0587f5b964 Add __attribute__((unused)) to generated test code (#2906)
Without this, the compiler will generate unused parameter warnings in
the native version:

test/output_export.cpp: In function ‘void output_start(unsigned int)’:
test/output_export.cpp:6:32: error: unused parameter ‘baudrate’ [-Werror=unused-parameter]
 void output_start(unsigned int baudrate)
                                ^~~~~~~~
cc1plus: all warnings being treated as errors
2019-08-17 21:07:37 +03:00
Ivan Kravets
e0ec4ff435 Encode PIO Core version before hashing // Resolve #2916 2019-08-17 21:06:15 +03:00
Ivan Kravets
0677bcecb9 Improve printing of tabulated results 2019-08-17 20:55:16 +03:00
Ivan Kravets
9023358d9e YAPF=0.28.0 2019-08-17 17:54:31 +03:00
Ivan Kravets
3edf7e6ca8 Fixed an issue with PIO Home's "No JSON object could be decoded" // Resolve #2823 2019-08-15 21:44:07 +03:00
Ivan Kravets
59114bbd86 Fixes for creating dev/platform 2019-08-15 17:13:45 +03:00
Ivan Kravets
fac45d37f8 Article by Tech Explorations 2019-08-13 20:48:19 +03:00
Ivan Kravets
d0c73af459 Fix docs when only Python 2 was mentioned for PIO Core 2019-08-13 20:44:52 +03:00
Yusuf Soyipek
fcd1862f40 Add FT231XS ids for Sparkfun ESP32 Thing (#2886)
Signed-off-by: Yusuf Soyipek's ysoyipek@iora.com.tr
2019-08-12 23:22:55 +03:00
Ivan Kravets
a6d42bedc1 Minor fix 2019-08-12 23:00:25 +03:00
Ivan Kravets
04ebdf428b Move "match_src_files" to FS module 2019-08-12 20:32:26 +03:00
Ivan Kravets
6a90388649 Move FS related helpers to fs.py module 2019-08-12 19:44:37 +03:00
Ivan Kravets
1b2e410f12 New article by Jean-Claude Wippler about PlatformIO CLI 2019-07-24 13:08:51 +03:00
Ivan Kravets
f7647438ef Docs: Fix case sensitive files 2019-07-24 12:15:08 +03:00
Ivan Kravets
436a6bc521 Updated contributing guidelines // Resolve #2820 2019-07-24 12:08:21 +03:00
Ivan Kravets
8ea3909a64 Updated contributing guidelines // Resolve #2820 2019-07-24 12:03:28 +03:00
Ivan Kravets
ba0ab796c6 Updated contributing guidelines // Resolve #2820 2019-07-23 19:11:22 +03:00
Ivan Kravets
0e61020652 Docs: Sync Atmel AVR boards 2019-07-22 20:03:54 +03:00
Ivan Kravets
c51c35018d Fix test 2019-07-22 00:57:01 +03:00
Ivan Kravets
5505c6c0e3 Switch Energia's projects to Arduino framework 2019-07-21 22:31:39 +03:00
Ivan Kravets
d6a8360b29 Fix platformio ide search query for VSCode 2019-07-19 14:57:00 +03:00
Ivan Kravets
0687ceb8a4 Bump version to 4.0.1b3 2019-07-19 13:00:52 +03:00
Ivan Kravets
6d7854d113 Session based IDE integration with PIO Home 2019-07-19 12:59:50 +03:00
Ivan Kravets
aebe891895 Skip modified homeState 2019-07-18 14:17:30 +03:00
Ivan Kravets
e69d5e5873 Sync docs and examples 2019-07-18 13:16:23 +03:00
Ivan Kravets
6ea49910d5 Fixed an issue when "debug", "home", "run", and "test" commands were not shown in "platformio --help" CLI 2019-07-18 00:19:30 +03:00
Ivan Kravets
b17e318373 Add Gitlab CI to known list 2019-07-17 14:03:48 +03:00
Ivan Kravets
b0aa4c6682 Renamed "enable_ssl" setting to "strict_ssl" 2019-07-17 00:53:40 +03:00
Rotzbua
4d6c452d79 add telemetry / privacy policy reference (#2798) 2019-07-17 00:20:14 +03:00
Ivan Kravets
d06d5def72 Docs: Use renamed "default_envs" option 2019-07-16 16:55:23 +03:00
Ivan Kravets
aa3c943651 Fix typo in docs 2019-07-16 16:50:44 +03:00
Ivan Kravets
1369b10e76 Bump version to 4.0.1b2 2019-07-16 15:48:06 +03:00
Ivan Kravets
8059e04499 Improved computing of project check sum (structure, configuration) and avoid unnecessary rebuilding 2019-07-16 15:47:33 +03:00
Ivan Kravets
71c4201487 Do not save unnecessary data for PIO Home 2019-07-16 14:15:48 +03:00
Ivan Kravets
425c1fb0a8 Do not shutdown PIO Home Server for "upgrade" operations // Resolve #2784 2019-07-15 18:19:40 +03:00
Ivan Kravets
bbf829fe92 Bump version to 4.0.1b1 2019-07-15 14:56:18 +03:00
Ivan Kravets
6f2779fe5d Remove unnecessary code 2019-07-15 14:46:23 +03:00
Ivan Kravets
b51f2ae722 Fixed an issue with incorrect escaping of Windows slashes for PIO Unified Debugger 2019-07-15 14:20:14 +03:00
Ivan Kravets
d5dd4d4b3a Add global "env" group to extra_configs example 2019-07-13 13:51:04 +03:00
Ivan Kravets
eaecad3d49 Add docs for Kendryte FreeRTOS SDK 2019-07-12 15:21:04 +03:00
Ivan Kravets
a8a0cbbbf3 Remove PIO Plus link 2019-07-12 14:16:27 +03:00
Ivan Kravets
94e21bf8a1 Update badges 2019-07-12 14:12:38 +03:00
Ivan Kravets
02c3d870ff Sync Kendryte dev/platform 2019-07-12 13:57:12 +03:00
Ivan Kravets
91f0217d39 Make scripts compatible with Python 3 // Resolve #2779 2019-07-12 13:38:37 +03:00
Ivan Kravets
5e73348263 Print debug tool name in debugging session 2019-07-11 14:09:15 +03:00
Ivan Kravets
2f871db3ae Add docs about configuring MCUdude's cores 2019-07-11 12:12:54 +03:00
Ivan Kravets
28972b838b Add "publish" target 2019-07-10 16:52:04 +03:00
Ivan Kravets
0473405b92 Merge tag 'v4.0.0' into develop
Bump version to 4.0.0
2019-07-10 16:22:53 +03:00
Ivan Kravets
0d00d0534a Merge branch 'release/v4.0.0' 2019-07-10 16:22:52 +03:00
Ivan Kravets
fe210aadcf Bump version to 4.0.0 2019-07-10 16:22:37 +03:00
Ivan Kravets
6fcc76e199 Docs for VSCode: Proxy Server Support 2019-07-10 16:07:13 +03:00
Ivan Kravets
e927669632 Document how to override board configuration 2019-07-10 13:49:59 +03:00
Ivan Kravets
24d2b94e79 Drop Python 2.7 limitation from a docs // Resolve #1991 2019-07-10 13:17:42 +03:00
Ivan Kravets
f81b1089c1 Control a number of parallel build jobs with a new -j, --jobs option 2019-07-10 13:00:51 +03:00
Ivan Kravets
fee748d384 Bump version to 4.0.0rc6 2019-07-10 00:20:43 +03:00
Ivan Kravets
d003dffc5a Fixed an issue with broken internal call for PIO Account // Resolve #2748 2019-07-10 00:20:23 +03:00
Ivan Kravets
a300168658 Bump version to 4.0.0rc5 2019-07-09 00:14:46 +03:00
Ivan Kravets
0a638b7ea5 Fix issues with Unicode arguments when calling inline PIO Core 2019-07-09 00:14:11 +03:00
Ivan Kravets
ffcf6b873a Use native Windows API for getting My Documents folder path 2019-07-08 17:21:28 +03:00
Ivan Kravets
c69e80249d Append system PATH to overridden in CDT project // Resolve #810 2019-07-04 22:56:54 +03:00
Ivan Kravets
2a4b25705c More pre-configured target for Eclipse IDE 2019-07-04 22:53:36 +03:00
Ivan Kravets
412a1f78cd Fixed an issue when generating invalid "Eclipse CDT Cross GCC Built-in Compiler Settings" if a custom PLATFORMIO_CORE_DIR is used // Resolve #806 2019-07-04 20:07:44 +03:00
Ivan Kravets
73dacd9418 Add "make profile" hotkey 2019-07-04 19:02:13 +03:00
Ivan Kravets
caf5159002 Fixed an issue when Ctrl+C(SIGINT) terminates debugging session instead of halting // Resolve #2733 2019-07-04 17:47:26 +03:00
Ivan Kravets
d9b6842b6a Update history with refactored PIO Home back-end 2019-07-04 16:49:29 +03:00
Ivan Kravets
affa54e5fc Fix an issue when lib_compat_mode = strict does not ignore libraries incompatible with a project framework 2019-07-04 16:46:54 +03:00
Ivan Kravets
c3ac10fe29 Update docs and examples for SiFive dev/platform 2019-07-03 22:58:27 +03:00
Ivan Kravets
0a907627be Bump version to 4.0.0rc4 2019-07-03 15:22:22 +03:00
Ivan Kravets
26dda104dd Remove debug code 2019-07-03 15:22:04 +03:00
Ivan Kravets
7c6fabaee2 Fix an issue with unhandled warnings from PIO Core when calling it internally // Resolved #2727 2019-07-03 15:10:37 +03:00
Ivan Kravets
dc07ea56d2 Bump version to 4.0.0rc3 2019-07-03 14:01:14 +03:00
Ivan Kravets
b68e5db46b Fix broken example when using custom uploader // Resolve #2735 2019-07-03 12:37:00 +03:00
Ivan Kravets
fd9ca0cd15 Ensure buffer is created for thread stream 2019-07-02 22:35:35 +03:00
Ivan Kravets
6c47c7506e Do not remove thread buffers, reset them instead 2019-07-02 22:26:01 +03:00
Ivan Kravets
18d93dfcc9 Use StringIO for PY3 2019-07-02 21:04:43 +03:00
Ivan Kravets
900a4d463f Bump version to 4.0.0rc2 2019-07-02 20:49:06 +03:00
Ivan Kravets
4b24d6e3e4 Minor changes 2019-07-02 20:48:43 +03:00
Ivan Kravets
2988724456 Setup MultiThreadingStdStreams from child threads 2019-07-02 20:44:33 +03:00
Ivan Kravets
c79d5f0cf1 Fix an issue saving modified State 2019-07-02 15:52:12 +03:00
Ivan Kravets
148b7dccfd Refactor ThreadSafeStdBuffer 2019-07-02 15:47:03 +03:00
Ivan Kravets
83f64cebbd Remove test code 2019-07-02 12:23:35 +03:00
Ivan Kravets
69de40c409 Fix an issue when empty multiple values for project option were not casted to list // Resolve #2734 2019-07-02 12:21:06 +03:00
Ivan Kravets
bf9552bd56 Free lock when state is deleted 2019-07-02 00:45:35 +03:00
Ivan Kravets
5afaa6d0ee Merge branch 'feature/performance-fixes' into develop 2019-07-02 00:42:04 +03:00
Ivan Kravets
d2c86ab71c Refactor state to a proxied dictionary 2019-07-02 00:41:47 +03:00
Ivan Kravets
6d9de80f12 Better comparison for app state changes 2019-07-01 20:42:23 +03:00
Ivan Kravets
bf77d70d82 Thread safe internal PIO Core calling for PIO Home 2019-07-01 20:39:52 +03:00
Ivan Kravets
8525fd6ae8 Docs: Sync Atmel SAMD boards 2019-07-01 18:33:05 +03:00
Ivan Kravets
dfca7f0b68 Speedup PIO Home via internal calling of PIO Core CLI 2019-07-01 15:55:42 +03:00
Ivan Kravets
500b3e08fe Docs: Fix default OTA port for ESP32 2019-06-29 13:29:10 +03:00
Axel W
6739d5a570 In the current version of this template all build targets result (#2714)
in

   pio -c -f eclipse debug run target <mytarget>

The commit fixes this to be

   pio -c -f eclipse run target <mytarget>

See also discussion in forum:
   https://community.platformio.org/t/pio-4-0-0b3-potential-bug-in-cprojet-tpl/8390
2019-06-29 12:48:24 +03:00
Ivan Kravets
f8dd90c9a9 Docs: Fix invalid references to Sipeed boards 2019-06-28 23:34:08 +03:00
Ivan Kravets
8d459d86d3 Bump version to 4.0.0rc1 2019-06-28 19:09:47 +03:00
Ivan Kravets
f30bd18bdc Skip async output when empty byte is given 2019-06-28 19:07:59 +03:00
Ivan Kravets
0035f56e15 Sync docs and examples 2019-06-28 19:07:44 +03:00
Ivan Kravets
4123aa4c23 Look in for "lib_deps" in all declared library storages // Resolve #2708 2019-06-28 13:27:05 +03:00
Ivan Kravets
1bff3c6615 Use isolated Core folder for test_maintenance 2019-06-28 13:21:11 +03:00
Ivan Kravets
936b04e075 Remove upgrade hooks from Core 2.0 to Core 3.0 2019-06-28 13:04:34 +03:00
Ivan Kravets
4d23ad03c3 Remove upgrade hooks from Core 2.0 to Core 3.0 2019-06-28 13:03:49 +03:00
Ivan Kravets
a75823227d Use :1234 as default GDB port for QEMU 2019-06-27 15:13:16 +03:00
Ivan Kravets
96d337388b Debug: Initial configuration for QEMU 2019-06-27 15:07:13 +03:00
Ivan Kravets
c89793eab9 Use piped openOCD for RISC-V 2019-06-27 15:06:12 +03:00
Ivan Kravets
e27b40390d Look for project dir in sys env variables (hooks for Eclipse, CLion) 2019-06-27 14:57:05 +03:00
Ivan Kravets
1d80914070 Remove upgrade hooks from Core 2.0 to Core 3.0 2019-06-27 14:56:21 +03:00
Ivan Kravets
e61caa37a8 Fix issue when CMakeListsUser.txt is not included // Resolve #2712 2019-06-27 14:04:16 +03:00
Ivan Kravets
d07a1d265e Log stdout of GDB client 2019-06-27 13:38:46 +03:00
Ivan Kravets
54921c5dbd Bump version to 4.0.0b3 2019-06-26 01:02:08 +03:00
Ivan Kravets
5cb2a970fa Suppress IOError 2019-06-26 00:52:22 +03:00
Ivan Kravets
89b951e7d5 Switch to news from registry 2019-06-26 00:29:49 +03:00
Peter
6daf387c90 Missing parentheses and depreciated syntax (#2700)
Fixes
```
  File "get-platformio.py", line 93
    print r['out']
          ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(r['out'])?
```

and 

```
  File "get-platformio.py", line 146
    except Exception, e:
                    ^
SyntaxError: invalid syntax
```
2019-06-25 23:50:06 +03:00
Ivan Kravets
2c3d8ce695 Bump version to 4.0.0b2 2019-06-23 21:23:44 +03:00
Ivan Kravets
17fa5f77d5 Fix LDF recursive behaviour 2019-06-23 21:23:19 +03:00
Ivan Kravets
c0a9ae5c70 Better handling of library.properties "architectures" meta data 2019-06-23 21:21:34 +03:00
Ivan Kravets
4b7916c2af Bump version to 4.0.0b1 2019-06-21 17:50:18 +03:00
Ivan Kravets
6d968a7093 Docs: Add info about using custom targets with mbed framework 2019-06-21 15:11:51 +03:00
Ivan Kravets
634afdcf8a Update FUNDING.yml 2019-06-20 19:11:50 +03:00
Ivan Kravets
3ebeb1bab2 Create FUNDING.yml 2019-06-20 19:10:21 +03:00
Ivan Kravets
5ab564a6d0 Add doc page about ULP programming 2019-06-20 17:41:06 +03:00
Ivan Kravets
04dc6230e7 Open source PIO Unified Debugger and Unit Testing 2019-06-19 00:29:21 +03:00
Peter
51115c1254 Ignore vscode-cpptools cache (#2623)
One of the recent updates to the vscode-cpptools extension made it start caching in .vscode/ipch, and this cache can be quite big for even small projects. Since they're cache files, they should be ignored by default. This may be a short-lived suggestion, as there is already some mention that the IntelliSense cache folder may be moved to workspace storage, rather than 'per project' storage... although the 'when' is anyone's guess. 

See here for more: https://github.com/microsoft/vscode-cpptools/issues/3347
2019-06-16 12:37:32 +03:00
Peter
40c8046546 Fix Teensy serial lockout (#2676)
Fixes `[Errno 16] Device or resource busy: '/dev/ttyACM0` issue on Teensy 3.2 and 3.5 (at minimum) due to ModemManager probing the devices and making them unavailable. Updated rules sourced from current https://www.pjrc.com/teensy/49-teensy.rules configuration.
2019-06-16 12:36:41 +03:00
Ivan Kravets
fa761f9616 Use build cache for AppVeyor CI examples 2019-06-15 22:06:55 +03:00
Ivan Kravets
5fabadd059 Use build cache for CI examples 2019-06-15 21:12:40 +03:00
Ivan Kravets
38408c1e1f Use only 1 example per framework for CI 2019-06-15 21:09:52 +03:00
Ivan Kravets
fbdfe31f17 Shared cache directory for the build derived files // Resolve #2674 2019-06-15 18:53:13 +03:00
Ivan Kravets
bd8ba738cf Improve docs how to enable PIO Core dev/version in PIO IDE 2019-06-13 23:46:53 +03:00
Ivan Kravets
8b8b6c3b9e Bump version to 4.0.0a23 2019-06-13 22:57:53 +03:00
Ivan Kravets
bd3b29c304 Fix converting to real version 2019-06-13 20:24:55 +03:00
Ivan Kravets
1339924c2e Print installation progress for "lib_deps" after LDF banner 2019-06-13 19:54:40 +03:00
Ivan Kravets
46eab99888 Typo fix 2019-06-13 18:31:03 +03:00
Ivan Kravets
461d71c2c7 Look firstly in built-in library storages for a missing dependency instead of PlatformIO Registry // Resolve #1654 2019-06-13 18:22:36 +03:00
Ivan Kravets
1ccc526960 Revert "Revert back "Look firstly in built-in library storages""
This reverts commit 4ae302762a.
2019-06-13 13:08:53 +03:00
Ivan Kravets
5338a9caa3 Bump version to 4.0.0a22 2019-06-13 00:42:24 +03:00
Ivan Kravets
4ae302762a Revert back "Look firstly in built-in library storages" 2019-06-13 00:42:10 +03:00
Ivan Kravets
98513c9967 Fix nested import 2019-06-12 23:47:22 +03:00
Ivan Kravets
b6688db8b7 Bump version to 4.0.0a21 2019-06-12 22:03:28 +03:00
Ivan Kravets
d5c98e4f27 Look firstly in built-in library storages for a missing dependency instead of PlatformIO Registry // Resolve #1654 2019-06-12 22:02:59 +03:00
Ivan Kravets
b7e9bcb609 Do not check udev rules for gdb --version 2019-06-11 20:30:06 +03:00
Ivan Kravets
9de7297d38 Fix "UnicodeEncodeError: 'ascii' codec can't encode characters" // Resolve #2644 2019-06-10 19:44:18 +03:00
Ivan Kravets
97acf23a6d Docs: Add info how to enable built-in PIO Core for VSCode 2019-06-10 16:58:34 +03:00
Ivan Kravets
80718ebb95 Fix "UnicodeEncodeError: 'ascii' codec can't encode characters" // Resolve #2644 2019-06-10 15:25:59 +03:00
Ivan Kravets
643d118062 Sync docs 2019-06-07 17:42:33 +03:00
Ivan Kravets
15b5a14995 Bump version to 4.0.0a20 2019-06-07 17:24:07 +03:00
Ivan Kravets
68a3b3f9e7 Custom platform_packages per a build environment with an option to override default // Resolve #1367 2019-06-07 17:22:02 +03:00
Ivan Kravets
5f1bd286c7 Fix "ValueError: invalid literal for int() with base 10: '0.0'" // Resolve #2646 2019-06-07 15:12:24 +03:00
Ivan Kravets
d18b4f12d0 Sync docs 2019-06-07 15:01:52 +03:00
Ivan Kravets
d9010230a4 Make internal in-memory cache for package manager to be instance related 2019-06-07 15:01:27 +03:00
Ivan Kravets
686d615639 Cast env_name to string // Resolve #2644 2019-06-07 13:14:14 +03:00
Ivan Kravets
d205370e9b Docs: Minor changes to migration guide 2019-06-07 01:06:16 +03:00
Ivan Kravets
ce66033190 Docs: update migration from 3.0 to 4.0 2019-06-07 00:18:34 +03:00
Ivan Kravets
bcff26d4d7 Refactor using "@util.memoized" 2019-06-06 00:13:04 +03:00
Ivan Kravets
898d79956d Bump version to 4.0.0a19 2019-06-05 18:28:23 +03:00
Ivan Kravets
522f814811 Show detailed info about a platform when is installed from local folder or VCS // Resolve #2081 2019-06-05 18:26:39 +03:00
Ivan Kravets
394d272324 Fix numerous issues related to "UnicodeDecodeError" and international locales, or when project path contains non-ASCII chars // Resolve #143, Resolve #1342, Resolve #1959, Resolve #2100 2019-06-05 17:57:22 +03:00
Ivan Kravets
84ce7db3e3 Fixed an issue when library keeps reinstalling for non-latin path // Resolve #1252 2019-06-05 17:53:02 +03:00
Ivan Kravets
f873bd41f8 Better printing of relative path for removed objects 2019-06-05 16:47:02 +03:00
Ivan Kravets
5c8c10e7d3 Do not check that lib_extra_dirs exist // Resolve #2624 2019-06-04 13:55:11 +03:00
Ivan Kravets
a504a13fa8 Fix broken example with ConfigParser using // Resolve #2616 2019-06-04 00:50:45 +03:00
Ivan Kravets
d09964a897 Use common IDE data loading for IDE and DEBUG 2019-06-03 19:20:10 +03:00
Ivan Kravets
4416c12747 Fix numerous issues related to "UnicodeDecodeError" and international locales, or when project path contains non-ASCII chars // Resolve #2100 2019-06-03 17:44:41 +03:00
Ivan Kravets
80a1b95887 Sync docs 2019-06-03 14:48:05 +03:00
Ivan Kravets
9eb18ca72d PyLint fix 2019-06-03 14:29:22 +03:00
Ivan Kravets
37653d8446 Better decoding SCons arguments 2019-06-03 13:57:58 +03:00
Ivan Kravets
e269c91d26 Improve compatibility with hashlib Py2/Py3 2019-06-03 13:30:35 +03:00
Ivan Kravets
ac3236693f Bump version to 4.0.0a18 2019-06-03 01:14:02 +03:00
Ivan Kravets
d0b3c5ee86 Switch between Build Configurations (release and debug) with a new project configuration option build_type // Resolve #2184 2019-06-02 14:11:31 +03:00
Ivan Kravets
23a2022f04 Add support for PLATFORMIO_DEFAULT_ENVS system environment variable // Resolve #1967 2019-06-01 22:43:44 +03:00
Ivan Kravets
c5177efd0b Minor fixes 2019-06-01 22:24:38 +03:00
Ivan Kravets
d51cd9c277 Bump version to 4.0.0a17 2019-06-01 19:48:21 +03:00
Ivan Kravets
6257480d0d Print platform package details, such as version, VSC source and commit // Resolve #2155 2019-06-01 19:44:45 +03:00
Ivan Kravets
4af615a49c Maintain renamed options when reading configuration file 2019-06-01 16:58:14 +03:00
Ivan Kravets
6186b425d4 Typo fix 2019-06-01 15:38:55 +03:00
Ivan Kravets
c038074489 Override default development platform upload command with a custom // Resolve #2599 2019-06-01 14:36:07 +03:00
Ivan Kravets
d25f1ddc21 Add project folder prefix to $PROJECT_HASH 2019-05-31 21:47:50 +03:00
Ivan Kravets
5011e47709 Added support for "shared_dir" 2019-05-31 21:18:37 +03:00
Ivan Kravets
33d16bfcf0 Use named context meta vars for unit testing 2019-05-31 15:47:25 +03:00
Ivan Kravets
bae21f1cdd Allow to pass multiple load commands to PIO Unified Debugger 2019-05-31 14:45:48 +03:00
Ivan Kravets
5f9fd9260e New project configuration parser with a strict options typing 2019-05-31 14:45:01 +03:00
Ivan Kravets
61db0f1d6a YAPF 0.27.0 2019-05-30 23:42:15 +03:00
Ivan Kravets
1598c8197e Fix "clean" target 2019-05-30 23:33:57 +03:00
Ivan Kravets
01db26f204 Add a link to PIO Unified Debugger options 2019-05-30 22:26:42 +03:00
Ivan Kravets
12876c5c2b Merge branch 'feature/refactor-project-options' into develop 2019-05-30 22:15:16 +03:00
Ivan Kravets
5c60d922ca Skip "arduino-mock" from CI 2019-05-30 22:15:06 +03:00
Ivan Kravets
0570fc6c48 Don't override custom "core_dir" on Windows platform 2019-05-30 21:56:55 +03:00
Ivan Kravets
f3c8277572 Fix broken tests 2019-05-30 21:27:12 +03:00
Ivan Kravets
1dbaed5beb Implement "silent" mode for config.validate() 2019-05-30 21:26:51 +03:00
Ivan Kravets
19c1574993 Use the latest TOX for Travis.CI 2019-05-30 17:37:48 +03:00
Ivan Kravets
346579b93c Improve type converting for config options 2019-05-30 17:34:44 +03:00
Ivan Kravets
0ce2343836 Do not pass project settings as SCons arguments // Resolve #1637 2019-05-30 17:08:00 +03:00
Ivan Kravets
d5e277b7cc Minor improvements to unit testing engine 2019-05-30 16:39:17 +03:00
Ivan Kravets
3cc4af1723 Refactor project config options 2019-05-30 16:38:04 +03:00
Ivan Kravets
8d05903bf3 Log THE ONLY non sensitive data (used board, platform, and framework) 2019-05-30 14:36:04 +03:00
Ivan Kravets
7f845ab943 Sync docs and examples 2019-05-30 14:32:49 +03:00
Ivan Kravets
ddc8a353cb Sync docs 2019-05-28 12:53:54 +03:00
Ivan Kravets
9ce9171a36 Fix typo 2019-05-28 01:19:51 +03:00
Ivan Kravets
dec43bec9d Fix test 2019-05-28 00:09:20 +03:00
Ivan Kravets
99377130eb Enhance unit testing summary 2019-05-27 22:25:48 +03:00
Ivan Kravets
3df01405a1 Remove unused Python imports 2019-05-27 22:25:22 +03:00
Ivan Kravets
3adcf66453 Docs: Use native Python ConfigParser for extra scripting examples 2019-05-27 19:03:31 +03:00
Ivan Kravets
b88c262a9d Use the latest version of tox for AppVeyor CI 2019-05-27 18:49:35 +03:00
Ivan Kravets
5999bcee3f Update history 2019-05-27 18:45:24 +03:00
Ivan Kravets
078b0af312 Test only 1 project example per dev/platform for AppVeyor CI 2019-05-27 18:17:57 +03:00
Ivan Kravets
a0fb88e28a Implement "envLibdepsDirs" per project for PIO Home 2019-05-27 17:57:46 +03:00
Ivan Kravets
3cd4b005d8 Open sourcing PIO Unified Debugger, PIO Unit Testing Engine, and PIO Home Server 2019-05-27 17:19:33 +03:00
Ivan Kravets
0a523fc06c Docs: Minor tweak 2019-05-27 14:33:38 +03:00
Ivan Kravets
16864509af Document "Override package files" 2019-05-27 14:21:48 +03:00
Ivan Kravets
cb8af5add9 Print "No items found" when there are no packages for llisting 2019-05-27 12:28:04 +03:00
Ivan Kravets
3f96dc1432 Fixed an issue when package cache (Library Manager) expires too fast // Resolve #2559 2019-05-27 12:24:20 +03:00
Ivan Kravets
e1aa29cb36 Bump version to 4.0.0a16 2019-05-25 22:18:23 +03:00
Ivan Kravets
6e87089ded Add support for Unix shell-style wildcards for "monitor_port" option // Resolve #2541 2019-05-25 22:14:38 +03:00
Ivan Kravets
a84195bb5a Add user-definable monitor options to platformio.ini // Resolve #2165 2019-05-25 21:49:51 +03:00
Ivan Kravets
70a0bd72c0 Sync "include" directory for PIO Remote // Resolve #2210 2019-05-25 21:06:08 +03:00
Ivan Kravets
fea7e97112 Fix an issue with hardcoded C stadard version when generating project for CLion IDE // Resolve #2527 2019-05-25 20:47:39 +03:00
Ivan Kravets
7beb332b31 Support custom CMake configuration for CLion IDE using `CMakeListsUser.txt` file 2019-05-25 20:46:56 +03:00
Ivan Kravets
7b2c1f27fc Sync docs 2019-05-25 20:46:23 +03:00
Ivan Kravets
67f7b6cda3 Bump version to 4.0.0a15 2019-05-25 01:18:28 +03:00
Ivan Kravets
4266cba53b Cleanup ".piolibdeps" 2019-05-25 01:10:35 +03:00
Ivan Kravets
19725fec04 Add options to override default locations used by PlatformIO Core // Resolve #1615 2019-05-24 20:49:05 +03:00
Ivan Kravets
a6e5a0c7f5 Fix an issue for Project Generator when include path search order is inconsistent to what passed to the compiler // Resolve #2509 2019-05-24 16:06:27 +03:00
Ivan Kravets
2baea815fe Update history 2019-05-24 15:06:33 +03:00
Ivan Kravets
b38c57bcf9 Fix an issue when `-U in build_flags does not remove macro previously defined via -D` flag // Resolve #2508 2019-05-24 14:57:59 +03:00
Ivan Kravets
e6d1805f0b Save library requirements when using --save option // Issue #1028 2019-05-24 14:09:25 +03:00
Ivan Kravets
9a95b0df56 Fix handling custom includeDir and srcDir for library.json // Resolve #2518 2019-05-24 01:15:47 +03:00
Ivan Kravets
70a5d32925 Add "--save" flag to "platformio lib install" command // Resolve #1028 2019-05-23 19:39:04 +03:00
Ivan Kravets
c2a549b0c2 Install all project dependencies declared via "lib_deps" option using "platformio lib install" command // Resolve #2147 2019-05-23 18:37:08 +03:00
Ivan Kravets
0fda79a075 Switch to Click meta context for lib CLI 2019-05-23 13:05:44 +03:00
Ivan Kravets
21e2ac6695 Use isolated library dependency storage per project build environment // Resolve #1696 2019-05-23 00:23:24 +03:00
Ivan Kravets
e7d75d1412 Remove debug code 2019-05-21 21:47:20 +03:00
Ivan Kravets
4386dc56ea Move "in_silence" to PlatformioCLI 2019-05-21 13:18:11 +03:00
Ivan Kravets
a30b79c5fc Sync docs 2019-05-21 12:01:14 +03:00
Ivan Kravets
f29a74042f Drop support for "lib_extra_dirs" in "platformio" section 2019-05-20 21:12:45 +03:00
Ivan Kravets
c46643f0fd Custom project "***_dir" options declared in “platformio” section of “platformio.ini” have higher priority than Environment variables 2019-05-20 17:07:59 +03:00
Ivan Kravets
5fe4de626b Implement unified project workspace storage ".pio" // Resolve #1778 2019-05-20 17:01:54 +03:00
Ivan Kravets
774380c2ef Bump version to 4.0.0a14 2019-05-20 12:38:49 +03:00
Ivan Kravets
8643f0454e Move "glob_escape" and "get_file_contents" helpers to "compat" module 2019-05-17 13:18:15 +03:00
Ivan Kravets
f844d9cb47 Remove line-buffering from "platformio run" command which was leading to omitting progress bar from upload tools // Resolve #856, Resolve #857 2019-05-17 12:53:51 +03:00
Ivan Kravets
f94fbb951a Typo fix 2019-05-16 21:27:32 +03:00
Ivan Kravets
899de600e4 Fix broken "util.string_types" 2019-05-16 21:11:21 +03:00
Ivan Kravets
971049b41c Move process related helpers to "proc" module 2019-05-16 21:03:15 +03:00
Ivan Kravets
aaf61082c1 Replace "--only-check" CLI option by "--dry-run" 2019-05-16 20:02:45 +03:00
Ivan Kravets
b14abeff48 Bump version to 4.0.0a13 2019-05-13 22:37:45 +03:00
Ivan Kravets
f26553b451 ESP8266, docs for "SSL Support" 2019-05-13 22:37:24 +03:00
Ivan Kravets
8b93ad00a2 Docs: ESP32: Implement "espota" protocol 2019-05-11 22:18:35 +03:00
Ivan Kravets
5e1a931145 Switch Python or Platform dependent code to "compat" module 2019-05-10 17:50:08 +03:00
Ivan Kravets
abfee8308e Switch Python or Platform dependent code to "compat" module 2019-05-10 17:47:02 +03:00
Ivan Kravets
d2449762c2 Move Python or Platform dependent code to "compat" module 2019-05-10 17:27:04 +03:00
Ivan Kravets
59848c3115 Check unknown build environment passed by user 2019-05-10 17:26:47 +03:00
Ivan Kravets
834206ff20 Move Python or Platform dependent code to "compat" module 2019-05-10 17:26:10 +03:00
Ivan Kravets
ce4ed18ceb Check unknown build environment passed by user 2019-05-10 15:49:01 +03:00
Ivan Kravets
b710bbd80e Allow to skip ProjectConfig option validation with new "validate_options" argument 2019-05-10 15:47:45 +03:00
Ivan Kravets
446176bf5e Allow to skip ProjectConfig option validation with new "validate_options" argument 2019-05-10 15:47:17 +03:00
Ivan Kravets
0b2d780618 Switch to the new ProjectConfig API 2019-05-10 15:45:52 +03:00
Ivan Kravets
d9b0364aa8 Allow overriding a default project "platformio.ini" configuration file 2019-05-10 13:12:41 +03:00
Ivan Kravets
76818448e2 Ensure PIO Home mimetypes are known 2019-05-10 13:01:52 +03:00
Ivan Kravets
131144ec34 Resolve PyLint "import-error" 2019-05-10 13:00:53 +03:00
Ivan Kravets
a21d75b273 Merge branch 'develop' into feature/pio-plus-oss 2019-05-10 01:10:51 +03:00
Ivan Kravets
c79b3ff7f1 Override default “platformio.ini” with a custom using "-c, --project-conf" option // Resolve #1913 2019-05-10 00:01:10 +03:00
Ivan Kravets
2b5ac57fd0 Bump version to 4.0.0a12 2019-05-09 18:40:19 +03:00
Ivan Kravets
32d317d3cb Fix PlatformIO CLI 2019-05-09 18:39:27 +03:00
Ivan Kravets
71f606912a Implement ProjectConfig.getlist() 2019-05-09 14:14:19 +03:00
Ivan Kravets
62b80c396b Added support for the latest Python "Click" package (CLI Builder) // Resolve #349 2019-05-09 00:51:28 +03:00
Ivan Kravets
7687a0a929 Fix PyLint "not-an-iterable" error 2019-05-08 21:02:23 +03:00
Ivan Kravets
f63fe1699b Bump version to 4.0.0a11 2019-05-08 20:20:56 +03:00
Ivan Kravets
4f98a3fd42 Share common (global) options between declared build environments using "[env]" section // Resolve #1643 Resolve #790 2019-05-08 20:19:39 +03:00
Ivan Kravets
693304590c Fix PyLint "not-an-iterable" error 2019-05-08 12:41:11 +03:00
Ivan Kravets
947e31ca8d Fix some PyLint errors 2019-05-07 23:51:46 +03:00
Ivan Kravets
45d4b92678 Export get_projectdata_dir for util, fix riscv_gap dev/platform 2019-05-07 23:00:01 +03:00
Ivan Kravets
07a2a49d93 Refactor project helpers 2019-05-07 22:13:21 +03:00
Ivan Kravets
7ddd22209f Enable PyLint "import-error" 2019-05-07 21:16:42 +03:00
Ivan Kravets
6cd4484be9 Init new project using new ProjectConfig API 2019-05-07 19:57:24 +03:00
Ivan Kravets
c235974eb6 Switch to the new ProjectConfig API 2019-05-07 17:51:50 +03:00
Ivan Kravets
1b4f945907 Remove support for renamed dev/platforms 2019-05-07 15:59:09 +03:00
Ivan Kravets
4fdd51e190 Docs: Sync MCS51 boards 2019-05-07 13:26:10 +03:00
Ivan Kravets
95b9ae9f24 Docs: Sync Atmel SAM boards 2019-05-06 13:38:48 +03:00
Ivan Kravets
94e580bf4e Override default source and include directories for a library via "library.json" manifest using "includeDir" and "srcDir" fields 2019-05-04 13:36:27 +03:00
Ivan Kravets
e4dca37874 Bump version to 4.0.0a10 2019-05-04 12:23:51 +03:00
Ivan Kravets
7f607b742f Fix issue when handling dynamic variables 2019-05-04 12:23:23 +03:00
Ivan Kravets
2c0e0b2619 Bump version to 4.0.0a9 2019-05-03 21:14:08 +03:00
Ivan Kravets
8e55c9e4d0 Include external configuration files with "extra_configs" option // Resolve #1590 2019-05-03 21:03:36 +03:00
Ivan Kravets
41ff1b0188 Support for Kendryte K210 // Resolve #2233 2019-05-03 16:56:44 +03:00
Ivan Kravets
48c1aeae03 Fix "systemd-udevd" warnings in 99-platformio-udev.rules // Resolve #2442 2019-05-03 13:11:03 +03:00
Ivan Kravets
eab2fd91fd Lowercase SHA sum for package manager 2019-04-25 12:49:22 +03:00
Ivan Kravets
ba6d120cf4 Docs: Sync Atmel AVR dev/platform 2019-04-24 00:14:53 +03:00
Ivan Kravets
e9df6166ee Update SCons to 3.0.5 2019-04-24 00:07:27 +03:00
Ivan Kravets
9bdc85fd52 Bump version to 4.0.0a8 2019-04-23 12:49:36 +03:00
Ivan Kravets
fa48a6460f Merge tag 'v3.6.7' into develop 2019-04-23 12:49:10 +03:00
Ivan Kravets
f07854879a Merge branch 'hotfix/v3.6.7' 2019-04-23 12:47:27 +03:00
Ivan Kravets
9ca53c57f4 Bump version to 3.6.7 2019-04-23 12:32:18 +03:00
Ivan Kravets
ee420cc35e Bump version to 3.6.7 2019-04-23 12:31:58 +03:00
Ivan Kravets
d49d91269d Update history with upcoming 3.6.7 release 2019-04-23 12:29:29 +03:00
Ivan Kravets
a59efc2fc0 Update history with upcoming 3.6.7 release 2019-04-23 12:29:16 +03:00
Ivan Kravets
20f28383a0 Fix links in changelog 2019-04-23 01:07:36 +03:00
Ivan Kravets
d3c3491a91 Fix links in changelog 2019-04-23 01:07:21 +03:00
Ivan Kravets
e6a7cc2036 Update core package dependencies 2019-04-23 01:05:11 +03:00
Ivan Kravets
4d615416f3 Improve debugging in debug_load_mode = modified and fix an issue with useless project rebuilding 2019-04-23 00:50:32 +03:00
Ivan Kravets
137a5d1c42 Improve debugging in debug_load_mode = modified and fix an issue with useless project rebuilding 2019-04-23 00:49:53 +03:00
Ivan Kravets
65354e995d Initial commit of PIO Home 2019-04-22 21:07:28 +03:00
Ivan Kravets
3032cade17 PyLint fixes 2019-04-19 20:46:28 +03:00
Ivan Kravets
948a977fa5 Initial commit of PIO Unit Testing 2019-04-19 20:33:31 +03:00
Ivan Kravets
c7d8b50474 Use generic GDB_MSPDEBUG_INIT_CONFIG 2019-04-19 19:58:34 +03:00
Ivan Kravets
f1da544279 Initial commit of PIO Unified Debugger 2019-04-19 19:56:16 +03:00
Ivan Kravets
40d1bb204c Docs: New boards by ESP32 dev/platform 2019-04-19 13:26:25 +03:00
Ivan Kravets
21a36f8ee9 Fix UnicodeEncodeError when converting INO to CPP 2019-04-18 16:20:01 +03:00
Ivan Kravets
be24c6ab4d Fix an issue when invalid "env_default" results into unhandled errors // Resolve #2265 2019-04-18 14:18:27 +03:00
Ivan Kravets
3d96e584fb Fix an issue when invalid "env_default" results into unhandled errors // Resolve #2265 2019-04-18 14:17:22 +03:00
Ivan Kravets
963eabc3f5 Docs: Rename "Download" button to INSTALL 2019-04-18 01:01:26 +03:00
Ivan Kravets
f63041a402 Add get_original_version to public utils API 2019-04-17 23:20:45 +03:00
Ivan Kravets
c084db1619 Enable AppVeyor CI only for Windows x64 2019-04-17 20:09:05 +03:00
Ivan Kravets
4edfb8f6cc Cleanup PING_INTERNET_IPS 2019-04-17 20:06:01 +03:00
Ivan Kravets
6501c1f171 Cleanup PING_INTERNET_IPS 2019-04-17 20:05:51 +03:00
Ivan Kravets
41ab97203a Docs: Add community video tutorials 2019-04-16 13:55:47 +03:00
Ivan Kravets
a51a03843d Docs: Use jQuery from Sphinx theme (fix search) 2019-04-16 00:33:21 +03:00
Ivan Kravets
e9b8478942 Sync docs 2019-04-07 00:52:20 +03:00
Ivan Kravets
29cf1c8596 Fix "ValueError: invalid literal for int() with base 10" for click.get_terminal_size 2019-04-05 19:49:36 +03:00
Ivan Kravets
e992e156bf Fix "ValueError: invalid literal for int() with base 10" for click.get_terminal_size 2019-04-05 19:48:04 +03:00
Ivan Kravets
cf13ec4035 Fix an "IndexError: list index out of range" for Arduino sketch preprocessor // Resolve #2268 2019-04-01 18:50:40 +03:00
Ivan Kravets
c1d01dbe34 Update info about PIO IDE for VSCode 2019-04-01 18:35:00 +03:00
Ivan Kravets
ff5da3c3cc Use stable dev/platforms for CI 2019-03-30 13:54:29 +02:00
Ivan Kravets
7d9e10095e Set manifest version of VSCode C/C++ configuration file 2019-03-30 13:00:27 +02:00
Ivan Kravets
bb17630571 Set manifest version of VSCode C/C++ configuration file 2019-03-30 13:00:10 +02:00
Ivan Kravets
7746f7eeee Project Generator: fixed a VSCode C/C++'s "Cannot find" warning when CPPPATH folder does not exist 2019-03-29 21:27:08 +02:00
Ivan Kravets
e089c4a546 Project Generator: fixed a VSCode C/C++'s "Cannot find" warning when CPPPATH folder does not exist 2019-03-29 21:26:45 +02:00
Ivan Kravets
8f29d951cb YAPF 0.26.0 2019-03-29 12:55:05 +02:00
Ivan Kravets
f182a6dcae Bump version to 3.6.7a1 2019-03-29 12:46:24 +02:00
Ivan Kravets
0c76116948 Merge tag 'v3.6.6' into develop 2019-03-29 12:44:54 +02:00
Ivan Kravets
6b17183cff Merge branch 'hotfix/v3.6.6' 2019-03-29 12:43:41 +02:00
Ivan Kravets
8cd35fb537 Bump version to 3.6.6 2019-03-29 12:43:16 +02:00
Ivan Kravets
2d4421e8e5 New article "Automated unit testing in the metal" 2019-03-25 16:04:05 +02:00
Ivan Kravets
760499c095 Append configuration settings from "mbed_lib.json" to "mbed_config.h" // Resolve #2164 2019-03-24 23:55:06 +02:00
Ivan Kravets
c141189883 Append configuration settings from "mbed_lib.json" to "mbed_config.h" // Resolve #2164 2019-03-24 23:54:53 +02:00
Ivan Kravets
00b162608e Fix an issue with incorrect order of project "include" and "src" paths in `CPPPATH` // Resolve #1914 2019-03-23 17:45:28 +02:00
Ivan Kravets
51cb87bc6f Bump version to 4.0.0a7 2019-03-23 17:44:30 +02:00
Ivan Kravets
cae708f2d7 Fix an issue with incorrect order of project "include" and "src" paths in `CPPPATH` // Resolve #1914 2019-03-23 17:44:01 +02:00
Ivan Kravets
e33b0fe291 Fix an issue when PlatformIO Build System does not pick up "mbed_lib.json" files from libraries // Resolve #2164 2019-03-23 14:33:34 +02:00
Ivan Kravets
3a77bed0d4 Fix an issue when PlatformIO Build System does not pick up "mbed_lib.json" files from libraries // Resolve #2164 2019-03-23 14:24:43 +02:00
Ivan Kravets
06fe557a20 Fix "SameFileError" when CI is used in pair with --keep-build-dir // Resolve #2227 2019-03-22 21:25:12 +02:00
Ivan Kravets
10a7367b33 Fix "SameFileError" when CI is used in pair with --keep-build-dir // Resolve #2227 2019-03-22 21:24:43 +02:00
Ivan Kravets
9c1cc97776 Project Generator: fixed a warning "Property !!! WARNING !!! is not allowed" for VSCode // Resolve #2243 2019-03-22 21:17:26 +02:00
Ivan Kravets
dea6551841 Bump version to 4.0.0a6 2019-03-22 21:16:33 +02:00
Ivan Kravets
4ca71e7df1 Project Generator: fixed a warning "Property !!! WARNING !!! is not allowed" for VSCode // Resolve #2243 2019-03-22 21:16:02 +02:00
Ivan Kravets
d7e2d05f60 Fix error with conflicting declaration of a prototype (Arduino sketch preprocessor) 2019-03-20 18:58:06 +02:00
Ivan Kravets
d9e6111ac3 Fix error with conflicting declaration of a prototype (Arduino sketch preprocessor) 2019-03-20 18:49:20 +02:00
Ivan Kravets
86e4641101 Bump version to 3.6.6a1 2019-03-14 20:16:15 +02:00
Ivan Kravets
326eb4a681 Fix "FileExistsError" when "platformio ci" command is used in pair with "--keep-build-dir" option 2019-03-14 20:14:55 +02:00
Ivan Kravets
d4af985eb8 Bump version to 4.0.0a5 2019-03-14 20:12:52 +02:00
Ivan Kravets
0d904ad1cc Fix "FileExistsError" when "platformio ci" command is used in pair with "--keep-build-dir" option 2019-03-14 20:12:18 +02:00
Ivan Kravets
b3ac567b53 Docs: New article "Getting started with the STM32F407VG and STM32Cube" 2019-03-14 14:46:44 +02:00
Ivan Kravets
03aec79cc1 Drop mbed OS support for Adafruit boards 2019-03-13 22:22:48 +02:00
Ivan Kravets
9a6d148bdc Update docs for PIO Plus products 2019-03-08 18:01:35 +02:00
Ivan Kravets
a9288e5a5b Docs: Cosmetic changes to PIO Unified Debugging and Unit Testing 2019-03-07 17:26:22 +02:00
Ivan Kravets
8280fd557b Bump version to 4.0.0a4 2019-03-07 14:12:45 +02:00
Ivan Kravets
15a1cbf95a Tag docs with v3.6.5 2019-03-07 14:09:50 +02:00
Ivan Kravets
775797b4e5 Merge tag '3.6.5' into develop 2019-03-07 14:02:35 +02:00
Ivan Kravets
e37d34b92f Merge branch 'release/3.6.5' 2019-03-07 14:00:57 +02:00
Ivan Kravets
b562541f20 Bump version to 3.6.5 2019-03-07 13:57:32 +02:00
Ivan Kravets
736a1404b4 YAPF 0.26.0 2019-03-07 12:55:03 +02:00
Ivan Kravets
9639626ab3 Fix an issue when `$PROJECT_HASH template was not expanded for the other directory ***_dir` options in "platformio.ini" // Resolve #2170 2019-03-07 12:54:40 +02:00
Ivan Kravets
4c8df44a5a Fix an issue when `$PROJECT_HASH template was not expanded for the other directory ***_dir` options in "platformio.ini" // Resolve #2170 2019-03-07 12:40:55 +02:00
Ivan Kravets
3f52a6d5ba YAPF 0.26.0 2019-03-07 12:36:17 +02:00
Ivan Kravets
237d55208c Fix "Unnecessary "else/elif" after "raise"" by PyLint 2019-03-07 12:35:34 +02:00
Ivan Kravets
b99494671a Update "dl.bintray.com" IP address 2019-03-06 22:39:38 +02:00
Ivan Kravets
5a72e3f2a1 Update "dl.bintray.com" IP address 2019-03-06 22:39:24 +02:00
Ivan Kravets
1ce913ea74 Sync docs 2019-03-06 21:04:01 +02:00
Ivan Kravets
9911a04232 Sync docs 2019-03-06 12:29:03 +02:00
Ivan Kravets
f1549e1f0e Docs: Sync new boards by STM32 2019-03-05 13:20:19 +02:00
Ivan Kravets
4659a44bd6 New boards: Adafruit Bluefruit nRF52832 Feather, Feather nRF52840 Express, and Nordic nRF52840-DK (Adafruit BSP) 2019-03-04 13:50:34 +02:00
Ivan Kravets
e39d4f5c32 Sync docs 2019-03-04 13:12:16 +02:00
Ivan Kravets
fb9fe8c77c Document upload_protocol = espota option 2019-03-04 13:03:22 +02:00
Ivan Kravets
9778778830 PyLin fix 2019-02-24 11:45:29 +02:00
Ivan Kravets
ab914e1566 PyLin fix 2019-02-24 11:45:14 +02:00
Ivan Kravets
d2c2171ef9 Project Generator: add new targets for CLion IDE "BUILD_VERBOSE" and "MONITOR" (serial port monitor) // Resolve #359 2019-02-23 22:43:30 +02:00
Ivan Kravets
856798488b Fix an issue when platformio ci recompiles project if `--keep-build-dir` option is passed // Resolve #2109 2019-02-23 22:41:45 +02:00
Ivan Kravets
00ba88911f Fix an issue with slow updating of PlatformIO Core packages on Windows 2019-02-23 22:41:15 +02:00
Ivan Kravets
e0b9d080fa Project Generator: add new targets for CLion IDE "BUILD_VERBOSE" and "MONITOR" (serial port monitor) // Resolve #359 2019-02-23 22:34:36 +02:00
Ivan Kravets
42c22758bb Use NodeMCUv2 as default board for wiring example 2019-02-23 21:04:43 +02:00
Ivan Kravets
522b42c2a9 Fix an issue when platformio ci recompiles project if `--keep-build-dir` option is passed // Resolve #2109 2019-02-23 18:39:54 +02:00
Ivan Kravets
5a707a4849 CI only for Python 2.7 & 3.6 2019-02-23 16:00:24 +02:00
Ivan Kravets
1bed2650f3 Sync docs 2019-02-23 14:44:13 +02:00
Ivan Kravets
65f30dd7b4 Sync docs 2019-02-23 01:10:41 +02:00
Ivan Kravets
59b27d5d0a Document switching between Arduino cores 2019-02-21 22:53:33 +02:00
Ivan Kravets
6575ddab26 Improve docs for pio ci command when multiple --project-option are used 2019-02-21 00:25:14 +02:00
Ivan Kravets
dc4a5df2af Drop support for RFduino 2019-02-20 00:13:56 +02:00
Ivan Kravets
2e4c9411af Docs: Update VSCode Custom Task example 2019-02-20 00:00:41 +02:00
Ivan Kravets
e477d1fbcf Docs: Move images from root of _static to _static/images 2019-02-19 23:25:13 +02:00
Ivan Kravets
6059e0dce6 Fix an issue with slow updating of PlatformIO Core packages on Windows 2019-02-19 20:12:07 +02:00
Ivan Kravets
234bb75b9b Sync docs & examples 2019-02-19 18:11:21 +02:00
Ivan Kravets
38dfa40e32 Docs: Sync Atmel SAM boards 2019-02-18 18:57:37 +02:00
Ivan Kravets
5add5f1cfb Document lwIP profiles for EPS8266 2019-02-18 15:51:35 +02:00
Ivan Kravets
f1b809f8dd Improve debugging instruction for ESP32 tutorial // Resolve #1871 2019-02-09 19:11:51 +02:00
Ivan Kravets
47aa63fc04 Update docs for mbed framework 2019-02-07 20:36:45 +02:00
Ivan Kravets
08000a6f62 Sync docs & examples 2019-02-07 19:01:51 +02:00
Ivan Kravets
31d4706abd Debug: Update wiring scheme for Mini-Module 2019-02-02 19:21:12 +02:00
Ivan Kravets
e23ca2c109 Docs: Allow to control firmware optimization for Teensy 2019-01-31 16:42:44 +02:00
Ivan Kravets
17efa89047 Disable STM8 from CI tests 2019-01-30 18:00:40 +02:00
Ivan Kravets
527efe3359 RISV-GAP, document AutoTiler 2019-01-30 18:00:12 +02:00
Ivan Kravets
5aed0efd61 Docs: Add Alorium Hinj board 2019-01-29 22:20:41 +02:00
Ivan Kravets
27ac17e8c3 Release docs to 3.6.4 2019-01-23 21:24:29 +02:00
Ivan Kravets
639c086728 Bump version to 3.6.5a1 2019-01-23 21:08:39 +02:00
Ivan Kravets
d2c545eb27 Bump version to 4.0.0a3 2019-01-23 20:55:18 +02:00
Ivan Kravets
035ab14202 Merge tag 'v3.6.4' into develop
Bump version to 3.6.4

# Conflicts:
#	HISTORY.rst
#	platformio/__init__.py
2019-01-23 20:54:21 +02:00
Ivan Kravets
4504080027 Merge branch 'release/v3.6.4' 2019-01-23 20:51:48 +02:00
Ivan Kravets
367e4d663c Bump version to 3.6.4 2019-01-23 20:47:18 +02:00
Ivan Kravets
28bca48eca Ignore examples for ststm8 on Linux 2019-01-23 17:55:07 +02:00
Ivan Kravets
eb57e14ac1 Fix "ValueError: invalid literal for int() with base 10" // Resolve #2061 2019-01-23 17:54:45 +02:00
Ivan Kravets
69065d8bd6 Fix "ValueError: invalid literal for int() with base 10" // Resolve #2058 2019-01-22 22:16:58 +02:00
Ivan Kravets
3cc996d89f Fix "ValueError: invalid literal for int() with base 10" // Resolve #2058 2019-01-22 21:59:26 +02:00
Ivan Kravets
d7d981f522 Add "Variable Format" section to VSCode 2019-01-22 21:05:38 +02:00
Ivan Kravets
eedc1c3ccd Bump version to 4.0.0a2 2019-01-17 18:18:28 +02:00
Ivan Kravets
db0bbcc043 CLion: Improve project portability using "${CMAKE_CURRENT_LIST_DIR}" instead of USER_HOME 2019-01-17 18:05:05 +02:00
Ivan Kravets
63075c9607 CLion: Improve project portability using "${CMAKE_CURRENT_LIST_DIR}" instead of USER_HOME 2019-01-17 18:04:52 +02:00
Ivan Kravets
b594c11718 Fix cmd_lib test 2019-01-17 17:56:35 +02:00
Ivan Kravets
b6ccda3568 Fix cmd_lib test 2019-01-17 17:56:21 +02:00
Ivan Kravets
35f96a534a Drop "do-not-modify-files-here.url" from build_dir 2019-01-17 02:07:46 +02:00
Ivan Kravets
7e8349d45e Docs: Sync Atmel AVR boards 2019-01-16 15:34:31 +02:00
Ivan Kravets
88d06b4437 Ignore examples for ststm8 on Linux 2019-01-12 01:08:13 +02:00
Ivan Kravets
3019e35724 Initial support for STM8 2019-01-11 16:52:01 +02:00
Ivan Kravets
38bb2c61c1 Docs: Sort upload protocols for board 2019-01-11 14:35:54 +02:00
Ivan Kravets
c7949ecd07 Temporary disable checking for PlatformIO Core engine (allow PIO Core 3 dev/platforms for PIO Core 4) 2019-01-11 14:11:54 +02:00
Ivan Kravets
d627a42268 Fix PyLint warning 2019-01-11 14:07:46 +02:00
Ivan Kravets
2b467f3fee Fix PyLint warning 2019-01-11 14:07:35 +02:00
Ivan Kravets
f058b8f18f Fix PY3 Lint "consider-using-set-comprehension" 2019-01-11 13:02:12 +02:00
Ivan Kravets
a750b06fc8 Fix PY3 Lint "consider-using-set-comprehension" 2019-01-11 13:01:53 +02:00
Ivan Kravets
13430aa628 Use GCC C++ compiler for Eclipse project indexer // Issue #1010 2019-01-11 12:52:17 +02:00
Ivan Kravets
286a53991c Use GCC C++ compiler for Eclipse project indexer // Issue #1010 2019-01-11 12:52:00 +02:00
Ivan Kravets
b92a8467c9 Update SCons to 3.0.3 2019-01-10 23:47:43 +02:00
Ivan Kravets
56cd55ba7d Eclipse: Provide language standard to a project C/C++ indexer // Resolve #1010 2019-01-10 21:57:52 +02:00
Ivan Kravets
a092f87c50 Eclipse: Provide language standard to a project C/C++ indexer // Resolve #1010 2019-01-10 21:57:39 +02:00
Ivan Kravets
19b5285d50 Fix "TypeError : startswith first arg" when checking udev rules with PY3 // Resolve #2000 2019-01-10 19:34:09 +02:00
Ivan Kravets
d5d95092c4 Fix an error "Could not extract item..." when extracting TAR archive with symbolic items on Windows platform // Resolve #2015 2019-01-10 19:33:45 +02:00
Ivan Kravets
02937216b0 Fix "TypeError : startswith first arg" when checking udev rules with PY3 // Resolve #2000 2019-01-10 19:33:15 +02:00
Ivan Kravets
e02d7528ad Fix an error "Could not extract item..." when extracting TAR archive with symbolic items on Windows platform // Resolve #2015 2019-01-10 19:14:03 +02:00
Ivan Kravets
68e3f9dc00 Fix "Runtime Error: Dictionary size changed during iteration" // Resolve #2003 2019-01-09 16:34:55 +02:00
Ivan Kravets
2ae41c8434 Fix "Runtime Error: Dictionary size changed during iteration" // Resolve #2003 2019-01-09 16:34:39 +02:00
Ivan Kravets
aa2bc4a63b Implement "get_file_contents" helper 2018-12-27 14:48:22 +02:00
Ivan Kravets
74218f4f93 Fix PyLint warning for Windows 2018-12-26 22:33:21 +02:00
Ivan Kravets
a60c57ac58 Initial support for Python 3.5+ // Resolve #895 Resolve #1365 2018-12-26 20:54:29 +02:00
Ivan Kravets
fabaadec60 Fix an issue with incorrect detecting of compatibility (LDF) between generic library and Arduino or ARM mbed frameworks 2018-12-22 22:30:23 +02:00
Ivan Kravets
7f697961ec Sync docs 2018-12-21 17:26:13 +02:00
Ivan Kravets
9334f31ff2 Docs: Sync boards 2018-12-20 20:51:34 +02:00
Ivan Kravets
579de32d4e Docs: Remove examples with ESP8266 LD scripts, they can change 2018-12-14 18:38:41 +02:00
Ivan Kravets
c3702391ea Docs: Add RISC-V ASM Video Tutorial 2018-12-13 20:45:35 +02:00
Ivan Kravets
826418a443 Bump version to 3.6.4b1 2018-12-13 17:30:49 +02:00
Ivan Kravets
4dfa885a85 CLion: Improve project portability using "${CMAKE_CURRENT_LIST_DIR}" instead of full path 2018-12-13 17:30:10 +02:00
Ivan Kravets
9f4dde4b5e Use full path to PlatformIO CLI when generate project for IDE 2018-12-13 17:24:08 +02:00
Ivan Kravets
3748219cac Document system PATH for a custom VSCode task 2018-12-12 21:46:28 +02:00
Ivan Kravets
4b55767fb9 Docs: "Custom Build Task" for VSCode 2018-12-12 21:01:13 +02:00
Ivan Kravets
5aef182652 Merge tag 'v3.6.3' into develop
Bump version to 3.6.3
2018-12-12 16:19:26 +02:00
Ivan Kravets
6db47cec2b Merge branch 'release/v3.6.3' 2018-12-12 16:19:25 +02:00
Ivan Kravets
6f8b9d70bc Bump version to 3.6.3 2018-12-12 16:19:14 +02:00
Ivan Kravets
d8cbe99f2c Fix an issue with a broken headers list when generating ".clang_complete" for Emacs // Resolve #1960 2018-12-12 15:50:34 +02:00
Ivan Kravets
a690b8c085 Bump version to 3.6.3b2 2018-12-12 02:51:24 +02:00
Ivan Kravets
b874359482 Ignore *.asm and *.ASM files when building Arduino-based library (compatibility with Arduino builder) 2018-12-12 02:49:42 +02:00
Ivan Kravets
3a18e668c2 Docs: Better explanation about "PlatformIO IDE" 2018-12-12 01:55:54 +02:00
Ivan Kravets
3ca9527da4 Bump version to 3.6.3b1 2018-12-12 01:29:43 +02:00
Ivan Kravets
f539513376 Fixed spurious project's "Problems" for PlatformIO IDE for VSCode when ARM mbed framework is used 2018-12-12 01:28:37 +02:00
Ivan Kravets
afdfaeec68 Check if "_lockfile" attribute exists 2018-12-03 18:31:12 -08:00
Ivan Kravets
676c87d081 Allow to override platform "package_repositories" 2018-11-30 01:36:50 +02:00
Ivan Kravets
db3b0499c9 Merge branch 'release/v3.6.2' 2018-11-29 18:02:58 +02:00
Ivan Kravets
98032ec548 Merge tag 'v3.6.2' into develop
Bump version to 3.6.2
2018-11-29 18:02:58 +02:00
Ivan Kravets
8ef6ea8053 Bump version to 3.6.2 2018-11-29 18:02:49 +02:00
Ivan Kravets
d87ee0b286 Bump docs 2018-11-29 18:00:52 +02:00
Ivan Kravets
6f01f10f59 YAPF 2018-11-29 17:59:29 +02:00
Ivan Kravets
59a0d2b618 Bump version to 3.6.2rc2 2018-11-29 16:02:59 +02:00
Ivan Kravets
16df5474e4 VSCode IntelliSense config: Typo fix with useless bracket 2018-11-29 15:59:22 +02:00
Ivan Kravets
33ea6ef123 Be in silence when debug interpreter is run 2018-11-29 15:21:06 +02:00
Ivan Kravets
a485e563f0 Bump version to 3.6.2rc1 2018-11-29 00:52:36 +02:00
Ivan Kravets
cf35f9dbf8 Only patch versions are allowed for "contrib-pysite" 2018-11-28 21:32:37 +02:00
Ivan Kravets
710b150fcd Switch PIO Home to native WebSockets (next step to PY3) 2018-11-28 17:28:14 +02:00
Ivan Kravets
13731b4461 Switch PIO Home to native WebSockets (next step to PY3) 2018-11-28 17:23:33 +02:00
Ivan Kravets
3d52710935 Bump version to 3.6.2b6 2018-11-27 00:55:30 +02:00
Ivan Kravets
d475f44e49 Escape string when generating manifest for VSCode C/C++ IntelliSense service 2018-11-27 00:54:59 +02:00
Ivan Kravets
7574798a3a Document "erase" target 2018-11-24 15:51:50 +02:00
Ivan Kravets
9ef8d4cfe0 Docs: Grammar fixes 2018-11-24 14:30:21 +02:00
Ivan Kravets
b42d0efa73 Bump version to 3.6.2b5 2018-11-21 15:00:52 +02:00
Ivan Kravets
4a17a9b5b3 Improved IntelliSense for PlatformIO IDE for VSCode via passing extra compiler information for C/C++ Code Parser 2018-11-21 15:00:13 +02:00
Ivan Kravets
d3909bdfa2 Bump version to 3.6.2b4 2018-11-21 00:52:54 +02:00
Ivan Kravets
a2b0b2893b LDF: Stop handling "define" and "undef" when condition fails; handle CPP files in "chain+" and "deep+" modes // Resolve #1930 2018-11-21 00:52:34 +02:00
Ivan Kravets
9d2499ab98 Bump version to 3.6.2b3 2018-11-20 01:23:55 +02:00
Ivan Kravets
579a973512 Handle CWD when searching for a file // Resolve #1930 2018-11-20 01:23:34 +02:00
Ivan Kravets
b861e9c192 Document in library.json how to pass flags to a global build environment 2018-11-20 00:50:52 +02:00
Ivan Kravets
375006ee65 Bump version to 3.6.2b2 2018-11-19 22:30:52 +02:00
Ivan Kravets
23af9c9027 Fix an issue when Library Dependency Finder (LDF) finds spurious dependencies in `chain+ and deep+` modes // Resolve #1930 2018-11-19 22:29:53 +02:00
Ivan Kravets
7322df26ad Fix an issue when Library Dependency Finder (LDF) does not handle project src_filter // Resolve #1905 2018-11-19 19:06:56 +02:00
Ivan Kravets
32bb9c9d83 Bump version to 3.6.2b1 2018-11-19 17:46:19 +02:00
Ivan Kravets
b22ca10f8c Prepend CPPATH of library dependencies instead of appending // Resolve #1914 2018-11-19 17:45:53 +02:00
Ivan Kravets
95beb03aad Bump version to 3.6.2a3 2018-11-18 23:54:42 +02:00
Ivan Kravets
f65ab58c88 Go over 8010-8100 TCP ports when shutting down PIO Home server 2018-11-18 23:53:47 +02:00
Ivan Kravets
c06a018d88 Docs: Add support for OLIMEX ESP32-PRO 2018-11-05 18:32:58 +02:00
Ivan Kravets
7789e3bc62 Rename "System" to "Hardware" for board spec 2018-11-04 17:24:39 +02:00
Ivan Kravets
1287e51bf8 Add info about "EN" pin for ESP32 and debug probes 2018-11-04 13:13:34 +02:00
Ivan Kravets
151823f80e Fix pinouts for oddWires IOT-Bus JTAG 2018-11-02 15:48:12 +02:00
Ivan Kravets
09d58d0d49 Update docs for ESP8266 lwIP profiles 2018-11-02 12:54:09 +02:00
Ivan Kravets
0a6fb68840 Bump version to 3.6.2a2 2018-10-30 06:40:36 +02:00
Ivan Kravets
38fb5b2234 Typo fix 2018-10-30 06:40:11 +02:00
Ivan Kravets
ab6a323aca Fixed an issue with VSCode IntelliSense warning about the missed headers located in "include" folder 2018-10-30 00:27:29 +02:00
Ivan Kravets
50ed828e7a Bump version to 3.6.2a1 2018-10-30 00:14:58 +02:00
Ivan Kravets
692af90161 Fix incorrect wording when initializing/updating project 2018-10-30 00:14:06 +02:00
Ivan Kravets
543a1dddae Sync docs 2018-10-29 22:38:20 +02:00
Ivan Kravets
fce84b5a48 Add debugging support using TIAO USB Multi-Protocol adapter (TUMPA) 2018-10-29 22:27:47 +02:00
Ivan Kravets
67a6f66a35 Add support for oddWires IoT-Bus Io debug tool 2018-10-29 19:23:06 +02:00
Ivan Kravets
fdbebb178c Merge tag 'v3.6.1' into develop
Bump version to 3.6.1
2018-10-29 14:10:57 +02:00
Ivan Kravets
0747fe9dea Merge branch 'release/v3.6.1' 2018-10-29 14:10:56 +02:00
Ivan Kravets
331cd0aa0d Bump version to 3.6.1 2018-10-29 14:10:42 +02:00
Ivan Kravets
8b74b12990 Don't recreate git ignore and travis configs when project is already inited 2018-10-29 14:02:29 +02:00
Ivan Kravets
7a0c1e13f3 Bump version to 3.6.1rc7 2018-10-28 00:39:42 +03:00
Ivan Kravets
e94d758131 Use "items" instead of "iteritems" (PY2/3) // Issue #895 2018-10-27 20:51:55 +03:00
Ivan Kravets
080369f597 Make "print" compatible between Py2 & Py3 2018-10-27 20:22:11 +03:00
Ivan Kravets
729178731c Improve a loading speed of PIO Home "Recent News" 2018-10-27 20:07:07 +03:00
Ivan Kravets
5c278b54f7 Use "super" when calling parent class // Issue #895 2018-10-27 15:24:10 +03:00
Ivan Kravets
2007491be9 Don't override existing ".gitignore" file 2018-10-27 14:20:33 +03:00
Ivan Kravets
e96078b4e3 Exclude upcoming ".pio" from VCS 2018-10-27 14:18:47 +03:00
Ivan Kravets
118f22bed3 PyLint fix 2018-10-26 01:27:57 +03:00
Ivan Kravets
2134022565 Print board's configuration URL 2018-10-26 01:27:06 +03:00
Ivan Kravets
cf2a2395e5 Sync new Atmel AVR boards 2018-10-25 19:52:55 +03:00
Ivan Kravets
8947b63e41 Better formatting when asking to remove a file 2018-10-25 14:12:09 +03:00
Ivan Kravets
fc8bffdd81 Ask user to remove manually a file on exception 2018-10-25 14:03:52 +03:00
Ivan Kravets
75105e18ba Wait 1 seconds on Windows when PIO Home shuts down 2018-10-25 13:48:47 +03:00
Ivan Kravets
3507290a20 Shutdown PIO Home server before updating tool-pioplus; Update tool-pioplus to 1.4.11 2018-10-25 13:44:41 +03:00
Ivan Kravets
7cc4e8ce15 Bump version to 3.6.1rc6 2018-10-24 01:21:02 +03:00
Ivan Kravets
08dc5dec89 Revert "Cache loaded project config"
This reverts commit bfee896378.
2018-10-24 01:19:54 +03:00
Ivan Kravets
d92349c8f7 Add "reset" support for "memoized" 2018-10-24 01:19:39 +03:00
Ivan Kravets
92289d373b Add example with $PROJECT_HASH for Windows 2018-10-24 00:23:10 +03:00
Ivan Kravets
4b9e8f0ba4 Added $PROJECT_HASH template variable for build_dir 2018-10-23 22:55:26 +03:00
Ivan Kravets
bfee896378 Cache loaded project config 2018-10-23 22:27:18 +03:00
Ivan Kravets
e4c112608b Docs: Move "Custom target" to upper level 2018-10-23 19:21:25 +03:00
Ivan Kravets
04eb531ac2 Add more example with a custom target 2018-10-23 19:12:02 +03:00
Ivan Kravets
8e3020c0f8 Sync docs 2018-10-23 18:09:43 +03:00
Ivan Kravets
51acd02421 Bump version to 3.6.1rc5 2018-10-22 16:49:08 +03:00
Ivan Kravets
8a1b94b48c Process `build_unflags` for cloned environment when building a static library 2018-10-22 16:33:30 +03:00
Ivan Kravets
e11013189b Docs: Move library manager CLI to userguide 2018-10-19 22:07:00 +03:00
Ivan Kravets
98deefc4f5 Bump version to 3.6.1rc4 2018-10-19 17:48:00 +03:00
Ivan Kravets
058a5e854d Skip aceinna_imu from linux builds 2018-10-19 16:50:51 +03:00
Ivan Kravets
7b998c8cda Fix an issue with incorrect handling of a custom package name 2018-10-19 16:37:15 +03:00
Ivan Kravets
98a1fd79b6 Revert back "Handle first part for package name" 2018-10-19 16:13:55 +03:00
Ivan Kravets
e344194f86 Handle first part for package name 2018-10-19 15:58:43 +03:00
Ivan Kravets
05b656e6b0 Update README for "include", "lib", and "test" directories 2018-10-17 21:56:27 +03:00
Ivan Kravets
9c30472777 Generate "test" directory per project 2018-10-17 21:16:09 +03:00
Ivan Kravets
016caa731d Rename "readme.txt" to README for "include" and "lib" project folder; don't create these folders if they were delated before 2018-10-17 19:58:38 +03:00
Ivan Kravets
5b0befef45 Drop support for Freescale Kinetis FRDM-KL26Z, include Aceinna in platforms list 2018-10-17 14:48:53 +03:00
Ivan Kravets
4b588a589d Add Aceinna dev/platform 2018-10-17 14:11:54 +03:00
Ivan Kravets
1598b0632a Sync docs 2018-10-17 14:03:19 +03:00
Ivan Kravets
a32c67a0ce Bump version to 3.6.1rc3 2018-10-17 01:47:08 +03:00
Ivan Kravets
1183105557 Revert back an clang includes list without quotes for Atom 2018-10-17 01:46:16 +03:00
Ivan Kravets
d1e4f22e7f Add docs for JTAG and SWD connectors 2018-10-16 23:01:40 +03:00
Ivan Kravets
8a5b3a90cb Bump version to 3.6.1rc2 2018-10-13 19:32:54 +03:00
Ivan Kravets
2b53ecb111 Improve PIO Unified Debugger for "mbed" framework and fix issue with missed local variables 2018-10-13 19:32:31 +03:00
Ivan Kravets
0159b1cf7f Fixed an issue with broken includes when generating `.clang_complete` and space is used in path // Issue #1873 2018-10-12 23:04:12 +03:00
José Antonio de la Torre
d9dd83e327 Solved issues with vim whitespaces in paths (#1873)
When a library has whitespaces in the name the path
will contain whitespace too. When vim tries to decode
path it will fail.

This fix wrap each path with quotes.
2018-10-12 22:41:13 +03:00
Ivan Kravets
05fe52bda9 Bump version to 3.6.1rc1 2018-10-12 22:31:11 +03:00
Ivan Kravets
6294580e25 Show a valid error when Internet is off-line while initializing a new project // Resolve #1784 2018-10-12 22:30:28 +03:00
Ivan Kravets
69d01c4bc1 Fix an issue when `pio run -t monitor always uses first monitor_port` even with multiple environments // Resolve #1841 2018-10-12 21:57:57 +03:00
Ivan Kravets
d4e553fb5a Generate an "include" directory with a README file when initializing a new project 2018-10-12 21:49:02 +03:00
Ivan Kravets
ff8fefb797 Report about outdated 99-platformio-udev.rules // Resolve #1823 2018-10-12 19:35:58 +03:00
Ivan Kravets
b77fb79cd6 Sync docs 2018-10-12 16:02:35 +03:00
Ivan Kravets
00b173f13f Fix an issue when dynamic build flags were not handled correctly // Resolve #1799 2018-10-12 15:09:54 +03:00
Ivan Kravets
13ff30788e Sync docs 2018-10-12 15:06:09 +03:00
Ivan Kravets
842db2643d Docs: Typos in VSCode Watchpoints 2018-10-10 16:20:28 +03:00
Ivan Kravets
aee0c7b9c2 Docs: Fix invalid COMPONENT_EMBED_TXTFILES macro for ESP32 2018-10-10 12:58:16 +03:00
Ivan Kravets
f67cc1770d Document "Watchpoints" for VSCode 2018-10-10 02:19:03 +03:00
Ivan Kravets
159cd7c073 Better explanation about overriding settings for board 2018-10-05 01:25:33 +03:00
Ivan Kravets
e83a11d02a More detailed info about debug per board 2018-10-05 00:36:23 +03:00
Ivan Kravets
ba2275fbba Test windows builds on x86 & x64 2018-10-04 20:20:16 +03:00
Ivan Kravets
59a3a7dd55 Minor tweak to docs 2018-10-04 01:51:21 +03:00
Ivan Kravets
0a7d6fb814 Revert back initial white-space for docs tables 2018-10-04 01:46:30 +03:00
Ivan Kravets
94bf067639 Refactor docs for boards 2018-10-04 01:33:15 +03:00
Ivan Kravets
4cd13b9d47 Bump version to 3.6.1a5 2018-10-02 00:12:29 +03:00
Ivan Kravets
34325dbc4c Support in-line comments for multi-line value in platformio.ini 2018-10-02 00:11:41 +03:00
Ivan Kravets
ec9fbca181 Docs: tutorial for ESP32 2018-09-30 23:32:53 +03:00
Ivan Kravets
e9f2334e59 Fix lib test 2018-09-26 15:25:38 +03:00
Ivan Kravets
c10b8633ab Sync docs 2018-09-23 01:47:35 +03:00
Ivan Kravets
18a8b05214 Rename "fixed" to "detached" for LDF 2018-09-21 19:23:08 +03:00
Ivan Kravets
22ceae0149 * Do not re-create ".gitignore" and ".travis.yml" files if they were removed from a project 2018-09-20 14:57:42 +03:00
Ivan Kravets
e6fa8654ad YAPF 2018-09-20 14:55:55 +03:00
Ivan Kravets
24f97ef768 Introduce RISC-V GAP dev/platform 2018-09-20 13:56:42 +03:00
Ivan Kravets
f0a91df2cf Fix incorrect activation commands for PIO Core Installation (Virtual Environment) 2018-09-19 16:12:57 +03:00
Ivan Kravets
a3e3c30d0d Docs: Add "Configuration" group to Library Manager 2018-09-19 16:03:43 +03:00
Ivan Kravets
421694ce0c Sync docs 2018-09-10 22:37:25 +03:00
Ivan Kravets
3c4d978c1c Document URL Handlers for device port monitor // Resolve #1838 2018-09-10 21:20:28 +03:00
Ivan Kravets
e5fc18fddb Sync docs 2018-09-06 22:50:59 +03:00
Ivan Kravets
535048c420 Bump version to 3.6.1a4 2018-09-06 22:26:43 +03:00
Ivan Kravets
b7ac59066f Revert back "PIO Debug (skip Pre-Debug)" debug configuration for VSCode 2018-09-06 22:21:46 +03:00
Ivan Kravets
4b2a63db1f Bump version to 3.6.1a3 2018-09-06 16:35:03 +03:00
Ivan Kravets
a477e8cb23 Default VSCode Debug configuration without Pre-Debug 2018-09-06 16:34:27 +03:00
Ivan Kravets
7108b2fdd4 Introduce "Release" and "Debug" Build Configurations 2018-09-06 14:42:37 +03:00
Ivan Kravets
e6e629d2c5 Bump version to 3.6.1a2 2018-09-06 02:26:14 +03:00
Ivan Kravets
f54d32843a Add "debug" target, update docs for "uploads" option // Resolve #1833 2018-09-06 02:25:28 +03:00
Ivan Kravets
ce47b6f69f Docs: update tutorials 2018-09-06 01:26:08 +03:00
Ivan Kravets
4f0c60edfa Clean cache on PIO Core update 2018-09-02 19:32:45 +03:00
David Hasenfratz
6caa7f30ac Fix typos (#1819) 2018-08-30 20:22:36 +03:00
Ivan Kravets
b43f243f6a Sync docs 2018-08-28 22:08:28 +03:00
Ivan Kravets
abbe30ef97 Docs: Add info about drivers to the tutorial requirements // Resolve #1802 2018-08-27 19:21:12 +03:00
Ivan Kravets
8d1ff91af1 Bump version to 3.6.1a1 2018-08-27 18:56:06 +03:00
Ivan Kravets
78c383eb68 Use Pre-Debug task by its VSCode defination 2018-08-27 18:55:08 +03:00
Ivan Kravets
476a878733 Skip Intel MCS-51 tests for Linux 2018-08-20 20:54:07 +03:00
Ivan Kravets
d109e4756d Initial support for Intel MCS-51 (8051) 2018-08-20 19:37:34 +03:00
Ivan Kravets
d448a0ec5c Switch docs to HTTPS 2018-08-15 19:44:02 +03:00
Ivan Kravets
d009b997bc Auto-dropdown navigation; move "Docs" to the right side 2018-08-15 19:12:41 +03:00
Ivan Kravets
9258763491 Correct docs for SemVer/Deps syntax 2018-08-15 14:38:19 +03:00
Ivan Kravets
79e6df7263 Temporary hook for ReadTheDocs #2971 with a broken "edit" link 2018-08-14 14:36:03 +03:00
Ivan Kravets
4ff013c0fe Improve docs for advanced scripting 2018-08-14 14:24:03 +03:00
Ivan Kravets
71cdc9fe78 Docs: Add compatible platforms, frameworks, and boards per debug tool 2018-08-11 15:34:33 +03:00
Ivan Kravets
e3d17d132a Docs: Improve "Drivers" section for debugging tools 2018-08-10 14:33:36 +03:00
Ivan Kravets
70eedfbeec Merge branch 'release/v3.6.0' 2018-08-06 18:46:23 +03:00
Ivan Kravets
c3d598f488 Merge tag 'v3.6.0' into develop
Bump version to 3.6.0 (issues #1594 #1412 #1462 #1735)
2018-08-06 18:46:23 +03:00
Ivan Kravets
6d5dc60b47 Bump version to 3.6.0 (issues #1594 #1412 #1462 #1735) 2018-08-06 18:43:58 +03:00
Ivan Kravets
129146e82e Bump version to 3.6.0rc1 2018-08-03 21:44:41 +03:00
Ivan Kravets
df923bf17e Add package "lib" folder to LD_PATH 2018-08-03 21:43:40 +03:00
Ivan Kravets
8f19dd50fe Docs: Fix "build_flags" examples with a macro where special chars are used 2018-08-02 17:57:57 +03:00
Ivan Kravets
ab1d1f248c Refactor docs for PIO Unified debug tools 2018-07-30 19:39:31 +03:00
Ivan Kravets
617f51b9ea Improve docs for PIO Unified Debugger 2018-07-30 18:13:04 +03:00
Ivan Kravets
41432d4075 Merge branch 'hotfix/v3.5.5' into develop
* hotfix/v3.5.5:
  Fixed an issue with PIO Remote  when upload process depends on the source code of a project framework
2018-07-30 14:26:35 +03:00
Ivan Kravets
ae964fa729 Fixed an issue with PIO Remote when upload process depends on the source code of a project framework 2018-07-30 14:26:24 +03:00
Ivan Kravets
9a5f9843b9 Bump version to 3.6.0a11 2018-07-28 12:51:52 +03:00
Ivan Kravets
44175f87b1 Merge branch 'hotfix/v3.5.5' into develop
* hotfix/v3.5.5:
  Fix broken unit testing when mbed framework is used
2018-07-28 12:49:33 +03:00
Ivan Kravets
2f2cfc2d84 Fix broken unit testing when mbed framework is used 2018-07-28 12:49:22 +03:00
Ivan Kravets
d9e908fceb Test 3 random examples from each dev/platform 2018-07-27 15:45:51 +03:00
Ivan Kravets
98aa47c885 Drop support for codecov.io 2018-07-27 15:38:46 +03:00
Ivan Kravets
c777b0095d Merge branch 'hotfix/v3.5.5' into develop
* hotfix/v3.5.5:
  Fix an issue when "srcFilter" field in "library.json" breaks a library build // Resolve #1735
  Fix "test_lib" test
2018-07-27 01:27:17 +03:00
Ivan Kravets
9191ea97fe Fix an issue when "srcFilter" field in "library.json" breaks a library build // Resolve #1735 2018-07-27 01:27:05 +03:00
Ivan Kravets
fedf3162f1 Fix "test_lib" test 2018-07-27 00:48:13 +03:00
Ivan Kravets
89fc77d87a Docs: Add Community link in TOP menu 2018-07-26 20:46:43 +03:00
Ivan Kravets
2004c9b079 Fix "test_lib" test 2018-07-26 20:46:21 +03:00
Ivan Kravets
5aaa9cf205 Fix "Home: Internal Store Exception" // Resolve #1756 2018-07-25 22:25:47 +03:00
Ivan Kravets
9b15ec417b Document solution for "ImportError: cannot import name _remove_dead_weakref" 2018-07-25 15:58:47 +03:00
Ivan Kravets
42540d4207 Docs: Fix broken example for "Dynamic build flags" 2018-07-23 22:49:25 +03:00
Ivan Kravets
72bfa4a1e2 Bump version to 3.6.0a10 2018-07-20 13:35:52 +03:00
Ivan Kravets
7b8342cd9a Merge branch 'hotfix/v3.5.5' into develop
* hotfix/v3.5.5:
  Typo fix
2018-07-20 13:35:22 +03:00
Ivan Kravets
a206b2e4fd Typo fix 2018-07-20 13:35:06 +03:00
Ivan Kravets
6e8ce56206 Disable requirements status temporary 2018-07-20 02:10:50 +03:00
Ivan Kravets
7c2c0ba1aa Bump version to 3.6.0a9 2018-07-20 02:09:40 +03:00
Ivan Kravets
f130b5bfb6 Disable requirements status temporary 2018-07-20 02:07:07 +03:00
Ivan Kravets
bf23d85005 Merge branch 'hotfix/v3.5.5' into develop
* hotfix/v3.5.5:
  Add "test_build_project_src" option for PIO Unit Testing
2018-07-20 02:05:01 +03:00
Ivan Kravets
903b41b336 Add "test_build_project_src" option for PIO Unit Testing 2018-07-20 02:04:40 +03:00
Ivan Kravets
ab24ca4ff6 Cleanup 2018-07-20 00:33:24 +03:00
Ivan Kravets
fd8b603910 Update README 2018-07-19 19:00:09 +03:00
Ivan Kravets
e4462d7546 Add Infineon XMC dev/platform // Resolve #471 2018-07-19 16:19:10 +03:00
Ivan Kravets
aa796959c9 Merge branch 'hotfix/v3.5.5' into develop
* hotfix/v3.5.5:
  Fix PIO Unit Testing issue when ``UNIT_TEST`` macro was not set in a build environment
  Append __PLATFORMIO_DEBUG__ macro in debug session
  Add udev rules for J-Link devices
  Disable exec command for Sublime Text debugger

# Conflicts:
#	HISTORY.rst
2018-07-19 15:28:58 +03:00
Ivan Kravets
ff3ce2d69e Fix PIO Unit Testing issue when `UNIT_TEST` macro was not set in a build environment 2018-07-19 15:27:00 +03:00
Ivan Kravets
ff59dcefe0 Append __PLATFORMIO_DEBUG__ macro in debug session 2018-07-19 01:44:12 +03:00
Ivan Kravets
3f2f79ade4 Add udev rules for J-Link devices 2018-07-19 01:43:31 +03:00
Ivan Kravets
bc380714bd Disable exec command for Sublime Text debugger 2018-07-19 01:43:15 +03:00
Ivan Kravets
2ba41cddc4 Disable exec command for Sublime Text debugger 2018-07-17 20:58:20 +03:00
Ivan Kravets
4a14cc686c Add udev rules for J-Link devices 2018-07-17 20:57:41 +03:00
Ivan Kravets
734cb5c7aa Bump version to 3.6.0a8 2018-07-17 16:24:38 +03:00
Ivan Kravets
da89f57046 PIO Home 1.0.0; PIO Plus 1.4.0 2018-07-17 16:24:02 +03:00
Ivan Kravets
4a3b616b0f Sync docs 2018-07-16 17:45:52 +03:00
Ivan Kravets
a14f2d291e Improve checking of package structure after unpacking // Issue #1462 2018-07-15 01:06:59 +03:00
Ivan Kravets
72d260c295 Fix file locking of package installer // Issue #1594 2018-07-15 00:43:12 +03:00
Ivan Kravets
e1578dabac Lock interprocess requests to PlatformIO Package Manager for install/uninstall operations // Resolve #1462 2018-07-14 22:10:56 +03:00
Ivan Kravets
f2c4ba1895 Check item after unpacking only if not symbolic link 2018-07-13 13:10:24 +03:00
Ivan Kravets
695a850979 Bump version to 3.6.0a7 2018-07-13 12:16:44 +03:00
Ivan Kravets
1d7d518ec5 Temporary disable checking of extracted item from archive 2018-07-13 12:15:07 +03:00
Ivan Kravets
44a926b30a Check package structure after unpacking and raise error when antivirus tool blocks PlatformIO package manager // Resolve #1462 2018-07-13 01:54:37 +03:00
Ivan Kravets
735cfbf850 Fix "Cannot uninstall 'pyparsing'" for macOS CI build 2018-07-13 00:25:50 +03:00
Ivan Kravets
6b6c60e82c Fix "Cannot uninstall 'pyparsing'" for macOS CI build 2018-07-13 00:04:16 +03:00
Ivan Kravets
cb7717eaf6 Update docs for creating a custom dev/platform 2018-07-12 20:52:25 +03:00
Ivan Kravets
28a76eb389 Update ISSUE_TEMPLATE.md 2018-07-12 01:26:02 +03:00
Ivan Kravets
0fdfb273c6 Update ISSUE_TEMPLATE.md 2018-07-12 01:23:59 +03:00
Ivan Kravets
eced1c4c2a Update ISSUE_TEMPLATE.md 2018-07-12 01:23:24 +03:00
Ivan Kravets
7d6192b069 Update ISSUE_TEMPLATE.md 2018-07-12 01:22:18 +03:00
Ivan Kravets
23f0ffdfeb Append __PLATFORMIO_DEBUG__ macro in debug session 2018-07-10 15:54:46 +03:00
Ivan Kravets
f7ac71d48e Docs: `projenv` is available only for POST-type scripts 2018-07-10 00:59:01 +03:00
Ivan Kravets
9af715e872 Improve docs for Advanced Scripting section 2018-07-08 18:58:04 +03:00
Ivan Kravets
dae50a32c0 Docs: Info about connection Vbus [CN3-1] to Vcc [CN3-3] of FT2232H Mini-Module 2018-07-07 20:34:34 +03:00
Ivan Kravets
ca37190da4 Update docs for PIO Unified Debugger; add wiring connections and debug probes pictures 2018-07-07 01:35:52 +03:00
Ivan Kravets
7c5c5b5f70 Bump version to 3.6.0a6 2018-07-06 15:26:45 +03:00
Ivan Kravets
83ccf96f36 Merge branch 'hotfix/v3.5.5' into develop
* hotfix/v3.5.5:
  Export extra flash images for IDE
  Update core dependencies
2018-07-06 15:26:01 +03:00
Ivan Kravets
c1f4b729ea Export extra flash images for IDE 2018-07-06 15:25:51 +03:00
Ivan Kravets
1c8ac97073 Update core dependencies 2018-07-06 15:25:26 +03:00
Ivan Kravets
fd88a249b4 Update core dependencies 2018-07-06 15:23:23 +03:00
Ivan Kravets
d8329a6868 ThingForward: First steps with PlatformIO’s Unified Debugger 2018-07-05 18:53:47 +03:00
Ivan Kravets
5c48233259 Docs: Install PIO Core into Virtual Environment 2018-07-05 17:49:27 +03:00
Ivan Kravets
5efe0e4f8c Merge branch 'hotfix/v3.5.5' into develop
* hotfix/v3.5.5:
  Shorten a name for VSCode debug launch configurations
2018-07-04 00:06:54 +03:00
Ivan Kravets
8f88939aa0 Shorten a name for VSCode debug launch configurations 2018-07-04 00:06:44 +03:00
Ivan Kravets
a58535d95c Bump version to 3.6.0a5 2018-07-03 15:15:44 +03:00
Ivan Kravets
a4173f5de1 Merge tag 'v3.5.4' into develop
Bump version to 3.5.4

# Conflicts:
#	HISTORY.rst
#	platformio/__init__.py
2018-07-03 15:14:28 +03:00
Ivan Kravets
dc3973b046 Merge branch 'hotfix/v3.5.4' 2018-07-03 15:11:32 +03:00
Ivan Kravets
7a5af4b180 Bump version to 3.5.4 (issues #1712, #1705, #1023, #1254, #1658, #1054, #1683, #1343, #1665) 2018-07-03 15:10:39 +03:00
Ivan Kravets
25b562e1c1 Added workaround for Python SemVer package's issue 61 with caret range and pre-releases 2018-07-03 14:55:48 +03:00
Ivan Kravets
6dada01e70 Disable macOS frameworks for VSCode IntelliSense 2018-07-03 14:17:38 +03:00
Ivan Kravets
3956dae01e Sync docs 2018-07-02 18:02:00 +03:00
Ivan Kravets
19711d75e0 Merge branch 'hotfix/v3.5.4' into develop
* hotfix/v3.5.4:
  Typo fix
2018-06-30 21:05:40 +03:00
Ivan Kravets
5b1b05cd09 Typo fix 2018-06-30 21:05:20 +03:00
Ivan Kravets
3e0feeabb4 Bump version to 3.6.0a4 2018-06-30 19:48:30 +03:00
Ivan Kravets
e21ac05e71 Merge branch 'hotfix/v3.5.4' into develop
* hotfix/v3.5.4:
  Improve removing of default build flags using `build_unflags` option // Resolve #1712
  Export ``LIBS``, ``LIBPATH``, and ``LINKFLAGS`` data from project dependent libraries to the global build environment
  Replace "env" pattern by "sysenv" in "platformio.ini" // Resolve #1705
2018-06-30 19:36:02 +03:00
Ivan Kravets
4adc73ebe2 Improve removing of default build flags using build_unflags option // Resolve #1712 2018-06-30 19:34:24 +03:00
Ivan Kravets
357e70e5bb Export `LIBS, LIBPATH, and LINKFLAGS` data from project dependent libraries to the global build environment 2018-06-30 18:24:50 +03:00
Ivan Kravets
ca3567df1e Replace "env" pattern by "sysenv" in "platformio.ini" // Resolve #1705 2018-06-29 19:55:29 +03:00
Ivan Kravets
9bd033e288 Update ESP32 boards flash size // Resolve #30 2018-06-29 19:29:32 +03:00
Ivan Kravets
7564e00fc4 Introduce Premium Support 2018-06-29 17:01:13 +03:00
Ivan Kravets
f1a8add795 Merge branch 'hotfix/v3.5.4' into develop
* hotfix/v3.5.4:
  Switch to PIO Plus support
2018-06-28 23:57:38 +03:00
Ivan Kravets
d6ca30a920 Switch to PIO Plus support 2018-06-28 23:57:16 +03:00
Ivan Kravets
c8f6907d02 Merge branch 'hotfix/v3.5.4' into develop
* hotfix/v3.5.4:
  Export PIOCOREPYSITEDIR to system environment
2018-06-26 01:34:37 +03:00
Ivan Kravets
369868624e Export PIOCOREPYSITEDIR to system environment 2018-06-26 01:34:26 +03:00
Ivan Kravets
dfecc04901 Merge branch 'hotfix/v3.5.4' into develop
* hotfix/v3.5.4:
  Export PIOPYSITEDIR to system environment
2018-06-26 01:33:30 +03:00
Ivan Kravets
e9fe2856ec Export PIOPYSITEDIR to system environment 2018-06-26 01:33:12 +03:00
Ivan Kravets
0ba9b341cd Add new Olimex debug tools for ESP32: ARM-USB-OCD and ARM-USB-TINY 2018-06-26 01:01:37 +03:00
Ivan Kravets
9cff2d3206 Sync docs 2018-06-25 15:52:57 +03:00
Ivan Kravets
ab8497e7ce [VIDEO OVERVIEW] ThingForward - Intro to PIO Unified Debugger using ARM mbed OS and PlatformIO IDE for VSCode 2018-06-25 15:47:01 +03:00
Ivan Kravets
f0cd122952 Merge branch 'hotfix/v3.5.4' into develop
* hotfix/v3.5.4:
  Fix broken history
2018-06-25 15:46:32 +03:00
Ivan Kravets
b83acf4297 Fix broken history 2018-06-25 15:46:21 +03:00
Ivan Kravets
89d403879e Docs: Reorder TOP menu 2018-06-23 19:32:58 +03:00
Ivan Kravets
b7ad64226e Merge branch 'hotfix/v3.5.4' into develop
* hotfix/v3.5.4:
  Fix issue when "platformio lib uninstall" removes initial source code // Resolve #1023
2018-06-21 21:34:07 +03:00
Ivan Kravets
2725d8da8b Fix issue when "platformio lib uninstall" removes initial source code // Resolve #1023 2018-06-21 21:33:56 +03:00
Vladimir Dronnikov
08759700b6 Add udev rule for Maple Leaf board (#1699) 2018-06-21 13:45:43 +03:00
Ivan Kravets
7cac351d25 Bump version to 3.6.0a3 2018-06-20 16:33:13 +03:00
Ivan Kravets
f62bde0e38 Merge branch 'hotfix/v3.5.4' into develop
* hotfix/v3.5.4:
  Handle ConfigParser erros
2018-06-20 16:32:48 +03:00
Ivan Kravets
a9577bc0ba Handle ConfigParser erros 2018-06-20 16:32:38 +03:00
Ivan Kravets
ee69c13b2d Handle ConfigParser erros 2018-06-20 16:31:03 +03:00
Ivan Kravets
3c6f57ac5c Custom tasks for VScode 2018-06-20 15:48:14 +03:00
Ivan Kravets
4d48c365f5 Autogenerate examples for platforms and frameworks 2018-06-16 21:11:31 +03:00
Ivan Kravets
a3cda59d70 Refactor docs menu 2018-06-16 18:41:46 +03:00
Ivan Kravets
22b5e4e5c0 Remove examples with cart range for SemVer (issue with dependent Python package) 2018-06-15 17:53:04 +03:00
Ivan Kravets
19844c89c1 Merge branch 'hotfix/v3.5.4' into develop
* hotfix/v3.5.4:
  Fix preprocessor for Arduino sketch when function returns certain type // Resolve #1683
2018-06-15 15:55:30 +03:00
Ivan Kravets
c055ed4850 Fix preprocessor for Arduino sketch when function returns certain type // Resolve #1683 2018-06-15 15:55:17 +03:00
Ivan Kravets
6f905e319f Merge branch 'hotfix/v3.5.4' into develop
* hotfix/v3.5.4:
  Removed "date&time" when processing project with "platformio run" command // Resolve #1343
  Improve documentation for advanced scripting
2018-06-15 15:03:15 +03:00
Ivan Kravets
389783adae Removed "date&time" when processing project with "platformio run" command // Resolve #1343 2018-06-15 14:53:48 +03:00
Ivan Kravets
46a62de14c Improve documentation for advanced scripting 2018-06-15 14:33:05 +03:00
Ivan Kravets
38c74b3f78 Merge branch 'hotfix/v3.5.4' into develop
* hotfix/v3.5.4:
  Handle "architectures" data from "library.properties" manifest in `lib_compat_mode = strict`
2018-06-12 13:47:29 +03:00
Ivan Kravets
92fc308590 Handle "architectures" data from "library.properties" manifest in lib_compat_mode = strict 2018-06-12 13:47:16 +03:00
Ivan Kravets
0f9c213796 Bump version to 3.6.0a2 2018-06-11 22:55:28 +03:00
Ivan Kravets
a6831d9783 Merge branch 'hotfix/v3.5.4' into develop
* hotfix/v3.5.4:
  Isolate build environment for "BuildSources" nodes
  Append a main LD script at the beginning
  Bump version to 3.5.4a1
  Fixed issue with invalid LD script if path contains space
  Don't export ``CPPPATH`` of project dependent libraries to frameworks // Resolve #1665
  YAPF

# Conflicts:
#	HISTORY.rst
#	platformio/__init__.py
#	platformio/builder/tools/pioupload.py
2018-06-11 18:41:39 +03:00
Ivan Kravets
2ba7c47603 Temporary disable raising error when program data size excesses declared in board manfiest 2018-06-10 01:56:48 +03:00
Ivan Kravets
786d505ecb Isolate build environment for "BuildSources" nodes 2018-06-10 01:27:50 +03:00
Ivan Kravets
00c0eaed8a Append a main LD script at the beginning 2018-06-09 14:50:54 +03:00
Ivan Kravets
46c904e67d Bump version to 3.5.4a1 2018-06-09 01:37:38 +03:00
Ivan Kravets
f9fde5d627 Fixed issue with invalid LD script if path contains space 2018-06-09 00:48:42 +03:00
Ivan Kravets
75754a4750 Don't export `CPPPATH` of project dependent libraries to frameworks // Resolve #1665 2018-06-08 21:38:41 +03:00
Ivan Kravets
a584ac1da2 YAPF 2018-06-08 21:37:57 +03:00
Ivan Kravets
2ff88837ec Sync docs 2018-06-08 18:37:05 +03:00
Ivan Kravets
4528ca0365 Bump version to 3.6.0a1 2018-06-04 16:38:53 +03:00
Ivan Kravets
bfc94d36e3 Introduce "Program Memory Usage" 2018-06-04 14:09:48 +03:00
Ivan Kravets
2fb8128791 YAPF 2018-06-02 16:14:58 +03:00
Ivan Kravets
20c1ce40d3 Check maximum allowed firmware size for uploading with "pio run --target checkprogsize" // Resolve #1412 2018-06-01 18:07:47 +03:00
Ivan Kravets
ecaa9d90b3 Continue work on PIO Core 3.5.4 2018-06-01 17:02:49 +03:00
Ivan Kravets
c0b069c920 Merge branch 'release/v3.5.3' 2018-06-01 17:01:46 +03:00
Ivan Kravets
551f0c1514 Merge tag 'v3.5.3' into develop
Bump version to 3.5.3
2018-06-01 17:01:46 +03:00
Ivan Kravets
7db04b1c3f Bump version to 3.5.3 (issue #1641 issue #1612 issue #1473 issue #1528 issue #1546 issue #1282 issue #1516 issue #1381 issue #1474) 2018-06-01 17:01:32 +03:00
Ivan Kravets
32dbf22d44 ESP32: Calculate an absolute path for a custom partitions table 2018-05-31 20:03:03 +03:00
Ivan Kravets
3243a84dba Fix incorrect handling of C/C++ standards passed via build_flags 2018-05-31 16:38:33 +03:00
Ivan Kravets
f465befa68 Rename "Standalone" to "Desktop" for IDE 2018-05-31 16:11:22 +03:00
Ivan Kravets
f4b4f5c434 Improve docs for lib_ignore option 2018-05-31 15:21:39 +03:00
Ivan Kravets
ffc94a88fe Sync dccs 2018-05-31 14:31:28 +03:00
Ivan Kravets
fb29c9c0f6 Support old version of monitor_baud option for device monitor 2018-05-30 20:25:59 +03:00
Ivan Kravets
df437995df Enable C++ exceptions for ESP32 and ESP-IDF 2018-05-30 19:12:30 +03:00
Ivan Kravets
e4440ed94c Bump version to 3.5.3rc2 2018-05-30 14:16:46 +03:00
Ivan Kravets
b213a302e3 Handle _MCU and _F_CPU variables for AVR native // Resolve #1641 2018-05-30 14:14:42 +03:00
Ivan Kravets
d50dfe19d9 Bump version to 3.5.3rc1 2018-05-26 01:04:38 +03:00
Ivan Kravets
9ba5dc0a60 Override any option from board manifest in Project Configuration File "platformio.ini" // Resolve #1612 2018-05-26 01:02:52 +03:00
Ivan Kravets
5011c3e21c API to update BoardConfig manifest 2018-05-25 21:18:08 +03:00
Ivan Kravets
e48e15b014 Fix "memoized" helper when "expire" is not used 2018-05-25 21:13:47 +03:00
Ivan Kravets
357c932a88 Fix broken link 2018-05-25 19:06:23 +03:00
Ivan Kravets
2f07a58e4f Split stable/upstream docs for dev/platforms 2018-05-25 16:17:02 +03:00
Ivan Kravets
4a2594c12e Docs: revert back to 'sphinx' theme for Pygments 2018-05-25 15:31:31 +03:00
Ivan Kravets
8cda6db02d Rename LDF compatibility mode from "light" to "soft" 2018-05-25 01:46:53 +03:00
Ivan Kravets
f7053928f0 Better explanation how to switch between stable/upstream dev/platforms 2018-05-15 17:22:03 -07:00
Ivan Kravets
e22335984f Default debugging configuration for ESP-WROVER-KIT 2018-05-15 15:23:09 -07:00
Ivan Kravets
6a1a1956c8 Docs: add ft2232h as debug tool 2018-05-15 15:13:11 -07:00
Ivan Kravets
98852caefa Bump version to 3.5.3b5 2018-05-15 14:06:12 -07:00
Ivan Kravets
e399c6b363 Fix issue with monitor_speed option 2018-05-15 14:05:29 -07:00
Ivan Kravets
cb2c3b1b63 Bump version to 3.5.3b4 2018-05-14 22:14:10 -07:00
Ivan Kravets
19003ea51b Simplify configuration for PIO Unit Testing 2018-05-14 22:13:42 -07:00
Ivan Kravets
29064b6c63 Rename "monitor_baud" option to "monitor_speed" 2018-05-14 18:53:16 -07:00
Ivan Kravets
ba352454ed RISC-V dev/platform; Debug for ESP32 2018-05-11 20:02:33 +03:00
Ivan Kravets
5ee194b2b9 Document "Debug Level" for ESP32 2018-05-11 03:06:28 +03:00
Ivan Kravets
9d566d8905 Add debugger to env PATH 2018-05-11 03:06:18 +03:00
Ivan Kravets
b310c57136 Document the missed "--project-dir" and "--environment" options for pio device monitor 2018-05-09 15:35:06 +03:00
Ivan Kravets
9aa5f16b49 Update link to PIO Unified Debugger / Community 2018-05-08 21:31:55 +03:00
Ivan Kravets
4fac523811 Bump version to 3.5.3b3 2018-05-08 18:24:13 +03:00
Ivan Kravets
2bb22a86d7 New UI for PIO Unified Debugger and VSCode 2018-05-08 18:23:27 +03:00
Ivan Kravets
39aaae303f Use "debug_init_break" for Eclipse 2018-05-08 18:22:56 +03:00
Ivan Kravets
1310b7b07b Add OTA demo for ESP32 2018-05-05 23:51:59 +03:00
Ivan Kravets
18f6f23271 Fix default OTA port for ESP32 2018-05-05 21:30:18 +03:00
Ivan Kravets
366efacd81 Prepend upload flags instead of "append" 2018-05-05 21:15:50 +03:00
Ivan Kravets
7be1af4241 Do not check if a custom SVD file exists 2018-05-02 12:37:51 +03:00
Ivan Kravets
d0bc40bc24 Update history 2018-05-01 21:16:32 +03:00
Ivan Kravets
73b1d9ccd5 Configure a custom path to SVD file using "debug_svd_path" option 2018-05-01 21:09:32 +03:00
Ivan Kravets
94c27ae30f Update PIO Core deps 2018-05-01 00:58:36 +03:00
Ivan Kravets
b476e298d3 Bump version to 3.5.3b2 2018-04-30 16:50:23 +03:00
Ivan Kravets
c9fa2206ef Normalize SVD path 2018-04-30 12:33:19 +03:00
Ivan Kravets
b1caaa2208 Export path to SVD file for IDEs 2018-04-27 20:37:41 +03:00
Ivan Kravets
f46072f769 Generate beta configuration for the new PIO Debugger for VSCode 2018-04-27 18:01:08 +03:00
Ivan Kravets
7de4d6aeef PyLint fix 2018-04-27 12:57:11 +03:00
Ivan Kravets
31f14274af Ignore idedata event 2018-04-27 01:41:28 +03:00
Ivan Kravets
50c568c232 Fix "RuntimeError: maximum recursion depth exceeded" for library manager // Resolve #1528 2018-04-26 01:49:16 +03:00
Ivan Kravets
3bcc3e07ae Respect a custom "lib_dir" option in platformio.ini // Resolve #1473 2018-04-25 17:15:40 +03:00
Ivan Kravets
2ae169d210 Fix "RuntimeError: maximum recursion depth exceeded" for library manager // Resolve #1528 2018-04-25 16:57:43 +03:00
Ivan Kravets
1c68409a08 Improve support for Black Magic Probe in "uploader" role 2018-04-23 17:30:05 +03:00
Ivan Kravets
f981916f1d Docs: ESP8266 VTables 2018-04-21 01:00:55 +03:00
Ivan Kravets
0a9031e448 Switch to shutil.move instead of os.rename // Resolve #1584 2018-04-20 21:27:52 +03:00
Ivan Kravets
2d1daa756d Docs: Custom lwIP Variant and debug levels for ESP8266 2018-04-20 21:02:52 +03:00
Ivan Kravets
6b6860196a Fix issue with "build_unparse" for string items 2018-04-20 19:10:20 +03:00
Ivan Kravets
ccb63a9ecc Bump version to 3.5.3b1 2018-04-20 15:55:29 +03:00
Ivan Kravets
3ce62fbafe Escape compiler path for Win 2018-04-20 14:00:40 +03:00
Ivan Kravets
b77160d363 Upgrade VSCode CPP manifest to v3 2018-04-20 13:56:04 +03:00
Ivan Kravets
6a04f52620 Add info about "library.json" to README instruction 2018-04-15 06:28:02 +03:00
Ivan Kravets
aa28beddd8 Handle broken JSON files 2018-04-15 06:08:29 +03:00
Ivan Kravets
d0cc3a045e Handle unknown packages when do cleaning // Resolve #1282 2018-04-15 05:48:38 +03:00
Ivan Kravets
02efe4f7f3 Bump version to 3.5.3a9 2018-04-12 18:47:12 -07:00
Ivan Kravets
2c0ca3e437 Update PIO Home and PIO Core+ 2018-04-12 18:46:11 -07:00
Ivan Kravets
aa8de4ff4b Export "docs" from platform manifest 2018-04-12 18:44:38 -07:00
Ivan Kravets
59fe190f20 Better handling of VSCode Terminal IOError 2018-04-05 22:10:28 -07:00
Ivan Kravets
e0fc44aa42 Reinit download session when IOError 2018-04-05 13:08:23 -07:00
Ivan Kravets
e7b5a14e11 Temporary workaround for VSCode's "IOError: PackageManager" issue 2018-04-05 11:06:23 -07:00
Ivan Kravets
0710c094e7 Bump version to 3.5.3a8 2018-04-01 10:31:47 -07:00
Ivan Kravets
1410dd093a Revert back g++ macro from dump list // Issue #1546 2018-04-01 10:28:25 -07:00
Ivan Kravets
d1362c3751 Article: Building a Web Of Things REST-API on an Arduino MKR1000 with PlatformIO 2018-03-27 22:29:26 +03:00
Ivan Kravets
2299383b03 Docs: Update example "J-Link as debugger and uploader" 2018-03-24 15:31:08 +02:00
Ivan Kravets
622e4033c1 Dump g++ macros for IDE 2018-03-24 12:45:00 +02:00
Ivan Kravets
ec9a2b02ea Verify mDNS devices before dumping // Issue #1381 2018-03-23 17:51:45 +02:00
Ivan Kravets
275648a882 Check for non-ASCII chars mDNS service // Issue #1381 2018-03-23 13:54:33 +02:00
Ivan Kravets
5214b32ee3 Print request URL when package fails 2018-03-23 13:50:33 +02:00
Ivan Kravets
c1c2be0b58 Bump version to 3.5.3a7 2018-03-23 12:14:40 +02:00
Ivan Kravets
44fc500c93 Fix issue with incorrect API result 2018-03-23 12:13:59 +02:00
Ivan Kravets
b6d2e1b243 Bump version to 3.5.3a6 2018-03-23 00:09:05 +02:00
Ivan Kravets
d54327f1a9 Refactor @memoized decorator with expiration feature; cache installed boards per platform 2018-03-23 00:08:07 +02:00
Ivan Kravets
0f4ab5b50b Update Unity tool to 2.4.3 2018-03-22 18:18:03 +02:00
Ivan Kravets
ca34da51aa PIO Home: sort folders by name (ignore case), catch ServerError exceptions // Resolve #1454 Resolve #1302 2018-03-22 17:37:51 +02:00
Ivan Kravets
f937eabc1a Handle error connections to the latest news for PIO Home // Resolve #1470 Resolve #1474 Resolve #1478 Resolve #1480 2018-03-22 16:14:11 +02:00
Ivan Kravets
e019341e59 Bump version to 3.5.3a5 2018-03-22 12:11:46 +02:00
Ivan Kravets
50b2bc07dc Add PlatformIO IDE as recommended extension for VSCode's workspace 2018-03-22 12:10:16 +02:00
Ivan Kravets
8f7206b186 Use absolute path for CPP includes when exporting data to IDE 2018-03-22 12:09:36 +02:00
Ivan Kravets
1461953341 Process "unflags" after frameworks 2018-03-21 19:49:45 +02:00
Ivan Kravets
cd3245960b ThingForward, Webinar: Unit Testing for Embedded with PlatformIO and Qt Creator 2018-03-21 19:49:06 +02:00
Ivan Kravets
580c0601cf Add example with POST scripting and changing of build flags in runtime 2018-03-20 19:32:00 +02:00
Ivan Kravets
979a6a80f0 Fix issue which did not allow to override runtime build environment using extra POST script 2018-03-20 19:24:05 +02:00
Ivan Kravets
6f9fac5663 YAPF for test 2018-03-20 16:10:11 +02:00
Ivan Kravets
85730619f4 Ignore ".pytest_cache" from sources 2018-03-20 16:08:22 +02:00
Ivan Kravets
61374f15f1 Fix issue with `build_unflags` option when a macro contains value 2018-03-20 16:06:39 +02:00
Ivan Kravets
ad52f618cf Save data in UTF-8 by default 2018-03-20 01:14:29 +02:00
Ivan Kravets
bbb32607ed Catch UnicodeError when saving content cache 2018-03-20 01:06:05 +02:00
Ivan Kravets
669ef3cc93 Bump version to 3.5.3a4 2018-03-20 00:42:37 +02:00
Ivan Kravets
d47022b8c3 PIO Home: Recent news 2018-03-20 00:42:10 +02:00
Ivan Kravets
c20cd1b464 Do not load automaically JSON from cached resources 2018-03-19 17:16:51 +02:00
Ivan Kravets
3161e5f606 Bump version to 3.5.3a3 2018-03-16 14:13:00 +02:00
Ivan Kravets
233d48fac0 Describe a project with "description" option for "platformio.ini" 2018-03-16 14:12:05 +02:00
Ivan Kravets
218a1dccf6 Fix issue with installing only the one platform package by specified type 2018-03-16 13:33:59 +02:00
Ivan Kravets
02bad10652 Do not show duplicated upload protocols 2018-03-15 20:53:23 +02:00
Ivan Kravets
7495160374 Bump version to 3.5.3a2 2018-03-15 19:53:47 +02:00
Ivan Kravets
3663dc3470 Fix issue with useless project rebuilding for case insensitive file systems (Windows) 2018-03-15 19:53:05 +02:00
Ivan Kravets
d2b34d42f7 Docs: Fix missed "s" for "99-platformio-udev.rules" 2018-03-14 11:36:30 +02:00
Ivan Kravets
b78a151706 Update requirements for PIO Home and PIO Core+ contribs 2018-03-13 22:59:02 +02:00
Ivan Kravets
6a49df7dfe Start a work on PIO Core 3.5.3 2018-03-13 12:02:25 +02:00
Ivan Kravets
f79e2e38ef Merge branch 'release/v3.5.2' 2018-03-13 12:00:28 +02:00
Ivan Kravets
bc323252e8 Bump version to 3.5.2 (issue #1301 issue #1313 issue #1323 issue #1303 issue #1029 issue #1310 issue #1390 issue #1312 issue #1433) 2018-03-13 12:00:01 +02:00
Ivan Kravets
f63a6d73ee Add "include_dir" to known options list // Resolve #1433 2018-03-12 19:22:55 +02:00
Jack
5e6d1d9361 Fix CLion not recognizing includes in lib and .piolibdeps (#1429) 2018-03-12 16:58:08 +02:00
Ivan Kravets
7e875553c2 Allow to control maximum depth of nested includes for conditional PreProcessor 2018-03-08 16:29:09 +02:00
Ivan Kravets
105cd0fa71 Use custom object suffix only for Arduino/Energia frameworks 2018-03-07 23:35:03 +02:00
Ivan Kravets
8676f471f1 Docs: Update url for Sanguino boards 2018-03-07 22:48:21 +02:00
Ivan Kravets
93d524a392 Bump version to 3.5.2rc4 2018-03-07 20:47:09 +02:00
Ivan Kravets
e5b73dcd2b Fix issue when custom board is used with the same ID 2018-03-07 20:46:31 +02:00
Ivan Kravets
ade6c25056 Docs: Arduino Core ESP32 Wiki 2018-03-07 17:01:53 +02:00
Ivan Kravets
e0ce40d6b3 Ability to specify a name for new project 2018-03-07 16:30:21 +02:00
Ivan Kravets
90993ec69f Docs: Show onboard debug tools before 2018-03-07 13:48:59 +02:00
Ivan Kravets
3269d243a8 Firmware memory size explanation: text, data and bss 2018-03-06 12:06:52 +02:00
Ivan Kravets
ef861ed702 Use workspace folder for VSCode CPP tool DB files 2018-03-06 10:38:41 +02:00
Ivan Kravets
b1c9eb9022 Bump version to 3.5.2rc3 2018-03-05 15:51:23 +02:00
Ivan Kravets
3d300414ac Multiple themes (Dark & Light) for PlatformIO Home 2018-03-05 15:50:49 +02:00
Ivan Kravets
3a16ecbaa1 Typo fix 2018-03-04 11:29:03 +02:00
Ivan Kravets
9415b369e1 Bump version to 3.5.2rc2 2018-03-03 14:37:08 +02:00
Ivan Kravets
6ec1890f52 Fix GitHub's "TLSV1_ALERT_PROTOCOL_VERSION" issue when upgrading PIO Core to development version 2018-03-03 14:36:17 +02:00
Ivan Kravets
d1c7f56950 Add example with a custom name for library dependency 2018-03-02 14:40:35 +02:00
Ivan Kravets
2ccb30b0f0 Print VCS version if available in LDF Graph 2018-03-02 14:31:24 +02:00
Ivan Kravets
e95354afeb Bump version to 3.5.2rc1 2018-02-24 01:51:07 +02:00
Ivan Kravets
cfb9ec77ce Keep VSCode CPP DB in workspace 2018-02-24 01:40:49 +02:00
Ivan Kravets
3a52f35fe5 Add "udev" to FAQ 2018-02-20 15:06:35 +02:00
Ivan Kravets
ba0e87b978 Fix issue with mDNS lookup service // Resolve #1310 2018-02-20 14:38:47 +02:00
Ivan Kravets
1cb1af3375 Revert back caching for Travis.CI 2018-02-20 14:29:20 +02:00
Ivan Kravets
7c0cd12f80 Builder: append target suffix to the filename instead of replacing 2018-02-20 01:15:52 +02:00
Ivan Kravets
a3457dfca6 Bump version to 3.5.2b5 2018-02-20 01:11:25 +02:00
Ivan Kravets
cdee242333 Builder: append target suffix to the filename instead of replacing 2018-02-20 01:10:27 +02:00
Ivan Kravets
aa0b6c2071 Sync boards from ST STM32 2018-02-19 20:37:57 +02:00
Ivan Kravets
be306224e3 Document creating of a "Custom build target" 2018-02-17 17:13:30 +02:00
Ivan Kravets
1fce214a6b Bump version to 3.5.2b4 2018-02-16 14:53:00 +02:00
Ivan Kravets
f1f42c6888 Fix issue with PIO Unified Debugger and "debug_load_mode = always" 2018-02-16 14:52:36 +02:00
Ivan Kravets
1d6dcb1c5a Bump version to 3.5.2b3 2018-02-15 19:44:51 +02:00
Ivan Kravets
6b36a29858 Control PIO Unified Debugger and its firmware loading mode using "debug_load_mode" option 2018-02-15 19:44:29 +02:00
Ivan Kravets
18c6fe98ee Search for a library using PIO Library Registry ID 2018-02-15 02:00:12 +02:00
Ivan Kravets
f86885a523 Typo fix 2018-02-13 23:21:19 +02:00
Ivan Kravets
0c2f973412 Mark project source and library directories for CLion IDE // Resolve #1359 Resolve #897 Resolve #1345 2018-02-13 19:24:02 +02:00
Ivan Kravets
591e876660 Move http://platformio.org to https://platformio.org 2018-02-13 01:34:24 +02:00
Ivan Kravets
acefc8d276 Remove debug code 2018-02-13 00:19:07 +02:00
Ivan Kravets
0763a54af3 Add Atmel-ICE debugging tool 2018-02-12 19:32:02 +02:00
Ivan Kravets
d7f7418812 Sync docs with hardware changes 2018-02-12 18:31:31 +02:00
Ivan Kravets
06cce20707 Minor formatting to the system info 2018-02-12 17:27:20 +02:00
Ivan Kravets
b553b8f9df Sort debug tools by name 2018-02-10 18:09:23 +02:00
Ivan Kravets
8736e7bfb0 Bump version to 3.5.2b2 2018-02-10 17:00:45 +02:00
Ivan Kravets
231bd8b294 Implement autodetecting of default debug tool 2018-02-09 21:47:59 +02:00
Ivan Kravets
cc08bb0fd0 Document how to switch between stable release and upstream dev/platform 2018-02-09 14:31:22 +02:00
Ivan Kravets
46cca359e7 Bump version to 3.5.2b1 2018-02-09 01:30:35 +02:00
Ivan Kravets
aac0b29929 Dump only "platform, board and framework" by default when processing environment 2018-02-09 01:23:02 +02:00
Ivan Kravets
f7023aa8ff Print platform information while processing environment 2018-02-07 19:44:02 +02:00
Ivan Kravets
904c5464c3 Add user libraries before built-in (frameworks, toolchains) 2018-02-07 15:28:34 +02:00
Ivan Kravets
31edb2a570 Minor fix 2018-02-06 11:27:44 +02:00
Ivan Kravets
d428d18fae Bump version to 3.5.2a8 2018-02-06 11:26:26 +02:00
Ivan Kravets
e7e80ff152 Fix issue when no environment is specified 2018-02-06 11:25:38 +02:00
Ivan Kravets
1362630ed6 Raise an error when invalid environment name was set for env_default option 2018-02-06 01:54:34 +02:00
Ivan Kravets
e5543b2aee Fix broken RST 2018-02-06 00:36:52 +02:00
Ivan Kravets
53afdc5e02 Fix project generator for Qt Creator IDE // Resolve #1303 Resolve #1323 2018-02-05 21:44:37 +02:00
Ivan Kravets
20641bb4ff Sync docs 2018-02-05 17:30:44 +02:00
Ivan Kravets
33a05fa7ca Update README 2018-02-05 13:16:12 +02:00
Ivan Kravets
f358a4ff57 Ignore unit-testing/calculator from CI test 2018-02-05 12:25:24 +02:00
Ivan Kravets
aa57924488 Fix command:ci test 2018-02-04 01:46:57 +02:00
Ivan Kravets
c5af85f123 Fix issue with multiple OneWire libs and infinite pause 2018-02-04 01:04:53 +02:00
Ivan Kravets
55b8ff7e74 Fold install dev/platform output for CI 2018-02-04 00:08:28 +02:00
Ivan Kravets
8913f1b1ea Don't install desktop dev/platforms 2018-02-03 23:04:46 +02:00
Ivan Kravets
4360ff7463 Use examples from dev/platforms for test 2018-02-03 22:59:41 +02:00
Ivan Kravets
718d1f2de1 Use examples from development platforms 2018-02-03 21:08:45 +02:00
Ivan Kravets
195444b253 Refactor dev/platforms and frameworks docs 2018-02-03 01:34:01 +02:00
Ivan Kravets
17dc5f594f VSCode: Show debug console for each session 2018-02-02 17:51:54 +02:00
Ivan Kravets
3b99dabbf4 Add example with executing of a custom script before upload action 2018-02-01 22:20:26 +02:00
Ivan Kravets
c9e578f977 Do not show debug console by default for VSCode 2018-01-31 01:11:25 +02:00
Ivan Kravets
00782fc624 Cosmetic changes 2018-01-30 23:31:21 +02:00
Ivan Kravets
19d2dfdad0 Bump version to 3.5.2a7 2018-01-30 21:34:10 +02:00
Ivan Kravets
1890162f3f VSCode: add a new "Pre-Debug" task and run it before debugging session 2018-01-30 21:33:56 +02:00
Ivan Kravets
4980d3e4bb Bump version to 3.5.2a6 2018-01-30 15:25:17 +02:00
Ivan Kravets
fc53cb4489 Revert back to SCons 2.0, a lot of issues with non-unicode locales // Issue #895 2018-01-30 15:14:55 +02:00
Ivan Kravets
640aa72cff Minor fix 2018-01-30 14:49:10 +02:00
Ivan Kravets
6235328194 Bump version to 3.5.2a5 2018-01-28 00:28:21 +02:00
Ivan Kravets
332472e84b Save temporary file in unicode for INO2CPP 2018-01-28 00:17:55 +02:00
Ivan Kravets
59fb4b103f Fix issue when project without a specified board can't be uploaded // Resolve #1313 2018-01-27 01:16:37 +02:00
Ivan Kravets
8186aed8d9 Bump version to 3.5.2a4 2018-01-27 00:52:45 +02:00
Ivan Kravets
31700c6bfc Fix issue with detecting media disk when mbed upload protocol is specified 2018-01-27 00:18:32 +02:00
Ivan Kravets
316c2c6e1a Improve calculating of project hash 2018-01-26 22:24:49 +02:00
Ivan Kravets
b6ad672f6a Use SCons "gas" tool instead of "as" 2018-01-26 20:50:33 +02:00
Ivan Kravets
59337c71c1 Upgrad build system to SCons 3.0 // Issue #895 2018-01-26 20:04:43 +02:00
Ivan Kravets
7a40992cc1 Add aliases for LDF compatibility modes 2018-01-26 19:53:07 +02:00
Ivan Kravets
1412f085b8 Minor improvements 2018-01-25 18:12:36 +02:00
Ivan Kravets
6b826abce0 Bump version to 3.5.2a3 2018-01-25 18:03:10 +02:00
Ivan Kravets
f8dafbca80 Show device system information (MCU, Frequency, RAM, Flash, Debugging tools) in a build log 2018-01-25 17:58:52 +02:00
Ivan Kravets
dabe9ba2a7 Show all available upload protocols before firmware uploading 2018-01-25 14:26:15 +02:00
Ivan Kravets
b8fde283fd Use util.get_systype when checking for system 2018-01-24 18:33:41 +02:00
Ivan Kravets
fa738650da Add special prefix for BlackMagic probe for Windows COM ports >= COM10 2018-01-24 17:22:28 +02:00
Ivan Kravets
717a699546 Bump version to 3.5.2a2 2018-01-24 16:10:14 +02:00
Ivan Kravets
f512ccbe68 Fix issue with duplicated "include" records when generating data for IDE // Resolve #1301 2018-01-24 15:53:28 +02:00
Ivan Kravets
de523493b2 Improve support for old mbed libraries without manifest 2018-01-24 14:56:44 +02:00
Ivan Kravets
c0b277d9c8 Handle "os.mbed.com" URL as Mercurial (hg) repository 2018-01-24 14:56:15 +02:00
Ivan Kravets
e615e7529e Fix issue with downloader when dependency URL ends with "/" 2018-01-24 14:34:08 +02:00
Ivan Kravets
86667c5664 Bump version to 3.5.2a1 2018-01-18 22:13:36 +02:00
Ivan Kravets
dcb299e9b9 Use dynamic "build_dir" when checking project for structure chnages 2018-01-18 22:12:32 +02:00
Ivan Kravets
2b4b2eb571 Pass a list iterator directly to "any" or "all" functions 2018-01-18 22:04:43 +02:00
Ivan Kravets
3caa2a9e8d Merge branch 'release/v3.5.1' into develop 2018-01-18 15:12:25 +02:00
Ivan Kravets
0b5769dc57 Merge branch 'release/v3.5.1' 2018-01-18 15:12:24 +02:00
Ivan Kravets
9b9b05439b Bump version to 3.5.1 (issue #1273 issue #1280 issue #1286 issue #1247 issue #1284 issue #1299 issue #1290) 2018-01-18 15:11:38 +02:00
Ivan Kravets
93d4e68378 Bump docs to 3.5.1 2018-01-18 15:04:15 +02:00
Ivan Kravets
2c79de971e Show full library version in "Library Dependency Graph" including VCS information // Issue #1274 2018-01-18 14:49:01 +02:00
Ivan Kravets
bc18941eb0 Fix project generator for Qt Creator IDE // Resolve #1299 Resolve #1290 2018-01-18 01:30:39 +02:00
Ivan Kravets
23ecce297a Update docs for custom slash size for ESP8266 2018-01-17 13:18:14 +02:00
Ivan Kravets
cc646b19bf Extend example with a custom program name using extra scripting 2018-01-17 01:00:09 +02:00
Ivan Kravets
4b08dbd602 Bump version to 3.5.1a7 2018-01-16 13:40:59 +02:00
Ivan Kravets
d822334fdd Drop "python-dateutil" dependency, implement light-weight "parse_date" 2018-01-16 00:57:06 +02:00
Ivan Kravets
3289b36450 Refactore code without "arrow" dependency (resolve issue with "ImportError: No module named backports.functools_lru_cache") 2018-01-16 00:06:24 +02:00
Ivan Kravets
affd53eb27 Use "python_requires" for setuptools and depend on Python 2.7+ <3 2018-01-15 23:02:40 +02:00
Ivan Kravets
06a6822173 Minor fix to history 2018-01-13 19:45:54 +02:00
Ivan Kravets
6380d6c3ea Bump version to 3.5.1a6 2018-01-13 19:44:55 +02:00
Ivan Kravets
24f314d73d Improve a work in off-line mode 2018-01-13 19:44:05 +02:00
Ivan Kravets
6cddaf9eb7 Ignore VSCode launch.json for VCS 2018-01-13 19:01:27 +02:00
Ivan Kravets
ec419f3d0e Refactor CMD:LIB tests 2018-01-13 17:02:08 +02:00
Ivan Kravets
a6c84da83a Check cached API result before Internet 2018-01-13 01:21:53 +02:00
Ivan Kravets
7cad113f0a Cleanup tests 2018-01-13 01:19:41 +02:00
Ivan Kravets
712155243c Add "lib" and ".piolibdeps" to CLion project index 2018-01-12 14:20:53 +02:00
Ivan Kravets
2091a33fb9 Show full version of the current interpreter 2018-01-12 02:23:55 +02:00
Ivan Kravets
1d5245edbd Add "lib_ldf_mode = chain+" for example with C/C++ Preprocessor conditional syntax 2018-01-11 14:14:35 +02:00
Ivan Kravets
cfb22f2a36 Add FAQ:Package Manager for PackageInstallError 2018-01-11 02:10:51 +02:00
Ivan Kravets
16eb41b84e Document "[Error 5] Access is denied" for Package Manager 2018-01-11 02:02:59 +02:00
Ivan Kravets
ae38d17b7f Ignore packages with TMP_FOLDER_PREFIX 2018-01-10 15:23:56 +02:00
Ivan Kravets
7bbb850c2f Bump version to 3.5.1a5 2018-01-10 03:33:51 +02:00
Ivan Kravets
fda439841e Restore PY2/3 ConfigParser 2018-01-10 03:07:17 +02:00
Ivan Kravets
c558584640 Fix importing of ConfigParser 2018-01-10 02:58:50 +02:00
Ivan Kravets
cfb04b31a4 Bump version to 3.5.1a4 2018-01-10 02:12:26 +02:00
Ivan Kravets
1090c414f5 Update PIO Core+ and PIO Home // Resolve #1247 Resolve #1280 Resolve #1284 Resolve #1286 2018-01-10 02:06:05 +02:00
Ivan Kravets
5b64bf1f7c Set default build environment for each example 2018-01-09 22:26:33 +02:00
Ivan Kravets
61eb989edd Fix project generator for CLion // Issue #1287 2018-01-09 22:15:03 +02:00
Dmitry Bolotin
23ae8e0d3e Additional fix to 7354515 (#1287)
* Additional fix to 7354515

* Update CMakeListsPrivate.txt.tpl

Also perform `replace('"', '\\"')`
2018-01-09 22:07:57 +02:00
Ivan Kravets
e4f8a1877c Fix library updates when a version is declared in VCS format (not SemVer) 2018-01-09 21:56:21 +02:00
Ivan Kravets
61872dd734 Improve support of PIO Unified Debugger for Eclipse Oxygen 2018-01-06 01:04:43 +02:00
Ivan Kravets
16b307d1b3 Sync docs 2018-01-05 19:08:16 +02:00
Ivan Kravets
a4770a27f4 Bump version to 3.5.1a3 2018-01-05 00:18:08 +02:00
Ivan Kravets
ba858989f2 Fix PIO Unified Debugger for mbed framework 2018-01-05 00:17:45 +02:00
Ivan Kravets
93c055a2ec Bump version to 3.5.1a2 2018-01-04 17:14:04 +02:00
Ivan Kravets
2b3bc05f2b Option which allows to specify custom test_speed // Resolve #1273 2018-01-04 16:14:56 +02:00
Ivan Kravets
5260217537 Sync docs with new boards 2018-01-03 19:46:44 +02:00
Ivan Kravets
62235ef32d Sync examples 2018-01-03 18:59:41 +02:00
Ivan Kravets
ec40dcada7 Custom firmware/program name in build directory 2018-01-03 18:35:25 +02:00
Ivan Kravets
5e666492c3 Rename envs_dir option to build_dir in platformio.ini 2018-01-03 15:47:02 +02:00
Ivan Kravets
82246a837e Change wording 2017-12-31 00:07:12 +02:00
Ivan Kravets
2758e99295 Bump version to 3.5.1a1 2017-12-29 20:51:20 +02:00
Ivan Kravets
7354515845 Fix project generator for CLion IDE 2017-12-29 20:50:17 +02:00
Ivan Kravets
d58c392930 Typo fix in docs 2017-12-28 20:38:08 +02:00
Ivan Kravets
86cb2efd64 Sync docs 2017-12-28 20:36:57 +02:00
Ivan Kravets
b307855207 Fix typo in docs 2017-12-28 20:35:24 +02:00
Ivan Kravets
3ad4ff02e8 Typo fix 2017-12-28 18:57:17 +02:00
Ivan Kravets
4ef3818482 Merge branch 'release/v3.5.0' 2017-12-28 17:26:12 +02:00
Ivan Kravets
0082dc43a3 Merge branch 'release/v3.5.0' into develop 2017-12-28 17:26:12 +02:00
Ivan Kravets
755ade05c6 Bump version to 3.5.0 (issue #1260, issue #781, issue #778, issue #463, issue #1236, issue #1235, issue #953, issue #1118, issue #1107, issue #1196, issue #1179, issue #1161, issue #1126, issue #104, issue #1033, issue #1034, issue #1175, issue #1173, issue #1155, issue #1188, issue #1111, issue #1153, issue #1150, issue #1145, issue #1139, issue #1137, issue #1170, issue #1157, issue #1102, issue #1105, issue #1140, issue #1154, issue #1066, issue #1038, issue #1054, issue #1055, issue #1061, issue #1017) 2017-12-28 17:25:49 +02:00
Ivan Kravets
12e4318de7 Don't follow redirects when checking internet connection 2017-12-28 17:15:34 +02:00
Ivan Kravets
34e9063ddd Use "paged" links for docs 2017-12-28 16:58:15 +02:00
Ivan Kravets
2315b08909 PIO Home docs 2017-12-28 16:51:18 +02:00
Ivan Kravets
9c9a40a531 Add GitHub to PING_INTERNET_IPS list 2017-12-28 15:01:18 +02:00
Ivan Kravets
ac4b485521 Fix issue with non-ascii path when printing LDF Tree in verbose mode 2017-12-28 14:27:08 +02:00
Ivan Kravets
f13bf35dbd Bump version to 3.5.0rc17 2017-12-28 01:11:54 +02:00
Ivan Kravets
012cb85e31 Allow libraries with the same folder name 2017-12-28 00:19:17 +02:00
Ivan Kravets
62ee8066c2 Handle incompatibility between PIO Core and PIO Core+ 2017-12-27 22:05:56 +02:00
Ivan Kravets
fc064aaf05 Support the latest arrow package 2017-12-27 21:38:03 +02:00
Ivan Kravets
0516cd74e1 Check system compatibility for package 2017-12-27 21:36:45 +02:00
Ivan Kravets
5b7a0e6997 Bump version to 3.5.0rc16 2017-12-27 19:57:57 +02:00
Ivan Kravets
ad08ed8d12 Improve support for partial package versions 2017-12-27 19:37:26 +02:00
Ivan Kravets
55d4fc23d0 Use "path" instead of "device" for logical devices 2017-12-27 16:02:36 +02:00
Ivan Kravets
e29ecb47a5 Skip mDSN services with wrong encoding 2017-12-23 22:59:49 +02:00
Ivan Kravets
c96c1f2b2f Bump version to 3.5.0rc15 2017-12-23 21:05:05 +02:00
Ivan Kravets
fab4f00ad4 Reformat exceptions 2017-12-23 19:48:16 +02:00
Ivan Kravets
adaa3757ac Switch to newly created "contrib-pysite" 2017-12-23 13:06:38 +02:00
Ivan Kravets
2eb7d0e8be temporary switch to old "pysite-pioplus" 2017-12-19 17:59:49 +02:00
Ivan Kravets
d16d715898 Bump version to 3.5.0rc14 2017-12-19 17:22:16 +02:00
Ivan Kravets
1171cb204c Fix broken syntax 2017-12-19 16:50:09 +02:00
Ivan Kravets
d70a90f1d5 Explain that no need to use sudo pio ... 2017-12-19 15:49:44 +02:00
Ivan Kravets
06574e3066 Do not update automatically Core packages while upgrading PIO Core 2017-12-19 15:38:32 +02:00
Ivan Kravets
39dfbbdd87 Don't create "packages" directory when there are no packages isntalled 2017-12-19 15:24:23 +02:00
Ivan Kravets
7b8c68c934 Show error information when permissions are broken to PIO home dir 2017-12-19 15:05:41 +02:00
Ivan Kravets
6d81c230a5 Bump version to 3.5.0rc13 2017-12-19 14:48:07 +02:00
Ivan Kravets
a6c1869eb2 Depend on "zeroconf" from "contrib-pysite" 2017-12-19 14:47:31 +02:00
Ivan Kravets
0c3f2b54ed Bump version to 3.5.0rc12 2017-12-19 12:42:18 +02:00
Ivan Kravets
c6abdf8206 Check zeroconf installation before adding to setuptools 2017-12-19 12:41:56 +02:00
Ivan Kravets
9f2875fcd7 Update changelog with missed records 2017-12-19 01:55:51 +02:00
Ivan Kravets
78b296f2ec Update changelog 2017-12-19 01:49:25 +02:00
Ivan Kravets
903ad6c6f8 Bump version to 3.5.0rc11 2017-12-19 01:42:10 +02:00
Ivan Kravets
9441f776cc Handle missed dependency and provide a help how to find it using PlatformIO Library Registry // Resolve #781 2017-12-19 01:41:18 +02:00
Ivan Kravets
5dd97a35cc Reinstall/redownload package with a new `-f, --force` option // Resolve #778 2017-12-19 00:51:35 +02:00
Ivan Kravets
31814b5122 Extend "pio device list" command with new options to list logical devices and multicast DNS services // Resolve #463 2017-12-18 21:31:49 +02:00
Ivan Kravets
724135f40e Docs: Simplify solution for "PackageManager is unable to install tool" 2017-12-17 01:58:43 +02:00
Ivan Kravets
cbb7db552a Add contents for "FAQ: Install PIO Core Shell Commands" 2017-12-17 01:23:40 +02:00
Ivan Kravets
cdf4639c97 Remove duplicate package versions from result 2017-12-16 20:50:25 +02:00
Ivan Kravets
170917a927 Sync supported boards and frameworks 2017-12-16 19:19:08 +02:00
Ivan Kravets
efceb5db72 Explain that we need Internet connection to install all dependencies 2017-12-16 17:40:56 +02:00
Ivan Kravets
cee2da7448 Bump version to 3.5.0rc10 2017-12-16 16:16:07 +02:00
Ivan Kravets
3d8183a2e1 LDF: handle "include" folder per project; fix issue with header files // Resolve #1235 2017-12-16 15:38:13 +02:00
Ivan Kravets
25341d1ec7 Bump version to 3.5.0rc9 2017-12-16 01:07:18 +02:00
Ivan Kravets
05081561c3 Minor fixes 2017-12-16 01:07:03 +02:00
Ivan Kravets
abbba7fe2e Don't use PIOBUILDFILES for LDF 2017-12-15 23:51:13 +02:00
Ivan Kravets
269935726d Check all URL parsed args before installing a package 2017-12-15 23:36:23 +02:00
Ivan Kravets
56aeff87dd Typo fix 2017-12-15 22:31:35 +02:00
Ivan Kravets
42fb589369 Refactor PyLint "inconsistent-return-statements" 2017-12-15 22:16:37 +02:00
Ivan Kravets
bff590e207 Search for libraries used in test // Resolve #953 2017-12-15 21:48:20 +02:00
Ivan Kravets
0933e46a58 Update history 2017-12-15 14:09:07 +02:00
Ivan Kravets
1a7429a1ef Fix "get-platformio.py" script which hangs on Windows 10 // Resolve #1118 2017-12-15 13:47:44 +02:00
Ivan Kravets
fd0b45afdb Use short version of a link for IOError exception 2017-12-15 02:42:38 +02:00
Ivan Kravets
3d67535a9e Bump version to 3.5.0rc8 2017-12-15 02:12:04 +02:00
Ivan Kravets
0eb67a7b61 Handle unknown platform when uninstall/update 2017-12-15 02:01:03 +02:00
Ivan Kravets
75774ad9fa Compress exception report 2017-12-15 01:39:10 +02:00
Ivan Kravets
7b6ecf4e45 Fix broken authentication via PIO Home // Resolve #1229 Resolve #1230 Resolve #1231 2017-12-15 00:22:40 +02:00
Ivan Kravets
ca8bc3819f Add "include" folder for project’s header files // Resolve issue #1107 2017-12-14 22:02:41 +02:00
Ivan Kravets
0bd103a46d YAPF 2017-12-14 22:01:59 +02:00
Ivan Kravets
736c6a9a1e Sort all package versions using SemVer rules 2017-12-14 21:20:08 +02:00
Ivan Kravets
ef00ecd7f1 Test IPs which used for testing internet connection 2017-12-14 20:18:19 +02:00
Ivan Kravets
70b63d8618 Bump version to 3.5.0rc7 2017-12-14 20:05:50 +02:00
Ivan Kravets
a632583f89 Catch IOError for VSCode Terminal 2017-12-14 20:05:06 +02:00
Ivan Kravets
15bb626e78 Docs: explain about VSCode known issue: "PackageManager is unable to install tool" 2017-12-14 18:26:45 +02:00
Ivan Kravets
bc0d1f06e0 Ensure that PIO Home works without Internet connection // Resolve #1179 2017-12-14 16:52:44 +02:00
Ivan Kravets
bd611bbee8 Allow to change default projects location // Resolve #1161 2017-12-14 16:52:13 +02:00
Ivan Kravets
2522d19453 Fix issue when API cache is turned off 2017-12-14 14:55:04 +02:00
Ivan Kravets
5c4b5c2270 Don't export PIO Core Python's PATH 2017-12-13 22:15:37 +02:00
Ivan Kravets
2d0ac1a9c2 Export PYTHONPATH to PIO Core+ 2017-12-13 20:05:39 +02:00
Ivan Kravets
0f37e15b6c Improve off-line mode // Resolve #1126 2017-12-13 18:14:01 +02:00
Ivan Kravets
3d0f0659ae Rename --develop to --dev option for upgrade command 2017-12-13 13:42:16 +02:00
Ivan Kravets
02a263fdce Bump version to 3.5.0rc6 2017-12-13 01:32:19 +02:00
Ivan Kravets
f7815d6c9b Check PIO Core updates after reset of time counter // Issue #1126 2017-12-13 01:31:41 +02:00
Ivan Kravets
786dd8fe18 Implement "--develop" option for "upgrade" command // Resolve #104 2017-12-13 01:23:18 +02:00
Ivan Kravets
f9b9ed317d Export built-in GCC macros for IDEs 2017-12-13 00:59:51 +02:00
Ivan Kravets
0394e43ba4 Remove caching from TravisCI template 2017-12-12 21:35:48 +02:00
Ivan Kravets
3b1fa572fa Handle unicode errors 2017-12-04 16:18:45 +02:00
Ivan Kravets
ea99701172 Bump version to 3.5.0rc5 2017-12-03 02:29:14 +02:00
Ivan Kravets
e329688954 Update PIO Home to 0.4.0 // Resolve #1034 2017-12-03 02:25:49 +02:00
Ivan Kravets
18b10a7fbf Raise exception when try to load non-PIO project 2017-12-03 02:15:49 +02:00
Ivan Kravets
05069f7ac6 Bump version to 3.5.0rc4 2017-12-01 20:53:39 +02:00
Ivan Kravets
1b1453808f Merge branch 'feature/travis-ci' into develop 2017-11-30 14:06:05 +02:00
Ivan Kravets
d0e32ebcb5 CI OSX: Don't upgrade system Python packages 2017-11-30 02:05:14 +02:00
Ivan Kravets
ad48b85a44 Fix sudo command for OSX CI 2017-11-30 00:18:11 +02:00
Ivan Kravets
75160bb231 Better handling of errors from VCS GIT 2017-11-29 22:46:57 +02:00
Ivan Kravets
4b1716e42b CI: Install PIP for macOS build 2017-11-29 22:27:03 +02:00
Ivan Kravets
10d21595c6 Fix issue when board is not specified and "idedata" target is called 2017-11-29 22:22:31 +02:00
Ivan Kravets
f922fac9d9 Handle espressif as espressif8266 dev/platform for LDF 2017-11-29 18:30:00 +02:00
Ivan Kravets
5846566bbb Bump version to 3.5.0rc3 2017-11-29 16:24:47 +02:00
Ivan Kravets
8f97181ea7 Add "__GNUC__" macro by default for VSCode
https://github.com/platformio/platformio-vscode-ide/issues/54
2017-11-29 16:07:11 +02:00
Ivan Kravets
3c6bd9824e Handle old "espressif" platform name for LDF 2017-11-29 15:32:38 +02:00
Ivan Kravets
1b0776167c Bump version to 3.5.0rc2 2017-11-27 21:05:40 +02:00
Ivan Kravets
f5f3cd85d8 Add support for Git scp-like syntax 2017-11-27 21:04:51 +02:00
Ivan Kravets
79b7974f35 Strip SHA1 sum because @bintray returns wrong value 2017-11-27 14:05:04 +02:00
Ivan Kravets
32c92eec95 Add link to LDF docs 2017-11-27 01:32:36 +02:00
Ivan Kravets
7ec90ac23b Bump version to 3.5.0rc1 2017-11-27 00:20:31 +02:00
Ivan Kravets
bab8ad088e Parse library source file in pair with a header when they have the same name // Resolve #1175 2017-11-27 00:01:24 +02:00
Ivan Kravets
46acad952e Parse source files by header name in default LDF mode // Issue #1175 2017-11-26 20:17:38 +02:00
Ivan Kravets
200cbae177 Experimental support for parsing source file in pair with a header when they have the same name // Issue #1175 2017-11-26 18:51:08 +02:00
Ivan Kravets
d8ee64a545 Fix tests 2017-11-26 01:02:21 +02:00
Ivan Kravets
7b324ebc3c Bump version to 3.5.0b6 2017-11-25 23:55:13 +02:00
Ivan Kravets
02d9272d2a Depend on Arrow 0.10.0 (issue with "backports.functools-lru-cache" for PIO Core+) 2017-11-25 23:54:50 +02:00
Ivan Kravets
9fc5aecb64 Add option to configure library Compatible Mode using library.json 2017-11-25 21:51:16 +02:00
Ivan Kravets
5ca472050c Typo fix 2017-11-25 20:16:37 +02:00
Ivan Kravets
dcab855d2c Fix PyLint 2017-11-25 19:59:03 +02:00
Ivan Kravets
0c9c6d1092 Remove debug code 2017-11-25 19:25:07 +02:00
Ivan Kravets
301b8dc649 Bump version to 3.5.0b5 2017-11-25 19:22:47 +02:00
Ivan Kravets
547e983a86 Improved handling of library dependencies defined as VCS or SemVer in platformio.ini // Resolve #1155 2017-11-25 19:22:00 +02:00
Ivan Kravets
9b514ba194 Remove temporary hook for Arrow deps 2017-11-25 19:06:38 +02:00
Ivan Kravets
37a2ccedbd Temporary fix for Arrow with a missing deps to backports.functools-lru-cache 2017-11-25 15:11:06 +02:00
Ivan Kravets
a983f60fa0 Bump version to 3.5.0b4 2017-11-25 01:12:49 +02:00
Ivan Kravets
fc96806e68 Update docs for ESP32 with custom options 2017-11-25 01:02:27 +02:00
Ivan Kravets
53b37216cc Improve support for VCS packages 2017-11-25 00:31:16 +02:00
Ivan Kravets
d07833e010 Include TizenRT to docs 2017-11-24 20:04:18 +02:00
Ivan Kravets
5b5387d97b Sync docs with the latest added hardware/software 2017-11-24 15:36:37 +02:00
Ivan Kravets
1c20efe9d1 Improve support for dependency with scp-like syntax 2017-11-22 21:38:14 +02:00
Ivan Kravets
8b4104bf5b YAPF 2017-11-22 21:09:16 +02:00
Ivan Kravets
448e0f27b6 Merge branch 'feature/debug-blackmagic' into develop 2017-11-08 11:34:22 +02:00
Ivan Kravets
02db510048 Check serial device description when looking for GDB port 2017-11-08 11:22:44 +02:00
Ivan Kravets
ce9c563c9f Bump version to 3.5.0b3 2017-11-08 00:39:25 +02:00
Ivan Kravets
4c170b7934 Ensure real dev/platform name before build process // Resolve #1170 2017-11-08 00:38:19 +02:00
Ivan Kravets
d1a2dba68c Integration with Jenkins CI 2017-11-07 23:47:23 +02:00
Ivan Kravets
5d2867d8a9 Automatically detect BlackMagic probe GDB port 2017-11-07 00:10:48 +02:00
Ivan Kravets
4504a65b92 Add Black Magic Probe rules 2017-11-04 00:38:49 +02:00
Ivan Kravets
25f52917ef Override VSCode IntelliSense mode with clang-x64 2017-11-03 23:38:09 +02:00
Ivan Kravets
75770bcedf Bump version to 3.5.0b2 2017-11-03 23:11:44 +02:00
Ivan Kravets
1c9fe4561a Terminate PIO Home servers when upgrade PIO Core // Issue #1132 2017-11-03 23:10:39 +02:00
Ivan Kravets
909b773f6d Bump version to 3.5.0b1 2017-11-03 00:51:28 +02:00
Ivan Kravets
0343dc0785 Drop flake8 2017-11-03 00:47:00 +02:00
Ivan Kravets
b670ab4888 Initial support for non-ascii locales 2017-11-02 23:14:32 +02:00
Ivan Kravets
f85202d64c Bump version to 3.5.0a17 2017-11-01 14:14:03 +02:00
Ivan Kravets
e5e5ebb7db YAPF formatter 2017-11-01 14:10:32 +02:00
Ivan Kravets
86de58b9e1 Fix missing toolchain include paths for project generator // Resolve #1154 2017-11-01 14:09:06 +02:00
Ivan Kravets
675cd456b6 New development platform - Samsung ARTIK 2017-09-27 19:28:53 +03:00
Ivan Kravets
9fe581e425 Update release notes 2017-09-27 19:03:04 +03:00
Ivan Kravets
a0626ac958 Hint user to delete file manually when exception is raised 2017-09-24 01:28:41 +03:00
Ivan Kravets
1fab2a5bec Bump version to 3.5.0a16 2017-09-24 00:33:35 +03:00
Ivan Kravets
d9ae367281 Improve archive unpacker 2017-09-24 00:33:12 +03:00
Ivan Kravets
837b040761 Bump version to 3.5.0a15 2017-09-22 01:22:41 +03:00
Ivan Kravets
71afea8d80 Expand user folder for lib_extra_dirs 2017-09-22 01:22:21 +03:00
Ivan Kravets
7c9989d999 Fix tests for "platform" command 2017-09-21 23:57:55 +03:00
Ivan Kravets
2e2b1fda9c Bump version to 3.5.0a14 2017-09-21 21:58:37 +03:00
Ivan Kravets
25da978fee Add support for "author" field in library.json manifest // Resolve #1055 2017-09-21 15:07:38 +03:00
Ivan Kravets
c677f24d8e Sync docs 2017-09-20 18:49:19 +03:00
Ivan Kravets
77fe1e8184 Use -ggdb3 instead of -ggdb by default 2017-09-18 14:06:16 +03:00
Ivan Kravets
377008ee08 New Microchip PIC32 boards 2017-09-17 02:21:59 +03:00
Ivan Kravets
22fb89e56a Fix tests 2017-09-17 02:18:35 +03:00
Ivan Kravets
68c56e042c Bump version to 3.5.0a13 2017-09-17 01:33:29 +03:00
Ivan Kravets
16c242e7fa Better parsing of F_CPU 2017-09-17 01:33:04 +03:00
Ivan Kravets
c9e1ae2548 Bump version to 3.5.0a12 2017-09-16 16:36:09 +03:00
Ivan Kravets
fc7f1c0728 Fix platforms, packages, and libraries updating behind proxy // Resolve #1061 2017-09-16 16:35:35 +03:00
Ivan Kravets
aa1c7609d2 Bump version to 3.5.0a11 2017-09-16 01:00:29 +03:00
Ivan Kravets
998f4ed6e6 Use VCS directly with "platform" option in configuration file 2017-09-16 00:57:36 +03:00
Ivan Kravets
33242a02ce Bump version to 3.5.0a10 2017-09-13 17:39:41 +03:00
Ivan Kravets
7963ce2cdd Do not warn about "custom_" options in configuration file 2017-09-13 17:38:42 +03:00
Ivan Kravets
b4159f9144 Docs: Update instruction how to install Espressif staging version 2017-09-09 23:03:15 +03:00
Ivan Kravets
674aa5c4d8 Decrease API cache timeouts 2017-09-09 20:57:25 +03:00
Ivan Kravets
e176e9922a Sync docs 2017-09-07 20:30:48 +03:00
Ivan Kravets
fd98aa0ff8 Fix PyLint warning 2017-09-06 20:57:56 +03:00
Ivan Kravets
f24e97e933 Skip missing package when checking for updates 2017-09-06 14:37:04 +03:00
Ivan Kravets
a934efa90a Sync docs 2017-09-06 02:04:06 +03:00
Ivan Kravets
a0cae2b1a6 Update docs for PIO IDE for Atom 2017-09-05 19:40:11 +03:00
Ivan Kravets
274c1a40a5 Bump version to 3.5.0a9 2017-09-05 14:42:56 +03:00
Ivan Kravets
059a408e95 Merge branch 'feature/prepend-python-pioplus' into develop 2017-09-05 14:42:02 +03:00
Ivan Kravets
f4c6919800 Don't verify SSL certificates for Python < 2.7.9 2017-09-05 14:23:49 +03:00
Ivan Kravets
7301b9e808 Prepend Python's binary folder before calling PIO Core+ 2017-09-05 14:13:00 +03:00
Ivan Kravets
113746dc74 Introduce "get_all_boards" API to PlatformManager 2017-09-03 22:40:00 +03:00
Ivan Kravets
95aaca5e02 Do not skip fixed packages with custom requirements 2017-09-03 20:58:48 +03:00
Ivan Kravets
ed6b196459 Bump version to 3.5.0a8 2017-09-02 18:33:56 +03:00
Ivan Kravets
34ed4678d7 Moved configuration code to a separate function, re-use it for PIO Core+ 2017-09-02 18:02:24 +03:00
Ivan Kravets
a127251107 Catch click's IOError for VSCode Terminal 2017-09-02 17:58:35 +03:00
Ivan Kravets
b55b80ecc8 Better catching of IOError for VSCode/Colorama 2017-09-02 16:23:24 +03:00
Ivan Kravets
68c75735f4 Bump version to 3.5.0a7 2017-09-02 15:39:53 +03:00
Ivan Kravets
9b66abf5ef Fix issue with "IOError" in VSCode when processing a project 2017-09-02 15:39:32 +03:00
Ivan Kravets
ccd650dda0 Fix invalid params order when installing PIO Core without PIP Cache 2017-09-02 14:43:08 +03:00
Ivan Kravets
3afac476e5 Docs: Remove Crisp chat 2017-09-01 20:27:24 +03:00
Ivan Kravets
8f7483cddf Update VSCode docs 2017-09-01 14:31:11 +03:00
Ivan Kravets
3b5c73b1a3 Bump version to 3.5.0a6 2017-09-01 00:39:17 +03:00
Ivan Kravets
04ec65df3e Minor fixes 2017-08-31 23:12:02 +03:00
Ivan Kravets
49244072c4 Improve fetching of logical disks 2017-08-31 20:56:25 +03:00
Ivan Kravets
3fe9ea1b01 Bump version to 3.5.0a5 2017-08-31 18:35:15 +03:00
Ivan Kravets
a55ccb2b28 Docs: Add CI for GitLab 2017-08-31 18:33:17 +03:00
Ivan Kravets
01a6ae656f Depend on new PIO Home 0.2.0 2017-08-31 18:32:52 +03:00
Ivan Kravets
2b7b852a68 Update VSCode docs 2017-08-29 14:16:30 +03:00
Ivan Kravets
b12c4d171e Sync docs 2017-08-26 16:51:27 +03:00
Ivan Kravets
3ce7104542 Fix broken links 2017-08-23 21:46:31 +03:00
Ivan Kravets
297c173418 Docs: Fix invalid hotkey for VSCode Tasks 2017-08-23 17:05:11 +03:00
Ivan Kravets
22733ea110 Docs: Minor fix 2017-08-22 19:52:12 +03:00
Ivan Kravets
845991f1d3 J-Link as debugger and uploader 2017-08-18 22:41:11 +03:00
Ivan Kravets
e6faed5dd9 Update history 2017-08-18 01:26:31 +03:00
Ivan Kravets
44909f9ce8 Switch to "develop" version of PIO Core Installer while it isn't merged to "master" // Resolve #1017 2017-08-18 01:23:15 +03:00
Ivan Kravets
4ff1d640b3 Minor fixes 2017-08-17 23:55:42 +03:00
Ivan Kravets
743de42484 Add "test_ignore" to known options list 2017-08-17 17:18:23 +03:00
Ivan Kravets
04c381d440 Sync docs and examples 2017-08-17 15:33:24 +03:00
Ivan Kravets
bda4b5d264 Docs: Create Advanced Scripting section for platformio.ini 2017-08-16 15:33:36 +03:00
Ivan Kravets
3f13821c43 Update history 2017-08-16 15:12:45 +03:00
Ivan Kravets
e60e076d16 Better explanation about lib_extra_dirs 2017-08-16 15:10:56 +03:00
Ivan Kravets
541993c06b Implement throttle for API calls 2017-08-15 22:57:20 +03:00
Ivan Kravets
3d5114655f Docs: Embedded Testing with PlatformIO - Part 2 2017-08-15 19:33:35 +03:00
Ivan Kravets
3229933ed0 Minor improvements 2017-08-14 23:58:12 +03:00
Ivan Kravets
d7d66fd4a6 Improve fetching logical disks 2017-08-14 15:27:12 +03:00
Ivan Kravets
4a7cd5be6a Update docs for VSCode 2017-08-13 00:08:49 +03:00
Ivan Kravets
fd56e5cec9 Docs: New boards, typo fixes 2017-08-12 19:16:36 +03:00
Ivan Kravets
2cb7fcca9a Bump version to 3.5.0a4 2017-08-10 16:04:51 +03:00
Ivan Kravets
9b2e7bf927 Fix broken installer script 2017-08-09 23:43:31 +03:00
Ivan Kravets
d913fb5600 Call pip as module 2017-08-09 23:02:33 +03:00
Ivan Kravets
6bf42f90ed Docs: Short titles in menu 2017-08-09 17:59:28 +03:00
Ivan Kravets
51ff2b65f4 Bump version to 3.5.0a3 2017-08-08 14:44:25 +03:00
Ivan Kravets
c05e1f7c9b Ignore missed packages in new development platform 2017-08-07 19:33:13 +03:00
Ivan Kravets
4700419590 Bump version to 3.5.0a2 2017-08-07 17:38:21 +03:00
Ivan Kravets
5f320cc5c8 Introduce PIO Home 2017-08-07 17:38:05 +03:00
Ivan Kravets
351aaa3974 Sync submodules 2017-08-05 19:19:43 +03:00
Ivan Kravets
327d42d02d Sync docs 2017-08-03 16:56:25 +03:00
Ivan Kravets
bbcc79208c Bump version to 3.5.0a1 2017-08-02 22:17:21 +03:00
Ivan Kravets
578dfa40aa Ignore only C/C++ properties for VSCode extension 2017-08-02 22:16:41 +03:00
Ivan Kravets
a43c6c6b9e Merge branch 'release/v3.4.1' into develop 2017-08-02 16:51:46 +03:00
Ivan Kravets
5f99dd620d Merge branch 'release/v3.4.1' 2017-08-02 16:51:45 +03:00
Ivan Kravets
e959710d6d Version bump to 3.4.1 (issues #891, #982, #993, #1000, #1001, #1003 ) 2017-08-02 16:51:19 +03:00
Ivan Kravets
f0f1d0a61a Bump version to 3.4.1rc1 2017-08-02 01:08:07 +03:00
Ivan Kravets
7f63928d21 New lib_archive option to control library archiving and linking behaviour // Resolve #993 2017-08-02 01:06:06 +03:00
Ivan Kravets
b929e452b0 Add "inc" folder automatically to CPPPATH when "src" is available (works for project and library) // Resolve #1003 2017-08-01 14:45:42 +03:00
Ivan Kravets
b4f927a84d Sync docs: add new boards 2017-08-01 01:45:48 +03:00
Ivan Kravets
fe4a72edd0 Bump version to 3.4.1b1 2017-08-01 00:35:16 +03:00
Ivan Kravets
5f4a10086f Merge branch 'feature/samba-due-issue' into develop 2017-08-01 00:34:01 +03:00
Ivan Kravets
d5baa153a5 Fix an issue when can not upload firmware to SAM-BA based board (Due) 2017-08-01 00:33:51 +03:00
Ivan Kravets
3f96530c32 Sync docs: Add example how to build a custom HEX from ELF 2017-08-01 00:21:57 +03:00
Ivan Kravets
861659e890 Wait for 400ms after touching serial port (fix SAM-BA issue) 2017-08-01 00:12:05 +03:00
Ivan Kravets
cd5b88dd1f Automatically update PIO Core packages when it is possible 2017-07-31 19:38:42 +03:00
Ivan Kravets
06b49ec3ec Some improvements 2017-07-31 19:05:03 +03:00
Ivan Kravets
4944731dc6 Sync docs: Split build flags into multiple lines 2017-07-31 18:25:57 +03:00
Ivan Kravets
5d31d6825b Export board's connectivity 2017-07-28 00:56:02 +03:00
Ivan Kravets
0099b037f3 Refactor docs for Unit Testing 2017-07-27 19:07:46 +03:00
Ivan Kravets
9994ed8b5e Check context arguments before comparison // Resolve #1000 2017-07-27 15:50:54 +03:00
Ivan Kravets
954357bdd2 Update links to ESP8266 docs 2017-07-25 20:00:27 +03:00
Ivan Kravets
c7f5629f82 Fix links in docs 2017-07-25 19:19:52 +03:00
Ivan Kravets
dfe769c92e Add support for Controllino PLC 2017-07-25 13:22:55 +03:00
Ivan Kravets
53017b24d1 VSCode configuration 2017-07-24 17:37:16 +03:00
Ivan Kravets
f13537cabb YAPF 2017-07-24 17:35:41 +03:00
Ivan Kravets
16ea8f29a1 Update docs with new boards 2017-07-21 22:07:11 +03:00
Ivan Kravets
e708b74507 Document Task Runner for VSCode 2017-07-20 13:36:13 +03:00
Ivan Kravets
f61c7f6030 Sync examples 2017-07-19 13:53:58 +03:00
Ivan Kravets
1260859c42 Sync examples 2017-07-18 23:15:09 +03:00
Ivan Kravets
ec9324d77f Sync examples with mbed 5.5 2017-07-18 22:47:39 +03:00
Ivan Kravets
d66b1780ce Bump version to 3.4.1a6 2017-07-17 13:13:42 +03:00
Ivan Kravets
35cab82605 Remove static tasks for VSCode 2017-07-16 21:28:54 +03:00
Ivan Kravets
12222c0f42 Improve docs for advanced scripting 2017-07-14 23:56:45 +03:00
Ivan Kravets
12ec11c7e2 Sync docs 2017-07-14 14:22:38 +03:00
Ivan Kravets
c926ca389c Sync examples 2017-07-14 14:05:38 +03:00
Ivan Kravets
e01c0a1eff Sync docs 2017-07-14 02:10:12 +03:00
Ivan Kravets
8008f87ffa Manage project libraries with "--storage-dir" option 2017-07-13 00:51:04 +03:00
Ivan Kravets
91d3a8ffad Improve docs for PIO Debugger 2017-07-10 01:28:19 +03:00
Ivan Kravets
309d3a45d6 New "forceUploadAndMonitor" option for PlatformIO IDE for VSCode 2017-07-05 21:22:33 +03:00
Ivan Kravets
ebe0d41b77 Bump version to 3.4.1a5 2017-07-05 20:38:55 +03:00
Ivan Kravets
6403cf0c8b New task "PlatformIO: Monitor" for VSCode 2017-07-05 20:38:28 +03:00
Ivan Kravets
7964aed453 New boards by RushUp 2017-07-04 19:30:39 +03:00
Ivan Kravets
97866cf44d Correct default values for auto_update_libraries/platforms 2017-07-04 14:24:40 +03:00
Ivan Kravets
4eb92ff2e3 Refactor pioNav for docs 2017-07-04 01:17:56 +03:00
Ivan Kravets
0e8fb1ba83 Bump version to 3.4.1a4 2017-07-03 13:36:51 +03:00
Ivan Kravets
8741f37831 Minor improvements 2017-07-03 13:35:39 +03:00
Ivan Kravets
68ccabda56 Update history 2017-07-01 22:17:37 +03:00
Ivan Kravets
a0cd0bc189 Fix an issue with a custom unit testing transport 2017-07-01 22:00:25 +03:00
Ivan Kravets
aadb186054 Escape spaces in task command for VSCode Task Runner 2017-07-01 21:54:04 +03:00
Ivan Kravets
2c232f2f3f Standalone IDEs Integration 2017-07-01 20:34:34 +03:00
Ivan Kravets
f85c894b52 Move Pricing before Docs 2017-07-01 20:24:03 +03:00
Ivan Kravets
fb432da26b Bump version to 3.4.1a3 2017-07-01 19:24:41 +03:00
Ivan Kravets
e8da7b4673 Depend on PIO Core Plus v0.9.1 2017-07-01 19:24:10 +03:00
Ivan Kravets
53906c49cb Refactor PIO Account docs 2017-07-01 14:16:26 +03:00
Ivan Kravets
b774bd6a55 Improve platformio.ini example 2017-06-30 22:07:04 +03:00
Ivan Kravets
cefc2fa21c Cosmetic improvements 2017-06-30 01:35:54 +03:00
Ivan Kravets
546993b12c Fix PyLint Warning 2017-06-30 01:23:52 +03:00
Ivan Kravets
08ab80187c Mode PIO Core Dev installation on upper level 2017-06-30 00:24:35 +03:00
Ivan Kravets
bf48643865 Bump version to 3.4.1a2 2017-06-30 00:20:27 +03:00
Ivan Kravets
35a91dbd57 Pre/Post extra scripting for advanced control of PIO Build System // Resolve #891 2017-06-30 00:15:49 +03:00
Ivan Kravets
7a56ec614c Added monitor_* options to white-list for Project Configuration File “platformio.ini” // Resolve #982 2017-06-29 21:27:38 +03:00
Ivan Kravets
7d2728845e Use a root of library when filtering source code using library.json and srcFilter field 2017-06-29 21:23:06 +03:00
Ivan Kravets
94a834ecc4 Use a root of library when filtering source code using library.json and srcFilter field 2017-06-29 21:22:44 +03:00
Ivan Kravets
46774466db Fix contact url 2017-06-29 19:32:38 +03:00
Ivan Kravets
671eff5012 Library Manager in PlatformIO IDE for Atom 2017-06-29 01:13:20 +03:00
Ivan Kravets
a3e7535db5 Simplify index page of docs 2017-06-28 19:33:53 +03:00
Ivan Kravets
f7ee7e2e8c Add Changelog for PIO IDE for Atom and VSCode 2017-06-28 18:29:56 +03:00
Ivan Kravets
7a04061d6d Typo fix 2017-06-28 14:05:28 +03:00
Ivan Kravets
7827994791 Do not ask for board ID when initialize project for desktop platform 2017-06-28 01:38:20 +03:00
Ivan Kravets
dae290ad2d Bump version to 3.4.1a1 2017-06-28 01:01:27 +03:00
Ivan Kravets
61fc7d8589 Fix issue when can not load broken PIO Core state 2017-06-28 01:01:03 +03:00
Ivan Kravets
0deb623ad5 Add link to PIO IDE packages 2017-06-27 01:56:03 +03:00
Ivan Kravets
ef8aeeb5f0 Add support for Adafruit Feather M0 Express & Metro M0 Expresss boards 2017-06-27 01:17:34 +03:00
Ivan Kravets
2695c985a4 Remove platforms related history from the Core 2017-06-27 01:03:26 +03:00
Ivan Kravets
fcfdc5c206 Sync docs 2017-06-27 00:05:23 +03:00
Ivan Kravets
78616bf06f Merge branch 'release/v3.4.0' into develop 2017-06-26 19:58:30 +03:00
142 changed files with 12086 additions and 5571 deletions

View File

@@ -1,13 +1,20 @@
build: off
environment:
platform:
- x64
environment:
matrix:
- TOXENV: "py27"
PLATFORMIO_BUILD_CACHE_DIR: C:/Temp/PIO_Build_Cache_P2_{build}
- TOXENV: "py36"
PLATFORMIO_BUILD_CACHE_DIR: C:/Temp/PIO_Build_Cache_P3_{build}
install:
- cmd: git submodule update --init --recursive
- cmd: SET PATH=%PATH%;C:\Python27\Scripts;C:\MinGW\bin
- cmd: pip install tox
- cmd: SET PATH=C:\MinGW\bin;%PATH%
- cmd: pip install --force-reinstall tox
test_script:
- cmd: tox

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
custom: https://platformio.org/donate

View File

@@ -1,22 +1,28 @@
What kind of issue is this?
- [ ] Question. This issue tracker is not the place for questions. If you want to ask how to do
something, or to understand why something isn't working the way you expect it to, use
our Community Forums https://community.platformio.org
- [ ] **Question**.
This issue tracker is not the place for questions. If you want to ask how to do something,
or to understand why something isn't working the way you expect it to,
use [Community Forums](https://community.platformio.org) or [Premium Support](https://platformio.org/support)
- [ ] PlatformIO IDE. All issues related to PlatformIO IDE should be reported to appropriate repository
https://github.com/platformio/platformio-atom-ide/issues
- [ ] **PlatformIO IDE**.
All issues related to PlatformIO IDE should be reported to appropriate repository:
[PlatformIO IDE for Atom](https://github.com/platformio/platformio-atom-ide/issues) or
[PlatformIO IDE for VSCode](https://github.com/platformio/platformio-vscode-ide/issues)
- [ ] Development Platform or Board. All issues related to Development Platforms or Embedded Boards
should be reported to appropriate repository.
See full list with repositories and search for "platform-xxx" repository related to your hardware
https://github.com/platformio?query=platform-
- [ ] **Development Platform or Board**.
All issues (building, uploading, adding new boards, etc.) related to PlatformIO development platforms
should be reported to appropriate repository related to your hardware
https://github.com/topics/platformio-platform
- [ ] Feature Request. Start by telling us what problem youre trying to solve. Often a solution
- [ ] **Feature Request**.
Start by telling us what problem youre trying to solve. Often a solution
already exists! Dont send pull requests to implement new features without first getting our
support. Sometimes we leave features out on purpose to keep the project small.
- [ ] PlatformIO Core. If youve found a bug, please provide an information below.
- [ ] **PlatformIO Core**.
If youve found a bug, please provide an information below.
*You can erase any parts of this template not applicable to your Issue.*

1
.gitignore vendored
View File

@@ -9,3 +9,4 @@ build
coverage.xml
.coverage
htmlcov
.pytest_cache

View File

@@ -1,3 +1,3 @@
[settings]
line_length=79
known_third_party=arrow,bottle,click,lockfile,pytest,requests,SCons,semantic_version,serial
known_third_party=bottle,click,pytest,requests,SCons,semantic_version,serial,twisted,autobahn,jsonrpc,tabulate

View File

@@ -1,23 +1,12 @@
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time. See also the "--disable" option for examples.
#enable=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --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=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating
disable=locally-disabled,missing-docstring,invalid-name,too-few-public-methods,redefined-variable-type,import-error,similarities,unsupported-membership-test,unsubscriptable-object,ungrouped-imports,cyclic-import
disable=
missing-docstring,
ungrouped-imports,
invalid-name,
cyclic-import,
duplicate-code,
superfluous-parens,
too-few-public-methods,
useless-object-inheritance,
useless-import-alias,
fixme

View File

@@ -6,32 +6,29 @@ matrix:
sudo: false
python: 2.7
env: TOX_ENV=docs
- os: linux
sudo: false
python: 2.7
env: TOX_ENV=lint
- os: linux
sudo: required
python: 2.7
env: TOX_ENV=py27
env: TOX_ENV=py27 PLATFORMIO_BUILD_CACHE_DIR=$(mktemp -d)
- os: linux
sudo: required
python: 3.6
env: TOX_ENV=py36 PLATFORMIO_BUILD_CACHE_DIR=$(mktemp -d)
- os: osx
language: generic
env: TOX_ENV=skipexamples
install:
- git submodule update --init --recursive
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo pip install -U tox; else pip install -U tox; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then curl -fsSL https://bootstrap.pypa.io/get-pip.py | sudo python; fi
- pip install -U tox
# ChipKIT issue: install 32-bit support for GCC PIC32
- if [[ "$TOX_ENV" == "py27" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libc6-i386; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libc6-i386; fi
script:
- tox -e $TOX_ENV
after_success:
- if [[ "$TOX_ENV" == "py27" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then tox -e coverage; fi
- if [[ "$TOX_ENV" == "py27" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then bash <(curl -s https://codecov.io/bash); fi
notifications:
email: false

View File

@@ -4,18 +4,18 @@ Contributing
To get started, <a href="https://www.clahub.com/agreements/platformio/platformio-core">sign the Contributor License Agreement</a>.
1. Fork the repository on GitHub.
2. Make a branch off of ``develop``
3. Run ``pip install tox``
4. Go to the root of project where is located ``tox.ini`` and run ``tox -e develop``
2. Clone repository `git clone --recursive https://github.com/YourGithubUsername/platformio-core.git`
3. Run `pip install tox`
4. Go to the root of project where is located `tox.ini` and run `tox -e py27`
5. Activate current development environment:
* Windows: ``.tox\develop\Scripts\activate``
* Bash/ZSH: ``source .tox/develop/bin/activate``
* Fish: ``source .tox/bin/activate.fish``
* Windows: `.tox\py27\Scripts\activate`
* Bash/ZSH: `source .tox/py27/bin/activate`
* Fish: `source .tox/py27/bin/activate.fish`
6. Make changes to code, documentation, etc.
7. Lint source code ``tox -e lint``
8. Run the tests ``tox -e py27``
9. Build documentation ``tox -e docs`` (creates a directory _build under docs where you can find the html)
7. Lint source code `make lint`
8. Run the tests `make test`
9. Build documentation `tox -e docs` (creates a directory _build under docs where you can find the html)
10. Commit changes to your forked repository
11. Submit a Pull Request on GitHub.

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,3 @@
lint:
pylint --rcfile=./.pylintrc ./platformio
@@ -9,7 +8,10 @@ isort:
yapf:
yapf --recursive --in-place platformio/
before-commit: isort yapf lint
test:
py.test --verbose --capture=no --exitfirst -n 3 --dist=loadscope tests --ignore tests/test_examples.py --ignore tests/test_pkgmanifest.py
before-commit: isort yapf lint test
clean-docs:
rm -rf docs/_build
@@ -20,4 +22,12 @@ clean: clean-docs
rm -rf .cache
rm -rf build
rm -rf htmlcov
rm -f .coverage
rm -f .coverage
profile:
# Usage $ > make PIOARGS="boards" profile
python -m cProfile -o .tox/.tmp/cprofile.prof $(shell which platformio) ${PIOARGS}
snakeviz .tox/.tmp/cprofile.prof
publish:
python setup.py sdist upload

View File

@@ -7,118 +7,136 @@ PlatformIO
.. image:: https://ci.appveyor.com/api/projects/status/unnpw0n3c5k14btn/branch/develop?svg=true
:target: https://ci.appveyor.com/project/ivankravets/platformio-core
:alt: AppVeyor.CI Build Status
.. image:: https://requires.io/github/platformio/platformio-core/requirements.svg?branch=develop
:target: https://requires.io/github/platformio/platformio-core/requirements/?branch=develop
:alt: Requirements Status
.. image:: https://img.shields.io/pypi/v/platformio.svg
:target: https://pypi.python.org/pypi/platformio/
:alt: Latest Version
.. image:: https://img.shields.io/pypi/l/platformio.svg
.. image:: https://img.shields.io/badge/license-Apache%202.0-blue.svg
:target: https://pypi.python.org/pypi/platformio/
:alt: License
.. image:: https://img.shields.io/PlatformIO/Community.png
.. image:: https://img.shields.io/badge/PlatformIO-Community-orange.svg
:alt: Community Forums
:target: https://community.platformio.org
.. image:: https://img.shields.io/PlatformIO/Plus.png?color=orange
:alt: PlatformIO Plus: Professional solutions for an awesome open source PlatformIO ecosystem
:target: https://pioplus.com
:target: https://community.platformio.org?utm_source=github&utm_medium=core
**Quick Links:** `Home Page <http://platformio.org>`_ |
`PlatformIO Plus <https://pioplus.com>`_ |
`PlatformIO IDE <http://platformio.org/platformio-ide>`_ |
`Project Examples <https://github.com/platformio/platformio-examples/>`_ |
`Docs <http://docs.platformio.org>`_ |
`Donate <http://platformio.org/donate>`_ |
`Contact Us <https://pioplus.com/contact.html>`_
**Quick Links:** `Web <https://platformio.org?utm_source=github&utm_medium=core>`_ |
`PlatformIO IDE <https://platformio.org/platformio-ide?utm_source=github&utm_medium=core>`_ |
`Project Examples <https://github.com/platformio/platformio-examples/>`__ |
`Docs <https://docs.platformio.org?utm_source=github&utm_medium=core>`_ |
`Donate <https://platformio.org/donate?utm_source=github&utm_medium=core>`_ |
`Contact Us <https://platformio.org/contact?utm_source=github&utm_medium=core>`_
**Social:** `Twitter <https://twitter.com/PlatformIO_Org>`_ |
`LinkedIn <https://www.linkedin.com/company/platformio/>`_ |
`Facebook <https://www.facebook.com/platformio>`_ |
`Hackaday <https://hackaday.io/project/7980-platformio>`_ |
`Bintray <https://bintray.com/platformio>`_ |
`Community <https://community.platformio.org>`_
`Community <https://community.platformio.org?utm_source=github&utm_medium=core>`_
.. image:: https://raw.githubusercontent.com/platformio/platformio-web/develop/app/images/platformio-ide-laptop.png
:target: http://platformio.org
:target: https://platformio.org?utm_source=github&utm_medium=core
`PlatformIO <http://platformio.org>`_ is an open source ecosystem for IoT
`PlatformIO <https://platformio.org?utm_source=github&utm_medium=core>`_ is an open source ecosystem for IoT
development. Cross-platform IDE and unified debugger. Remote unit testing and
firmware updates.
Get Started
-----------
* `What is PlatformIO? <http://docs.platformio.org/page/what-is-platformio.html>`_
* `What is PlatformIO? <https://docs.platformio.org/en/latest/what-is-platformio.html?utm_source=github&utm_medium=core>`_
Products
Open Source
-----------
* `PlatformIO IDE <https://platformio.org/platformio-ide?utm_source=github&utm_medium=core>`_
* `PlatformIO Core (CLI) <https://docs.platformio.org/en/latest/core.html?utm_source=github&utm_medium=core>`_
* `Library Management <https://docs.platformio.org/page/librarymanager/index.html?utm_source=github&utm_medium=core>`_
* `Project Examples <https://github.com/platformio/platformio-examples?utm_source=github&utm_medium=core>`__
* `Desktop IDEs Integration <https://docs.platformio.org/page/ide.html?utm_source=github&utm_medium=core>`_
* `Continuous Integration <https://docs.platformio.org/page/ci/index.html?utm_source=github&utm_medium=core>`_
* `Advanced Scripting API <https://docs.platformio.org/page/projectconf/advanced_scripting.html?utm_source=github&utm_medium=core>`_
PIO Plus
--------
* `PlatformIO IDE <http://platformio.org/platformio-ide>`_
* `PlatformIO Core <http://docs.platformio.org/page/core.html>`_
* `PIO Remote™ <http://docs.platformio.org/page/plus/pio-remote.html>`_
* `PIO Unified Debugger <http://docs.platformio.org/page/plus/debugging.html>`_
* `PIO Unit Testing <http://docs.platformio.org/page/plus/unit-testing.html>`_
* `PIO Delivery™ <http://platformio.org/pricing#solution-pio-delivery>`_
* `Cloud Builder <http://platformio.org/pricing#solution-cloud-builder>`_
* `PIO Remote <https://docs.platformio.org/page/plus/pio-remote.html?utm_source=github&utm_medium=core>`_
* `PIO Unified Debugger <https://docs.platformio.org/page/plus/debugging.html?utm_source=github&utm_medium=core>`_
* `PIO Unit Testing <https://docs.platformio.org/en/latest/plus/unit-testing.html?utm_source=github&utm_medium=core>`_
* `Cloud IDEs Integration <https://docs.platformio.org/en/latest/ide.html?utm_source=github&utm_medium=core#solution-pio-delivery>`_
* `Integration Services <https://platformio.org/pricing?utm_source=github&utm_medium=core#enterprise-features>`_
Registry
--------
* `Libraries <http://platformio.org/lib>`_
* `Development Platforms <http://platformio.org/platforms>`_
* `Frameworks <http://platformio.org/frameworks>`_
* `Embedded Boards <http://platformio.org/boards>`_
Solutions
---------
* `Library Manager <http://docs.platformio.org/page/librarymanager/index.html>`_
* `Cloud IDEs Integration <http://platformio.org/pricing#solution-cloud-ide>`_
* `Standalone IDEs Integration <http://docs.platformio.org/page/ide.html#other-ide>`_
* `Continuous Integration <http://docs.platformio.org/page/ci/index.html>`_
* `Libraries <https://platformio.org/lib?utm_source=github&utm_medium=core>`_
* `Development Platforms <https://platformio.org/platforms?utm_source=github&utm_medium=core>`_
* `Frameworks <https://platformio.org/frameworks?utm_source=github&utm_medium=core>`_
* `Embedded Boards <https://platformio.org/boards?utm_source=github&utm_medium=core>`_
Development Platforms
---------------------
* `Atmel AVR <http://platformio.org/platforms/atmelavr>`_
* `Atmel SAM <http://platformio.org/platforms/atmelsam>`_
* `Espressif 32 <http://platformio.org/platforms/espressif32>`_
* `Espressif 8266 <http://platformio.org/platforms/espressif8266>`_
* `Freescale Kinetis <http://platformio.org/platforms/freescalekinetis>`_
* `Intel ARC32 <http://platformio.org/platforms/intel_arc32>`_
* `Lattice iCE40 <http://platformio.org/platforms/lattice_ice40>`_
* `Maxim 32 <http://platformio.org/platforms/maxim32>`_
* `Microchip PIC32 <http://platformio.org/platforms/microchippic32>`_
* `Nordic nRF51 <http://platformio.org/platforms/nordicnrf51>`_
* `Nordic nRF52 <http://platformio.org/platforms/nordicnrf52>`_
* `NXP LPC <http://platformio.org/platforms/nxplpc>`_
* `Silicon Labs EFM32 <http://platformio.org/platforms/siliconlabsefm32>`_
* `ST STM32 <http://platformio.org/platforms/ststm32>`_
* `Teensy <http://platformio.org/platforms/teensy>`_
* `TI MSP430 <http://platformio.org/platforms/timsp430>`_
* `TI TivaVA C <http://platformio.org/platforms/titiva>`_
* `WIZNet W7500 <http://platformio.org/platforms/wiznet7500>`_
* `Aceinna IMU <https://platformio.org/platforms/aceinna_imu?utm_source=github&utm_medium=core>`_
* `Atmel AVR <https://platformio.org/platforms/atmelavr?utm_source=github&utm_medium=core>`_
* `Atmel SAM <https://platformio.org/platforms/atmelsam?utm_source=github&utm_medium=core>`_
* `Espressif 32 <https://platformio.org/platforms/espressif32?utm_source=github&utm_medium=core>`_
* `Espressif 8266 <https://platformio.org/platforms/espressif8266?utm_source=github&utm_medium=core>`_
* `Freescale Kinetis <https://platformio.org/platforms/freescalekinetis?utm_source=github&utm_medium=core>`_
* `Infineon XMC <https://platformio.org/platforms/infineonxmc?utm_source=github&utm_medium=core>`_
* `Intel ARC32 <https://platformio.org/platforms/intel_arc32?utm_source=github&utm_medium=core>`_
* `Intel MCS-51 (8051) <https://platformio.org/platforms/intel_mcs51?utm_source=github&utm_medium=core>`_
* `Kendryte K210 <https://platformio.org/platforms/kendryte210?utm_source=github&utm_medium=core>`_
* `Lattice iCE40 <https://platformio.org/platforms/lattice_ice40?utm_source=github&utm_medium=core>`_
* `Maxim 32 <https://platformio.org/platforms/maxim32?utm_source=github&utm_medium=core>`_
* `Microchip PIC32 <https://platformio.org/platforms/microchippic32?utm_source=github&utm_medium=core>`_
* `Nordic nRF51 <https://platformio.org/platforms/nordicnrf51?utm_source=github&utm_medium=core>`_
* `Nordic nRF52 <https://platformio.org/platforms/nordicnrf52?utm_source=github&utm_medium=core>`_
* `NXP LPC <https://platformio.org/platforms/nxplpc?utm_source=github&utm_medium=core>`_
* `RISC-V <https://platformio.org/platforms/riscv?utm_source=github&utm_medium=core>`_
* `RISC-V GAP <https://platformio.org/platforms/riscv_gap?utm_source=github&utm_medium=core>`_
* `Samsung ARTIK <https://platformio.org/platforms/samsung_artik?utm_source=github&utm_medium=core>`_
* `Silicon Labs EFM32 <https://platformio.org/platforms/siliconlabsefm32?utm_source=github&utm_medium=core>`_
* `ST STM32 <https://platformio.org/platforms/ststm32?utm_source=github&utm_medium=core>`_
* `ST STM8 <https://platformio.org/platforms/ststm8?utm_source=github&utm_medium=core>`_
* `Teensy <https://platformio.org/platforms/teensy?utm_source=github&utm_medium=core>`_
* `TI MSP430 <https://platformio.org/platforms/timsp430?utm_source=github&utm_medium=core>`_
* `TI Tiva <https://platformio.org/platforms/titiva?utm_source=github&utm_medium=core>`_
* `WIZNet W7500 <https://platformio.org/platforms/wiznet7500?utm_source=github&utm_medium=core>`_
Frameworks
----------
* `Arduino <http://platformio.org/frameworks/arduino>`_
* `ARTIK SDK <http://platformio.org/frameworks/artik-sdk>`_
* `CMSIS <http://platformio.org/frameworks/cmsis>`_
* `Energia <http://platformio.org/frameworks/energia>`_
* `ESP-IDF <http://platformio.org/frameworks/espidf>`_
* `libOpenCM3 <http://platformio.org/frameworks/libopencm3>`_
* `mbed <http://platformio.org/frameworks/mbed>`_
* `Pumbaa <http://platformio.org/frameworks/pumbaa>`_
* `Simba <http://platformio.org/frameworks/simba>`_
* `SPL <http://platformio.org/frameworks/spl>`_
* `STM32Cube <http://platformio.org/frameworks/stm32cube>`_
* `WiringPi <http://platformio.org/frameworks/wiringpi>`_
* `Arduino <https://platformio.org/frameworks/arduino?utm_source=github&utm_medium=core>`_
* `ARTIK SDK <https://platformio.org/frameworks/artik-sdk?utm_source=github&utm_medium=core>`_
* `CMSIS <https://platformio.org/frameworks/cmsis?utm_source=github&utm_medium=core>`_
* `Energia <https://platformio.org/frameworks/energia?utm_source=github&utm_medium=core>`_
* `ESP-IDF <https://platformio.org/frameworks/espidf?utm_source=github&utm_medium=core>`_
* `ESP8266 Non-OS SDK <https://platformio.org/frameworks/esp8266-nonos-sdk?utm_source=github&utm_medium=core>`_
* `ESP8266 RTOS SDK <https://platformio.org/frameworks/esp8266-rtos-sdk?utm_source=github&utm_medium=core>`_
* `Freedom E SDK <https://platformio.org/frameworks/freedom-e-sdk?utm_source=github&utm_medium=core>`_
* `Kendryte Standalone SDK <https://platformio.org/frameworks/kendryte-standalone-sdk?utm_source=github&utm_medium=core>`_
* `libOpenCM3 <https://platformio.org/frameworks/libopencm3?utm_source=github&utm_medium=core>`_
* `mbed <https://platformio.org/frameworks/mbed?utm_source=github&utm_medium=core>`_
* `PULP OS <https://platformio.org/frameworks/pulp-os?utm_source=github&utm_medium=core>`_
* `Pumbaa <https://platformio.org/frameworks/pumbaa?utm_source=github&utm_medium=core>`_
* `Simba <https://platformio.org/frameworks/simba?utm_source=github&utm_medium=core>`_
* `SPL <https://platformio.org/frameworks/spl?utm_source=github&utm_medium=core>`_
* `STM32Cube <https://platformio.org/frameworks/stm32cube?utm_source=github&utm_medium=core>`_
* `Tizen RT <https://platformio.org/frameworks/tizenrt?utm_source=github&utm_medium=core>`_
* `WiringPi <https://platformio.org/frameworks/wiringpi?utm_source=github&utm_medium=core>`_
Contributing
------------
See `contributing guidelines <https://github.com/platformio/platformio/blob/develop/CONTRIBUTING.md>`_.
Telemetry / Privacy Policy
--------------------------
Share minimal diagnostics and usage information to help us make PlatformIO better.
It is enabled by default. For more information see:
* `Telemetry Setting <https://docs.platformio.org/en/latest/userguide/cmd_settings.html?utm_source=github&utm_medium=core#enable-telemetry>`_
* `SSL Setting <https://docs.platformio.org/en/latest/userguide/cmd_settings.html?utm_source=github&utm_medium=core#strict-ssl>`_
License
-------

2
docs

Submodule docs updated: 58574c0741...3f5d12ca25

View File

@@ -12,29 +12,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
VERSION = (3, 4, 0)
VERSION = (4, 0, 2)
__version__ = ".".join([str(s) for s in VERSION])
__title__ = "platformio"
__description__ = ("An open source ecosystem for IoT development. "
"Cross-platform build system and library manager. "
"Continuous and IDE integration. "
"Arduino, ESP8266 and ARM mbed compatible")
__url__ = "http://platformio.org"
__description__ = (
"An open source ecosystem for IoT development. "
"Cross-platform IDE and unified debugger. "
"Remote unit testing and firmware updates. "
"Arduino, ARM mbed, Espressif (ESP8266/ESP32), STM32, PIC32, nRF51/nRF52, "
"FPGA, CMSIS, SPL, AVR, Samsung ARTIK, libOpenCM3")
__url__ = "https://platformio.org"
__author__ = "Ivan Kravets"
__email__ = "me@ikravets.com"
__author__ = "PlatformIO"
__email__ = "contact@platformio.org"
__license__ = "Apache Software License"
__copyright__ = "Copyright 2014-present PlatformIO"
__apiurl__ = "https://api.platformio.org"
if sys.version_info < (2, 7, 0) or sys.version_info >= (3, 0, 0):
msg = ("PlatformIO Core v%s does not run under Python version %s.\n"
"Minimum supported version is 2.7, please upgrade Python.\n"
"Python 3 is not yet supported.\n")
sys.stderr.write(msg % (__version__, sys.version.split()[0]))
sys.exit(1)

View File

@@ -14,60 +14,22 @@
import os
import sys
from os.path import join
from platform import system
from traceback import format_exc
import click
from platformio import __version__, exception, maintenance
from platformio.util import get_source_dir
from platformio import __version__, exception, maintenance, util
from platformio.commands import PlatformioCLI
from platformio.compat import CYGWIN
class PlatformioCLI(click.MultiCommand): # pylint: disable=R0904
def list_commands(self, ctx):
cmds = []
for filename in os.listdir(join(get_source_dir(), "commands")):
if filename.startswith("__init__"):
continue
if filename.endswith(".py"):
cmds.append(filename[:-3])
cmds.sort()
return cmds
def get_command(self, ctx, cmd_name):
mod = None
try:
mod = __import__("platformio.commands." + cmd_name, None, None,
["cli"])
except ImportError:
try:
return self._handle_obsolate_command(cmd_name)
except AttributeError:
raise click.UsageError('No such command "%s"' % cmd_name, ctx)
return mod.cli
@staticmethod
def _handle_obsolate_command(name):
if name == "platforms":
from platformio.commands import platform
return platform.cli
elif name == "serialports":
from platformio.commands import device
return device.cli
raise AttributeError()
@click.command(
cls=PlatformioCLI,
context_settings=dict(help_option_names=["-h", "--help"]))
@click.command(cls=PlatformioCLI,
context_settings=dict(help_option_names=["-h", "--help"]))
@click.version_option(__version__, prog_name="PlatformIO")
@click.option(
"--force",
"-f",
is_flag=True,
help="Force to accept any confirmation prompts.")
@click.option("--force",
"-f",
is_flag=True,
help="Force to accept any confirmation prompts.")
@click.option("--caller", "-c", help="Caller ID (service).")
@click.pass_context
def cli(ctx, force, caller):
@@ -80,29 +42,53 @@ def process_result(ctx, result, force, caller): # pylint: disable=W0613
maintenance.on_platformio_end(ctx, result)
def main():
try:
if "cygwin" in system().lower():
raise exception.CygwinEnvDetected()
@util.memoized()
def configure():
if CYGWIN:
raise exception.CygwinEnvDetected()
# https://urllib3.readthedocs.org
# /en/latest/security.html#insecureplatformwarning
# https://urllib3.readthedocs.org
# /en/latest/security.html#insecureplatformwarning
try:
import urllib3
urllib3.disable_warnings()
except (AttributeError, ImportError):
pass
# handle PLATFORMIO_FORCE_COLOR
if str(os.getenv("PLATFORMIO_FORCE_COLOR", "")).lower() == "true":
try:
import urllib3
urllib3.disable_warnings()
except (AttributeError, ImportError):
# pylint: disable=protected-access
click._compat.isatty = lambda stream: True
except: # pylint: disable=bare-except
pass
# handle PLATFORMIO_FORCE_COLOR
if str(os.getenv("PLATFORMIO_FORCE_COLOR", "")).lower() == "true":
try:
# pylint: disable=protected-access
click._compat.isatty = lambda stream: True
except: # pylint: disable=bare-except
pass
# Handle IOError issue with VSCode's Terminal (Windows)
click_echo_origin = [click.echo, click.secho]
def _safe_echo(origin, *args, **kwargs):
try:
click_echo_origin[origin](*args, **kwargs)
except IOError:
(sys.stderr.write if kwargs.get("err") else sys.stdout.write)(
"%s\n" % (args[0] if args else ""))
click.echo = lambda *args, **kwargs: _safe_echo(0, *args, **kwargs)
click.secho = lambda *args, **kwargs: _safe_echo(1, *args, **kwargs)
def main(argv=None):
exit_code = 0
prev_sys_argv = sys.argv[:]
if argv:
assert isinstance(argv, list)
sys.argv = argv
try:
configure()
cli(None, None, None)
except Exception as e: # pylint: disable=W0703
except SystemExit:
pass
except Exception as e: # pylint: disable=broad-except
if not isinstance(e, exception.ReturnErrorCode):
maintenance.on_platformio_exception(e)
error_str = "Error: "
@@ -119,7 +105,7 @@ An unexpected error occurred. Further steps:
`pip install -U platformio` command
* Try to find answer in FAQ Troubleshooting section
http://docs.platformio.org/page/faq.html
https://docs.platformio.org/page/faq.html
* Report this problem to the developers
https://github.com/platformio/platformio-core/issues
@@ -127,13 +113,13 @@ An unexpected error occurred. Further steps:
============================================================
"""
click.secho(error_str, fg="red", err=True)
return int(str(e)) if str(e).isdigit() else 1
return 0
exit_code = int(str(e)) if str(e).isdigit() else 1
sys.argv = prev_sys_argv
return exit_code
def debug_gdb_main():
sys.argv = [sys.argv[0], "debug", "--interface", "gdb"] + sys.argv[1:]
return main()
return main([sys.argv[0], "debug", "--interface", "gdb"] + sys.argv[1:])
if __name__ == "__main__":

View File

@@ -12,22 +12,55 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import codecs
import hashlib
import json
import os
import uuid
from copy import deepcopy
from os import environ, getenv, listdir, remove
from os.path import dirname, getmtime, isdir, isfile, join
from os.path import abspath, dirname, expanduser, isdir, isfile, join
from time import time
import requests
from lockfile import LockFailed, LockFile
from platformio import __version__, exception, util
from platformio.exception import InvalidSettingName, InvalidSettingValue
from platformio import exception, fs, lockfile
from platformio.compat import (WINDOWS, dump_json_to_unicode,
hashlib_encode_data)
from platformio.proc import is_ci
from platformio.project.helpers import (get_project_cache_dir,
get_project_core_dir)
def get_default_projects_dir():
docs_dir = join(expanduser("~"), "Documents")
try:
assert WINDOWS
import ctypes.wintypes
buf = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH)
ctypes.windll.shell32.SHGetFolderPathW(None, 5, None, 0, buf)
docs_dir = buf.value
except: # pylint: disable=bare-except
pass
return join(docs_dir, "PlatformIO", "Projects")
def projects_dir_validate(projects_dir):
assert isdir(projects_dir)
return abspath(projects_dir)
DEFAULT_SETTINGS = {
"auto_update_libraries": {
"description": "Automatically update libraries (Yes/No)",
"value": False
},
"auto_update_platforms": {
"description": "Automatically update platforms (Yes/No)",
"value": False
},
"check_libraries_interval": {
"description": "Check for the library updates interval (days)",
"value": 7
},
"check_platformio_interval": {
"description": "Check for the new PlatformIO interval (days)",
"value": 3
@@ -36,37 +69,28 @@ DEFAULT_SETTINGS = {
"description": "Check for the platform updates interval (days)",
"value": 7
},
"check_libraries_interval": {
"description": "Check for the library updates interval (days)",
"value": 7
"enable_cache": {
"description": "Enable caching for API requests and Library Manager",
"value": True
},
"auto_update_platforms": {
"description": "Automatically update platforms (Yes/No)",
"strict_ssl": {
"description": "Strict SSL for PlatformIO Services",
"value": False
},
"auto_update_libraries": {
"description": "Automatically update libraries (Yes/No)",
"value": False
"enable_telemetry": {
"description":
("Telemetry service <http://bit.ly/pio-telemetry> (Yes/No)"),
"value": True
},
"force_verbose": {
"description": "Force verbose output when processing environments",
"value": False
},
"enable_ssl": {
"description": "Enable SSL for PlatformIO Services",
"value": False
"projects_dir": {
"description": "Default location for PlatformIO projects (PIO Home)",
"value": get_default_projects_dir(),
"validator": projects_dir_validate
},
"enable_cache": {
"description": "Enable caching for API requests and Library Manager",
"value": True
},
"enable_telemetry": {
"description":
("Telemetry service <http://docs.platformio.org/page/"
"userguide/cmd_settings.html?#enable-telemetry> (Yes/No)"),
"value":
True
}
}
SESSION_VARS = {"command_ctx": None, "force_option": False, "caller_id": None}
@@ -78,54 +102,76 @@ class State(object):
self.path = path
self.lock = lock
if not self.path:
self.path = join(util.get_home_dir(), "appstate.json")
self._state = {}
self._prev_state = {}
self.path = join(get_project_core_dir(), "appstate.json")
self._storage = {}
self._lockfile = None
self.modified = False
def __enter__(self):
try:
self._lock_state_file()
if isfile(self.path):
self._state = util.load_json(self.path)
except ValueError:
self._state = {}
self._prev_state = deepcopy(self._state)
return self._state
self._storage = fs.load_json(self.path)
assert isinstance(self._storage, dict)
except (AssertionError, ValueError, UnicodeDecodeError,
exception.InvalidJSONFile):
self._storage = {}
return self
def __exit__(self, type_, value, traceback):
if self._prev_state != self._state:
with open(self.path, "w") as fp:
if "dev" in __version__:
json.dump(self._state, fp, indent=4)
else:
json.dump(self._state, fp)
if self.modified:
try:
with open(self.path, "w") as fp:
fp.write(dump_json_to_unicode(self._storage))
except IOError:
raise exception.HomeDirPermissionsError(get_project_core_dir())
self._unlock_state_file()
def _lock_state_file(self):
if not self.lock:
return
self._lockfile = LockFile(self.path)
if self._lockfile.is_locked() and \
(time() - getmtime(self._lockfile.lock_file)) > 10:
self._lockfile.break_lock()
self._lockfile = lockfile.LockFile(self.path)
try:
self._lockfile.acquire()
except LockFailed:
raise exception.PlatformioException(
"The directory `{0}` or its parent directory is not owned by "
"the current user and PlatformIO can not store configuration "
"data. \nPlease check the permissions and owner of that "
"directory. Otherwise, please remove manually `{0}` "
"directory and PlatformIO will create new from the current "
"user.".format(dirname(self.path)))
except IOError:
raise exception.HomeDirPermissionsError(dirname(self.path))
def _unlock_state_file(self):
if self._lockfile:
if hasattr(self, "_lockfile") and self._lockfile:
self._lockfile.release()
def __del__(self):
self._unlock_state_file()
# Dictionary Proxy
def as_dict(self):
return self._storage
def get(self, key, default=True):
return self._storage.get(key, default)
def update(self, *args, **kwargs):
self.modified = True
return self._storage.update(*args, **kwargs)
def clear(self):
return self._storage.clear()
def __getitem__(self, key):
return self._storage[key]
def __setitem__(self, key, value):
self.modified = True
self._storage[key] = value
def __delitem__(self, key):
self.modified = True
del self._storage[key]
def __contains__(self, item):
return item in self._storage
class ContentCache(object):
@@ -134,16 +180,10 @@ class ContentCache(object):
self._db_path = None
self._lockfile = None
if not get_setting("enable_cache"):
return
self.cache_dir = cache_dir or join(util.get_home_dir(), ".cache")
self.cache_dir = cache_dir or get_project_cache_dir()
self._db_path = join(self.cache_dir, "db.data")
def __enter__(self):
if not self._db_path or not isfile(self._db_path):
return self
self.delete()
return self
@@ -153,14 +193,10 @@ class ContentCache(object):
def _lock_dbindex(self):
if not self.cache_dir:
os.makedirs(self.cache_dir)
self._lockfile = LockFile(self.cache_dir)
if self._lockfile.is_locked() and \
(time() - getmtime(self._lockfile.lock_file)) > 10:
self._lockfile.break_lock()
self._lockfile = lockfile.LockFile(self.cache_dir)
try:
self._lockfile.acquire()
except LockFailed:
except: # pylint: disable=bare-except
return False
return True
@@ -171,36 +207,37 @@ class ContentCache(object):
return True
def get_cache_path(self, key):
key = str(key)
assert len(key) > 3
return join(self.cache_dir, key[-2:], key)
@staticmethod
def key_from_args(*args):
h = hashlib.md5()
for data in args:
h.update(str(data))
for arg in args:
if arg:
h.update(hashlib_encode_data(arg))
return h.hexdigest()
def get(self, key):
cache_path = self.get_cache_path(key)
if not isfile(cache_path):
return None
with open(cache_path, "rb") as fp:
data = fp.read()
if data and data[0] in ("{", "["):
return json.loads(data)
return data
with codecs.open(cache_path, "rb", encoding="utf8") as fp:
return fp.read()
def set(self, key, data, valid):
if not get_setting("enable_cache"):
return False
cache_path = self.get_cache_path(key)
if isfile(cache_path):
self.delete(key)
if not data:
return
return False
if not isdir(self.cache_dir):
os.makedirs(self.cache_dir)
tdmap = {"s": 1, "m": 60, "h": 3600, "d": 86400}
assert valid.endswith(tuple(tdmap.keys()))
assert valid.endswith(tuple(tdmap))
expire_time = int(time() + tdmap[valid[-1]] * int(valid[:-1]))
if not self._lock_dbindex():
@@ -208,18 +245,24 @@ class ContentCache(object):
if not isdir(dirname(cache_path)):
os.makedirs(dirname(cache_path))
with open(cache_path, "wb") as fp:
if isinstance(data, (dict, list)):
json.dump(data, fp)
else:
fp.write(str(data))
with open(self._db_path, "a") as fp:
fp.write("%s=%s\n" % (str(expire_time), cache_path))
try:
with codecs.open(cache_path, "wb", encoding="utf8") as fp:
fp.write(data)
with open(self._db_path, "a") as fp:
fp.write("%s=%s\n" % (str(expire_time), cache_path))
except UnicodeError:
if isfile(cache_path):
try:
remove(cache_path)
except OSError:
pass
return self._unlock_dbindex()
def delete(self, keys=None):
""" Keys=None, delete expired items """
if not isfile(self._db_path):
return None
if not keys:
keys = []
if not isinstance(keys, list):
@@ -229,20 +272,23 @@ class ContentCache(object):
newlines = []
with open(self._db_path) as fp:
for line in fp.readlines():
line = line.strip()
if "=" not in line:
continue
line = line.strip()
expire, path = line.split("=")
if time() < int(expire) and isfile(path) and \
path not in paths_for_delete:
newlines.append(line)
continue
try:
if time() < int(expire) and isfile(path) and \
path not in paths_for_delete:
newlines.append(line)
continue
except ValueError:
pass
found = True
if isfile(path):
try:
remove(path)
if not listdir(dirname(path)):
util.rmtree_(dirname(path))
fs.rmtree(dirname(path))
except OSError:
pass
@@ -256,7 +302,7 @@ class ContentCache(object):
def clean(self):
if not self.cache_dir or not isdir(self.cache_dir):
return
util.rmtree_(self.cache_dir)
fs.rmtree(self.cache_dir)
def clean_cache():
@@ -266,36 +312,37 @@ def clean_cache():
def sanitize_setting(name, value):
if name not in DEFAULT_SETTINGS:
raise InvalidSettingName(name)
raise exception.InvalidSettingName(name)
defdata = DEFAULT_SETTINGS[name]
try:
if "validator" in defdata:
value = defdata['validator']()
value = defdata['validator'](value)
elif isinstance(defdata['value'], bool):
if not isinstance(value, bool):
value = str(value).lower() in ("true", "yes", "y", "1")
elif isinstance(defdata['value'], int):
value = int(value)
except Exception:
raise InvalidSettingValue(value, name)
raise exception.InvalidSettingValue(value, name)
return value
def get_state_item(name, default=None):
with State() as data:
return data.get(name, default)
with State() as state:
return state.get(name, default)
def set_state_item(name, value):
with State(lock=True) as data:
data[name] = value
with State(lock=True) as state:
state[name] = value
state.modified = True
def delete_state_item(name):
with State(lock=True) as data:
if name in data:
del data[name]
with State(lock=True) as state:
if name in state:
del state[name]
def get_setting(name):
@@ -303,24 +350,25 @@ def get_setting(name):
if _env_name in environ:
return sanitize_setting(name, getenv(_env_name))
with State() as data:
if "settings" in data and name in data['settings']:
return data['settings'][name]
with State() as state:
if "settings" in state and name in state['settings']:
return state['settings'][name]
return DEFAULT_SETTINGS[name]['value']
def set_setting(name, value):
with State(lock=True) as data:
if "settings" not in data:
data['settings'] = {}
data['settings'][name] = sanitize_setting(name, value)
with State(lock=True) as state:
if "settings" not in state:
state['settings'] = {}
state['settings'][name] = sanitize_setting(name, value)
state.modified = True
def reset_settings():
with State(lock=True) as data:
if "settings" in data:
del data['settings']
with State(lock=True) as state:
if "settings" in state:
del state['settings']
def get_session_var(name, default=None):
@@ -335,26 +383,29 @@ def set_session_var(name, value):
def is_disabled_progressbar():
return any([
get_session_var("force_option"),
util.is_ci(),
is_ci(),
getenv("PLATFORMIO_DISABLE_PROGRESSBAR") == "true"
])
def get_cid():
cid = get_state_item("cid")
if not cid:
_uid = None
if getenv("C9_UID"):
_uid = getenv("C9_UID")
elif getenv("CHE_API", getenv("CHE_API_ENDPOINT")):
try:
_uid = requests.get("{api}/user?token={token}".format(
api=getenv("CHE_API", getenv("CHE_API_ENDPOINT")),
token=getenv("USER_TOKEN"))).json().get("id")
except: # pylint: disable=bare-except
pass
cid = str(
uuid.UUID(bytes=hashlib.md5(str(_uid if _uid else uuid.getnode()))
.digest()))
if cid:
return cid
uid = None
if getenv("C9_UID"):
uid = getenv("C9_UID")
elif getenv("CHE_API", getenv("CHE_API_ENDPOINT")):
try:
uid = requests.get("{api}/user?token={token}".format(
api=getenv("CHE_API", getenv("CHE_API_ENDPOINT")),
token=getenv("USER_TOKEN"))).json().get("id")
except: # pylint: disable=bare-except
pass
if not uid:
uid = uuid.getnode()
cid = uuid.UUID(bytes=hashlib.md5(hashlib_encode_data(uid)).digest())
cid = str(cid)
if WINDOWS or os.getuid() > 0: # yapf: disable pylint: disable=no-member
set_state_item("cid", cid)
return cid

View File

@@ -12,90 +12,74 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import base64
import json
import sys
from os import environ
from os.path import join
from os import environ, makedirs
from os.path import isdir, join
from time import time
from SCons.Script import (ARGUMENTS, COMMAND_LINE_TARGETS, DEFAULT_TARGETS,
AllowSubstExceptions, AlwaysBuild,
DefaultEnvironment, Variables)
import click
from SCons.Script import ARGUMENTS # pylint: disable=import-error
from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error
from SCons.Script import DEFAULT_TARGETS # pylint: disable=import-error
from SCons.Script import AllowSubstExceptions # pylint: disable=import-error
from SCons.Script import AlwaysBuild # pylint: disable=import-error
from SCons.Script import Default # pylint: disable=import-error
from SCons.Script import DefaultEnvironment # pylint: disable=import-error
from SCons.Script import Import # pylint: disable=import-error
from SCons.Script import Variables # pylint: disable=import-error
from platformio import util
from platformio import fs
from platformio.compat import PY2, dump_json_to_unicode
from platformio.managers.platform import PlatformBase
from platformio.proc import get_pythonexe_path
from platformio.project import helpers as project_helpers
AllowSubstExceptions(NameError)
# allow common variables from INI file
commonvars = Variables(None)
commonvars.AddVariables(
# append CLI arguments to build environment
clivars = Variables(None)
clivars.AddVariables(
("PLATFORM_MANIFEST",),
("BUILD_SCRIPT",),
("EXTRA_SCRIPT",),
("PROJECT_CONFIG",),
("PIOENV",),
("PIOTEST",),
("PIOPLATFORM",),
("PIOFRAMEWORK",),
# build options
("BUILD_FLAGS",),
("SRC_BUILD_FLAGS",),
("BUILD_UNFLAGS",),
("SRC_FILTER",),
# library options
("LIB_LDF_MODE",),
("LIB_COMPAT_MODE",),
("LIB_DEPS",),
("LIB_IGNORE",),
("LIB_EXTRA_DIRS",),
# board options
("BOARD",),
("BOARD_MCU",),
("BOARD_F_CPU",),
("BOARD_F_FLASH",),
("BOARD_FLASH_MODE",),
# upload options
("UPLOAD_PORT",),
("UPLOAD_PROTOCOL",),
("UPLOAD_SPEED",),
("UPLOAD_FLAGS",),
("UPLOAD_RESETMETHOD",)
("PIOTEST_RUNNING_NAME",),
("UPLOAD_PORT",)
) # yapf: disable
DEFAULT_ENV_OPTIONS = dict(
tools=[
"ar", "as", "gcc", "g++", "gnulink", "platformio", "pioplatform",
"piowinhooks", "piolib", "pioupload", "piomisc", "pioide"
], # yapf: disable
toolpath=[join(util.get_source_dir(), "builder", "tools")],
variables=commonvars,
"ar", "gas", "gcc", "g++", "gnulink", "platformio", "pioplatform",
"pioproject", "piowinhooks", "piolib", "pioupload", "piomisc", "pioide"
],
toolpath=[join(fs.get_source_dir(), "builder", "tools")],
variables=clivars,
# Propagating External Environment
PIOVARIABLES=commonvars.keys(),
ENV=environ,
UNIX_TIME=int(time()),
PIOHOME_DIR=util.get_home_dir(),
PROJECT_DIR=util.get_project_dir(),
PROJECTSRC_DIR=util.get_projectsrc_dir(),
PROJECTTEST_DIR=util.get_projecttest_dir(),
PROJECTDATA_DIR=util.get_projectdata_dir(),
PROJECTPIOENVS_DIR=util.get_projectpioenvs_dir(),
BUILD_DIR=join("$PROJECTPIOENVS_DIR", "$PIOENV"),
PROJECT_DIR=project_helpers.get_project_dir(),
PROJECTCORE_DIR=project_helpers.get_project_core_dir(),
PROJECTPACKAGES_DIR=project_helpers.get_project_packages_dir(),
PROJECTWORKSPACE_DIR=project_helpers.get_project_workspace_dir(),
PROJECTLIBDEPS_DIR=project_helpers.get_project_libdeps_dir(),
PROJECTINCLUDE_DIR=project_helpers.get_project_include_dir(),
PROJECTSRC_DIR=project_helpers.get_project_src_dir(),
PROJECTTEST_DIR=project_helpers.get_project_test_dir(),
PROJECTDATA_DIR=project_helpers.get_project_data_dir(),
PROJECTBUILD_DIR=project_helpers.get_project_build_dir(),
BUILDCACHE_DIR=project_helpers.get_project_optional_dir("build_cache_dir"),
BUILD_DIR=join("$PROJECTBUILD_DIR", "$PIOENV"),
BUILDSRC_DIR=join("$BUILD_DIR", "src"),
BUILDTEST_DIR=join("$BUILD_DIR", "test"),
LIBPATH=["$BUILD_DIR"],
LIBSOURCE_DIRS=[
util.get_projectlib_dir(),
util.get_projectlibdeps_dir(),
join("$PIOHOME_DIR", "lib")
project_helpers.get_project_lib_dir(),
join("$PROJECTLIBDEPS_DIR", "$PIOENV"),
project_helpers.get_project_global_lib_dir()
],
PROGNAME="program",
PROG_PATH=join("$BUILD_DIR", "$PROGNAME$PROGSUFFIX"),
PYTHONEXE=util.get_pythonexe_path())
PYTHONEXE=get_pythonexe_path())
if not int(ARGUMENTS.get("PIOVERBOSE", 0)):
DEFAULT_ENV_OPTIONS['ARCOMSTR'] = "Archiving $TARGET"
@@ -106,75 +90,78 @@ if not int(ARGUMENTS.get("PIOVERBOSE", 0)):
env = DefaultEnvironment(**DEFAULT_ENV_OPTIONS)
# decode common variables
for k in commonvars.keys():
if k in env:
env[k] = base64.b64decode(env[k])
if "\n" in env[k]:
env[k] = [v.strip() for v in env[k].split("\n") if v.strip()]
# Load variables from CLI
env.Replace(
**{
key: PlatformBase.decode_scons_arg(env[key])
for key in list(clivars.keys()) if key in env
})
if env.subst("$BUILDCACHE_DIR"):
if not isdir(env.subst("$BUILDCACHE_DIR")):
makedirs(env.subst("$BUILDCACHE_DIR"))
env.CacheDir("$BUILDCACHE_DIR")
if int(ARGUMENTS.get("ISATTY", 0)):
# pylint: disable=protected-access
click._compat.isatty = lambda stream: True
if env.GetOption('clean'):
env.PioClean(env.subst("$BUILD_DIR"))
env.Exit(0)
elif not int(ARGUMENTS.get("PIOVERBOSE", 0)):
print "Verbose mode can be enabled via `-v, --verbose` option"
print("Verbose mode can be enabled via `-v, --verbose` option")
# Handle custom variables from system environment
for var in ("BUILD_FLAGS", "SRC_BUILD_FLAGS", "SRC_FILTER", "EXTRA_SCRIPT",
"UPLOAD_PORT", "UPLOAD_FLAGS", "LIB_EXTRA_DIRS"):
k = "PLATFORMIO_%s" % var
if k not in environ:
continue
if var in ("UPLOAD_PORT", "EXTRA_SCRIPT") or not env.get(var):
env[var] = environ.get(k)
elif isinstance(env[var], list):
env.Append(**{var: environ.get(k)})
else:
env[var] = "%s%s%s" % (environ.get(k), ", "
if var == "LIB_EXTRA_DIRS" else " ", env[var])
# Parse comma separated items
for opt in ("PIOFRAMEWORK", "LIB_DEPS", "LIB_IGNORE", "LIB_EXTRA_DIRS"):
if opt not in env or isinstance(env[opt], list):
continue
env[opt] = [l.strip() for l in env[opt].split(", ") if l.strip()]
# Configure extra library source directories for LDF
if util.get_project_optional_dir("lib_extra_dirs"):
items = util.get_project_optional_dir("lib_extra_dirs")
env.Prepend(LIBSOURCE_DIRS=[
l.strip() for l in items.split("\n" if "\n" in items else ", ")
if l.strip()
])
env.Prepend(LIBSOURCE_DIRS=env.get("LIB_EXTRA_DIRS", []))
env.LoadPioPlatform(commonvars)
env.LoadProjectOptions()
env.LoadPioPlatform()
env.SConscriptChdir(0)
env.SConsignFile(join("$PROJECTPIOENVS_DIR", ".sconsign.dblite"))
env.SConsignFile(
join("$PROJECTBUILD_DIR",
".sconsign.dblite" if PY2 else ".sconsign3.dblite"))
for item in env.GetExtraScripts("pre"):
env.SConscript(item, exports="env")
env.SConscript("$BUILD_SCRIPT")
AlwaysBuild(env.Alias("__debug", DEFAULT_TARGETS + ["size"]))
AlwaysBuild(env.Alias("__test", DEFAULT_TARGETS + ["size"]))
if "UPLOAD_FLAGS" in env:
env.Append(UPLOADERFLAGS=["$UPLOAD_FLAGS"])
env.Prepend(UPLOADERFLAGS=["$UPLOAD_FLAGS"])
if env.GetProjectOption("upload_command"):
env.Replace(UPLOADCMD=env.GetProjectOption("upload_command"))
if env.get("EXTRA_SCRIPT"):
env.SConscript(env.get("EXTRA_SCRIPT"), exports="env")
for item in env.GetExtraScripts("post"):
env.SConscript(item, exports="env")
##############################################################################
# Checking program size
if env.get("SIZETOOL") and "nobuild" not in COMMAND_LINE_TARGETS:
env.Depends(["upload", "program"], "checkprogsize")
# Replace platform's "size" target with our
_new_targets = [t for t in DEFAULT_TARGETS if str(t) != "size"]
Default(None)
Default(_new_targets)
Default("checkprogsize")
# Print configured protocols
env.AddPreAction(["upload", "program"],
env.VerboseAction(
lambda source, target, env: env.PrintUploadInfo(),
"Configuring upload protocol..."))
AlwaysBuild(env.Alias("debug", DEFAULT_TARGETS))
AlwaysBuild(env.Alias("__test", DEFAULT_TARGETS))
##############################################################################
if "envdump" in COMMAND_LINE_TARGETS:
print env.Dump()
print(env.Dump())
env.Exit(0)
if "idedata" in COMMAND_LINE_TARGETS:
try:
print "\n%s\n" % json.dumps(env.DumpIDEData())
env.Exit(0)
except UnicodeDecodeError:
sys.stderr.write(
"\nUnicodeDecodeError: Non-ASCII characters found in build "
"environment\n"
"See explanation in FAQ > Troubleshooting > Building\n"
"http://docs.platformio.org/page/faq.html\n\n")
env.Exit(1)
Import("projenv")
print("\n%s\n" % dump_json_to_unicode(
env.DumpIDEData(projenv) # pylint: disable=undefined-variable
))
env.Exit(0)

View File

@@ -15,32 +15,36 @@
from __future__ import absolute_import
from glob import glob
from os.path import join
from os import environ
from os.path import abspath, isfile, join
from SCons.Defaults import processDefines
from SCons.Defaults import processDefines # pylint: disable=import-error
from platformio import util
from platformio.compat import glob_escape
from platformio.managers.core import get_core_package_dir
from platformio.proc import exec_command, where_is_program
def dump_includes(env):
def _dump_includes(env, projenv):
includes = []
for item in env.get("CPPPATH", []):
includes.append(env.subst(item))
for item in projenv.get("CPPPATH", []):
includes.append(projenv.subst(item))
# installed libs
for lb in env.GetLibBuilders():
includes.extend(lb.get_inc_dirs())
includes.extend(lb.get_include_dirs())
# includes from toolchains
p = env.PioPlatform()
for name in p.get_installed_packages():
if p.get_package_type(name) != "toolchain":
continue
toolchain_dir = util.glob_escape(p.get_package_dir(name))
toolchain_dir = glob_escape(p.get_package_dir(name))
toolchain_incglobs = [
join(toolchain_dir, "*", "include*"),
join(toolchain_dir, "*", "include", "c++", "*"),
join(toolchain_dir, "*", "include", "c++", "*", "*-*-*"),
join(toolchain_dir, "lib", "gcc", "*", "*", "include*")
]
for g in toolchain_incglobs:
@@ -50,10 +54,43 @@ def dump_includes(env):
if unity_dir:
includes.append(unity_dir)
return includes
includes.extend(
[env.subst("$PROJECTINCLUDE_DIR"),
env.subst("$PROJECTSRC_DIR")])
# remove duplicates
result = []
for item in includes:
if item not in result:
result.append(abspath(item))
return result
def dump_defines(env):
def _get_gcc_defines(env):
items = []
try:
sysenv = environ.copy()
sysenv['PATH'] = str(env['ENV']['PATH'])
result = exec_command("echo | %s -dM -E -" % env.subst("$CC"),
env=sysenv,
shell=True)
except OSError:
return items
if result['returncode'] != 0:
return items
for line in result['out'].split("\n"):
tokens = line.strip().split(" ", 2)
if not tokens or tokens[0] != "#define":
continue
if len(tokens) > 2:
items.append("%s=%s" % (tokens[1], tokens[2]))
else:
items.append(tokens[1])
return items
def _dump_defines(env):
defines = []
# global symbols
for item in processDefines(env.get("CPPDEFINES", [])):
@@ -61,35 +98,73 @@ def dump_defines(env):
# special symbol for Atmel AVR MCU
if env['PIOPLATFORM'] == "atmelavr":
defines.append(
"__AVR_%s__" % env.BoardConfig().get("build.mcu").upper()
.replace("ATMEGA", "ATmega").replace("ATTINY", "ATtiny"))
board_mcu = env.get("BOARD_MCU")
if not board_mcu and "BOARD" in env:
board_mcu = env.BoardConfig().get("build.mcu")
if board_mcu:
defines.append(
str("__AVR_%s__" % board_mcu.upper().replace(
"ATMEGA", "ATmega").replace("ATTINY", "ATtiny")))
# built-in GCC marcos
# if env.GetCompilerType() == "gcc":
# defines.extend(_get_gcc_defines(env))
return defines
def DumpIDEData(env):
LINTCCOM = "$CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS"
LINTCXXCOM = "$CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS"
def _get_svd_path(env):
svd_path = env.GetProjectOption("debug_svd_path")
if svd_path:
return abspath(svd_path)
if "BOARD" not in env:
return None
try:
svd_path = env.BoardConfig().get("debug.svd_path")
assert svd_path
except (AssertionError, KeyError):
return None
# custom path to SVD file
if isfile(svd_path):
return svd_path
# default file from ./platform/misc/svd folder
p = env.PioPlatform()
if isfile(join(p.get_dir(), "misc", "svd", svd_path)):
return abspath(join(p.get_dir(), "misc", "svd", svd_path))
return None
def DumpIDEData(env, projenv):
LINTCCOM = "$CFLAGS $CCFLAGS $CPPFLAGS"
LINTCXXCOM = "$CXXFLAGS $CCFLAGS $CPPFLAGS"
data = {
"libsource_dirs":
[env.subst(l) for l in env.get("LIBSOURCE_DIRS", [])],
"libsource_dirs": [env.subst(l) for l in env.GetLibSourceDirs()],
"defines":
dump_defines(env),
_dump_defines(env),
"includes":
dump_includes(env),
_dump_includes(env, projenv),
"cc_flags":
env.subst(LINTCCOM),
"cxx_flags":
env.subst(LINTCXXCOM),
"cc_path":
util.where_is_program(env.subst("$CC"), env.subst("${ENV['PATH']}")),
where_is_program(env.subst("$CC"), env.subst("${ENV['PATH']}")),
"cxx_path":
util.where_is_program(env.subst("$CXX"), env.subst("${ENV['PATH']}")),
where_is_program(env.subst("$CXX"), env.subst("${ENV['PATH']}")),
"gdb_path":
util.where_is_program(env.subst("$GDB"), env.subst("${ENV['PATH']}")),
where_is_program(env.subst("$GDB"), env.subst("${ENV['PATH']}")),
"prog_path":
env.subst("$PROG_PATH")
env.subst("$PROG_PATH"),
"flash_extra_images": [{
"offset": item[0],
"path": env.subst(item[1])
} for item in env.get("FLASH_EXTRA_IMAGES", [])],
"svd_path":
_get_svd_path(env),
"compiler_type":
env.GetCompilerType()
}
env_ = env.Clone()

File diff suppressed because it is too large Load Diff

View File

@@ -18,24 +18,27 @@ import atexit
import re
import sys
from os import environ, remove, walk
from os.path import basename, isdir, isfile, join, relpath, sep
from os.path import basename, isdir, isfile, join, realpath, relpath, sep
from tempfile import mkstemp
from SCons.Action import Action
from SCons.Script import ARGUMENTS
from SCons.Action import Action # pylint: disable=import-error
from SCons.Script import ARGUMENTS # pylint: disable=import-error
from platformio import util
from platformio import fs, util
from platformio.compat import get_file_contents, glob_escape
from platformio.managers.core import get_core_package_dir
from platformio.proc import exec_command
class InoToCPPConverter(object):
PROTOTYPE_RE = re.compile(r"""^(
PROTOTYPE_RE = re.compile(
r"""^(
(?:template\<.*\>\s*)? # template
([a-z_\d]+\*?\s+){1,2} # return type
([a-z_\d\&]+\*?\s+){1,2} # return type
([a-z_\d]+\s*) # name of prototype
\([a-z_,\.\*\&\[\]\s\d]*\) # arguments
)\s*\{ # must end with {
)\s*(\{|;) # must end with `{` or `;`
""", re.X | re.M | re.I)
DETECTMAIN_RE = re.compile(r"void\s+(setup|loop)\s*\(", re.M | re.I)
PROTOPTRS_TPLRE = r"\([^&\(]*&(%s)[^\)]*\)"
@@ -50,14 +53,14 @@ class InoToCPPConverter(object):
def convert(self, nodes):
contents = self.merge(nodes)
if not contents:
return
return None
return self.process(contents)
def merge(self, nodes):
assert nodes
lines = []
for node in nodes:
contents = node.get_text_contents()
contents = get_file_contents(node.get_path())
_lines = [
'# 1 "%s"' % node.get_path().replace("\\", "/"), contents
]
@@ -75,8 +78,7 @@ class InoToCPPConverter(object):
def process(self, contents):
out_file = self._main_ino + ".cpp"
assert self._gcc_preprocess(contents, out_file)
with open(out_file) as fp:
contents = fp.read()
contents = get_file_contents(out_file)
contents = self._join_multiline_strings(contents)
with open(out_file, "w") as fp:
fp.write(self.append_prototypes(contents))
@@ -89,8 +91,8 @@ class InoToCPPConverter(object):
self.env.Execute(
self.env.VerboseAction(
'$CXX -o "{0}" -x c++ -fpreprocessed -dD -E "{1}"'.format(
out_file,
tmp_path), "Converting " + basename(out_file[:-4])))
out_file, tmp_path),
"Converting " + basename(out_file[:-4])))
atexit.register(_delete_file, tmp_path)
return isfile(out_file)
@@ -157,32 +159,39 @@ class InoToCPPConverter(object):
return total
def append_prototypes(self, contents):
prototypes = self._parse_prototypes(contents)
prototypes = self._parse_prototypes(contents) or []
# skip already declared prototypes
declared = set(
m.group(1).strip() for m in prototypes if m.group(4) == ";")
prototypes = [
m for m in prototypes if m.group(1).strip() not in declared
]
if not prototypes:
return contents
prototype_names = set([m.group(3).strip() for m in prototypes])
prototype_names = set(m.group(3).strip() for m in prototypes)
split_pos = prototypes[0].start()
match_ptrs = re.search(self.PROTOPTRS_TPLRE %
("|".join(prototype_names)),
contents[:split_pos], re.M)
match_ptrs = re.search(
self.PROTOPTRS_TPLRE % ("|".join(prototype_names)),
contents[:split_pos], re.M)
if match_ptrs:
split_pos = contents.rfind("\n", 0, match_ptrs.start()) + 1
result = []
result.append(contents[:split_pos].strip())
result.append("%s;" % ";\n".join([m.group(1) for m in prototypes]))
result.append('#line %d "%s"' %
(self._get_total_lines(contents[:split_pos]),
self._main_ino.replace("\\", "/")))
result.append('#line %d "%s"' % (self._get_total_lines(
contents[:split_pos]), self._main_ino.replace("\\", "/")))
result.append(contents[split_pos:].strip())
return "\n".join(result)
def ConvertInoToCpp(env):
src_dir = util.glob_escape(env.subst("$PROJECTSRC_DIR"))
ino_nodes = (
env.Glob(join(src_dir, "*.ino")) + env.Glob(join(src_dir, "*.pde")))
src_dir = glob_escape(env.subst("$PROJECTSRC_DIR"))
ino_nodes = (env.Glob(join(src_dir, "*.ino")) +
env.Glob(join(src_dir, "*.pde")))
if not ino_nodes:
return
c = InoToCPPConverter(env)
@@ -199,11 +208,14 @@ def _delete_file(path):
pass
def GetCompilerType(env):
@util.memoized()
def _get_compiler_type(env):
if env.subst("$CC").endswith("-gcc"):
return "gcc"
try:
sysenv = environ.copy()
sysenv['PATH'] = str(env['ENV']['PATH'])
result = util.exec_command([env.subst("$CC"), "-v"], env=sysenv)
result = exec_command([env.subst("$CC"), "-v"], env=sysenv)
except OSError:
return None
if result['returncode'] != 0:
@@ -211,11 +223,15 @@ def GetCompilerType(env):
output = "".join([result['out'], result['err']]).lower()
if "clang" in output and "LLVM" in output:
return "clang"
elif "gcc" in output:
if "gcc" in output:
return "gcc"
return None
def GetCompilerType(env):
return _get_compiler_type(env)
def GetActualLDScript(env):
def _lookup_in_ldpath(script):
@@ -226,14 +242,25 @@ def GetActualLDScript(env):
return None
script = None
script_in_next = False
for f in env.get("LINKFLAGS", []):
if f.startswith("-Wl,-T"):
script = env.subst(f[6:].replace('"', "").strip())
if isfile(script):
return script
path = _lookup_in_ldpath(script)
if path:
return path
raw_script = None
if f == "-T":
script_in_next = True
continue
elif script_in_next:
script_in_next = False
raw_script = f
elif f.startswith("-Wl,-T"):
raw_script = f[6:]
else:
continue
script = env.subst(raw_script.replace('"', "").strip())
if isfile(script):
return script
path = _lookup_in_ldpath(script)
if path:
return path
if script:
sys.stderr.write(
@@ -258,43 +285,56 @@ def VerboseAction(_, act, actstr):
def PioClean(env, clean_dir):
if not isdir(clean_dir):
print "Build environment is clean"
print("Build environment is clean")
env.Exit(0)
clean_rel_path = relpath(clean_dir)
for root, _, files in walk(clean_dir):
for file_ in files:
remove(join(root, file_))
print "Removed %s" % relpath(join(root, file_))
print "Done cleaning"
util.rmtree_(clean_dir)
for f in files:
dst = join(root, f)
remove(dst)
print("Removed %s" %
(dst if clean_rel_path.startswith(".") else relpath(dst)))
print("Done cleaning")
fs.rmtree(clean_dir)
env.Exit(0)
def ProcessDebug(env):
if not env.subst("$PIODEBUGFLAGS"):
env.Replace(PIODEBUGFLAGS=["-Og", "-g3", "-ggdb"])
env.Append(
BUILD_FLAGS=env.get("PIODEBUGFLAGS", []),
BUILD_UNFLAGS=["-Os", "-O0", "-O1", "-O2", "-O3"])
env.Replace(PIODEBUGFLAGS=["-Og", "-g3", "-ggdb3"])
env.Append(BUILD_FLAGS=list(env['PIODEBUGFLAGS']) +
["-D__PLATFORMIO_BUILD_DEBUG__"])
unflags = ["-Os"]
for level in [0, 1, 2]:
for flag in ("O", "g", "ggdb"):
unflags.append("-%s%d" % (flag, level))
env.Append(BUILD_UNFLAGS=unflags)
def ProcessTest(env):
env.Append(
CPPDEFINES=["UNIT_TEST", "UNITY_INCLUDE_CONFIG_H"],
CPPPATH=[join("$BUILD_DIR", "UnityTestLib")])
unitylib = env.BuildLibrary(
join("$BUILD_DIR", "UnityTestLib"), get_core_package_dir("tool-unity"))
env.Append(CPPDEFINES=["UNIT_TEST", "UNITY_INCLUDE_CONFIG_H"],
CPPPATH=[join("$BUILD_DIR", "UnityTestLib")])
unitylib = env.BuildLibrary(join("$BUILD_DIR", "UnityTestLib"),
get_core_package_dir("tool-unity"))
env.Prepend(LIBS=[unitylib])
src_filter = None
if "PIOTEST" in env:
src_filter = "+<output_export.cpp>"
src_filter += " +<%s%s>" % (env['PIOTEST'], sep)
src_filter = ["+<*.cpp>", "+<*.c>"]
if "PIOTEST_RUNNING_NAME" in env:
src_filter.append("+<%s%s>" % (env['PIOTEST_RUNNING_NAME'], sep))
env.Replace(PIOTEST_SRC_FILTER=src_filter)
return env.CollectBuildFiles(
"$BUILDTEST_DIR",
"$PROJECTTEST_DIR",
src_filter=src_filter,
duplicate=False)
def GetExtraScripts(env, scope):
items = []
for item in env.GetProjectOption("extra_scripts", []):
if scope == "post" and ":" not in item:
items.append(item)
elif item.startswith("%s:" % scope):
items.append(item[len(scope) + 1:])
if not items:
return items
with fs.cd(env.subst("$PROJECT_DIR")):
return [realpath(item) for item in items]
def exists(_):
@@ -309,4 +349,5 @@ def generate(env):
env.AddMethod(PioClean)
env.AddMethod(ProcessDebug)
env.AddMethod(ProcessTest)
env.AddMethod(GetExtraScripts)
return env

View File

@@ -17,32 +17,35 @@ from __future__ import absolute_import
import sys
from os.path import isdir, isfile, join
from SCons.Script import COMMAND_LINE_TARGETS
from SCons.Script import ARGUMENTS # pylint: disable=import-error
from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error
from platformio import exception, util
from platformio import exception, fs, util
from platformio.compat import WINDOWS
from platformio.managers.platform import PlatformFactory
from platformio.project.config import ProjectOptions
# pylint: disable=too-many-branches, too-many-locals
@util.memoized
def initPioPlatform(name):
return PlatformFactory.newPlatform(name)
@util.memoized()
def PioPlatform(env):
variables = {}
for name in env['PIOVARIABLES']:
if name in env:
variables[name.lower()] = env[name]
p = initPioPlatform(env['PLATFORM_MANIFEST'])
variables = env.GetProjectOptions(as_dict=True)
if "framework" in variables:
# support PIO Core 3.0 dev/platforms
variables['pioframework'] = variables['framework']
p = PlatformFactory.newPlatform(env['PLATFORM_MANIFEST'])
p.configure_default_packages(variables, COMMAND_LINE_TARGETS)
return p
def BoardConfig(env, board=None):
p = initPioPlatform(env['PLATFORM_MANIFEST'])
p = env.PioPlatform()
try:
config = p.board_config(board if board else env['BOARD'])
except exception.UnknownBoard as e:
board = board or env.get("BOARD")
assert board, "BoardConfig: Board is not defined"
config = p.board_config(board)
except (AssertionError, exception.UnknownBoard) as e:
sys.stderr.write("Error: %s\n" % str(e))
env.Exit(1)
return config
@@ -57,19 +60,29 @@ def GetFrameworkScript(env, framework):
return script_path
def LoadPioPlatform(env, variables):
def LoadPioPlatform(env):
p = env.PioPlatform()
installed_packages = p.get_installed_packages()
# Add toolchains and uploaders to $PATH
# Ensure real platform name
env['PIOPLATFORM'] = p.name
# Add toolchains and uploaders to $PATH and $*_LIBRARY_PATH
systype = util.get_systype()
for name in installed_packages:
type_ = p.get_package_type(name)
if type_ not in ("toolchain", "uploader"):
if type_ not in ("toolchain", "uploader", "debugger"):
continue
path = p.get_package_dir(name)
if isdir(join(path, "bin")):
path = join(path, "bin")
env.PrependENVPath("PATH", path)
pkg_dir = p.get_package_dir(name)
env.PrependENVPath(
"PATH",
join(pkg_dir, "bin") if isdir(join(pkg_dir, "bin")) else pkg_dir)
if (not WINDOWS and isdir(join(pkg_dir, "lib"))
and type_ != "toolchain"):
env.PrependENVPath(
"DYLD_LIBRARY_PATH"
if "darwin" in systype else "LD_LIBRARY_PATH",
join(pkg_dir, "lib"))
# Platform specific LD Scripts
if isdir(join(p.get_dir(), "ldscripts")):
@@ -78,22 +91,121 @@ def LoadPioPlatform(env, variables):
if "BOARD" not in env:
return
# update board manifest with overridden data from INI config
board_config = env.BoardConfig()
for k in variables.keys():
if (k in env or
not any([k.startswith("BOARD_"),
k.startswith("UPLOAD_")])):
for option, value in env.GetProjectOptions():
if option.startswith("board_"):
board_config.update(option.lower()[6:], value)
# load default variables from board config
for option_meta in ProjectOptions.values():
if not option_meta.buildenvvar or option_meta.buildenvvar in env:
continue
_opt, _val = k.lower().split("_", 1)
if _opt == "board":
_opt = "build"
if _val in board_config.get(_opt):
env.Replace(**{k: board_config.get("%s.%s" % (_opt, _val))})
data_path = (option_meta.name[6:]
if option_meta.name.startswith("board_") else
option_meta.name.replace("_", "."))
try:
env[option_meta.buildenvvar] = board_config.get(data_path)
except KeyError:
pass
if "build.ldscript" in board_config:
env.Replace(LDSCRIPT_PATH=board_config.get("build.ldscript"))
def PrintConfiguration(env): # pylint: disable=too-many-statements
platform = env.PioPlatform()
board_config = env.BoardConfig() if "BOARD" in env else None
def _get_configuration_data():
return None if not board_config else [
"CONFIGURATION:",
"https://docs.platformio.org/page/boards/%s/%s.html" %
(platform.name, board_config.id)
]
def _get_plaform_data():
data = ["PLATFORM: %s %s" % (platform.title, platform.version)]
src_manifest_path = platform.pm.get_src_manifest_path(
platform.get_dir())
if src_manifest_path:
src_manifest = fs.load_json(src_manifest_path)
if "version" in src_manifest:
data.append("#" + src_manifest['version'])
if int(ARGUMENTS.get("PIOVERBOSE", 0)):
data.append("(%s)" % src_manifest['url'])
if board_config:
data.extend([">", board_config.get("name")])
return data
def _get_hardware_data():
data = ["HARDWARE:"]
mcu = env.subst("$BOARD_MCU")
f_cpu = env.subst("$BOARD_F_CPU")
if mcu:
data.append(mcu.upper())
if f_cpu:
f_cpu = int("".join([c for c in str(f_cpu) if c.isdigit()]))
data.append("%dMHz," % (f_cpu / 1000000))
if not board_config:
return data
ram = board_config.get("upload", {}).get("maximum_ram_size")
flash = board_config.get("upload", {}).get("maximum_size")
data.append("%s RAM, %s Flash" %
(fs.format_filesize(ram), fs.format_filesize(flash)))
return data
def _get_debug_data():
debug_tools = board_config.get(
"debug", {}).get("tools") if board_config else None
if not debug_tools:
return None
data = [
"DEBUG:", "Current",
"(%s)" % board_config.get_debug_tool_name(
env.GetProjectOption("debug_tool"))
]
onboard = []
external = []
for key, value in debug_tools.items():
if value.get("onboard"):
onboard.append(key)
else:
external.append(key)
if onboard:
data.extend(["On-board", "(%s)" % ", ".join(sorted(onboard))])
if external:
data.extend(["External", "(%s)" % ", ".join(sorted(external))])
return data
def _get_packages_data():
data = []
for name, options in platform.packages.items():
if options.get("optional"):
continue
pkg_dir = platform.get_package_dir(name)
if not pkg_dir:
continue
manifest = platform.pm.load_manifest(pkg_dir)
original_version = util.get_original_version(manifest['version'])
info = "%s %s" % (manifest['name'], manifest['version'])
extra = []
if original_version:
extra.append(original_version)
if "__src_url" in manifest and int(ARGUMENTS.get("PIOVERBOSE", 0)):
extra.append(manifest['__src_url'])
if extra:
info += " (%s)" % ", ".join(extra)
data.append(info)
return ["PACKAGES:", ", ".join(data)]
for data in (_get_configuration_data(), _get_plaform_data(),
_get_hardware_data(), _get_debug_data(),
_get_packages_data()):
if data and len(data) > 1:
print(" ".join(data))
def exists(_):
return True
@@ -103,4 +215,5 @@ def generate(env):
env.AddMethod(BoardConfig)
env.AddMethod(GetFrameworkScript)
env.AddMethod(LoadPioPlatform)
env.AddMethod(PrintConfiguration)
return env

View File

@@ -0,0 +1,49 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import absolute_import
from platformio.project.config import ProjectConfig, ProjectOptions
def GetProjectConfig(env):
return ProjectConfig.get_instance(env['PROJECT_CONFIG'])
def GetProjectOptions(env, as_dict=False):
return env.GetProjectConfig().items(env=env['PIOENV'], as_dict=as_dict)
def GetProjectOption(env, option, default=None):
return env.GetProjectConfig().get("env:" + env['PIOENV'], option, default)
def LoadProjectOptions(env):
for option, value in env.GetProjectOptions():
option_meta = ProjectOptions.get("env." + option)
if not option_meta or not option_meta.buildenvvar:
continue
env[option_meta.buildenvvar] = value
def exists(_):
return True
def generate(env):
env.AddMethod(GetProjectConfig)
env.AddMethod(GetProjectOptions)
env.AddMethod(GetProjectOption)
env.AddMethod(LoadProjectOptions)
return env

View File

@@ -14,18 +14,22 @@
from __future__ import absolute_import
import re
import sys
from fnmatch import fnmatch
from os import environ
from os.path import isfile, join
from platform import system
from shutil import copyfile
from time import sleep
from SCons.Node.Alias import Alias
from SCons.Script import ARGUMENTS # pylint: disable=import-error
from serial import Serial, SerialException
from platformio import util
from platformio import exception, fs, util
from platformio.compat import WINDOWS
from platformio.proc import exec_command
# pylint: disable=unused-argument
def FlushSerialBuffer(env, port):
@@ -41,23 +45,24 @@ def FlushSerialBuffer(env, port):
def TouchSerialPort(env, port, baudrate):
port = env.subst(port)
print "Forcing reset using %dbps open/close on port %s" % (baudrate, port)
print("Forcing reset using %dbps open/close on port %s" % (baudrate, port))
try:
s = Serial(port=port, baudrate=baudrate)
s.setDTR(False)
s.close()
except: # pylint: disable=W0702
except: # pylint: disable=bare-except
pass
sleep(0.4) # DO NOT REMOVE THAT (required by SAM-BA based boards)
def WaitForNewSerialPort(env, before):
print "Waiting for the new upload port..."
print("Waiting for the new upload port...")
prev_port = env.subst("$UPLOAD_PORT")
new_port = None
elapsed = 0
before = [p['port'] for p in before]
while elapsed < 5 and new_port is None:
now = [p['port'] for p in util.get_serialports()]
now = [p['port'] for p in util.get_serial_ports()]
for p in now:
if p not in before:
new_port = p
@@ -88,7 +93,7 @@ def WaitForNewSerialPort(env, before):
return new_port
def AutodetectUploadPort(*args, **kwargs): # pylint: disable=unused-argument
def AutodetectUploadPort(*args, **kwargs):
env = args[0]
def _get_pattern():
@@ -106,29 +111,35 @@ def AutodetectUploadPort(*args, **kwargs): # pylint: disable=unused-argument
def _look_for_mbed_disk():
msdlabels = ("mbed", "nucleo", "frdm", "microbit")
for item in util.get_logicaldisks():
if item['disk'].startswith(
"/net") or not _is_match_pattern(item['disk']):
for item in util.get_logical_devices():
if item['path'].startswith("/net") or not _is_match_pattern(
item['path']):
continue
mbed_pages = [
join(item['disk'], n) for n in ("mbed.htm", "mbed.html")
join(item['path'], n) for n in ("mbed.htm", "mbed.html")
]
if any([isfile(p) for p in mbed_pages]):
return item['disk']
if (item['name'] and
any([l in item['name'].lower() for l in msdlabels])):
return item['disk']
if any(isfile(p) for p in mbed_pages):
return item['path']
if item['name'] \
and any(l in item['name'].lower() for l in msdlabels):
return item['path']
return None
def _look_for_serial_port():
port = None
board_hwids = []
upload_protocol = env.subst("$UPLOAD_PROTOCOL")
if "BOARD" in env and "build.hwids" in env.BoardConfig():
board_hwids = env.BoardConfig().get("build.hwids")
for item in util.get_serialports(filter_hwid=True):
for item in util.get_serial_ports(filter_hwid=True):
if not _is_match_pattern(item['port']):
continue
port = item['port']
if upload_protocol.startswith("blackmagic"):
if WINDOWS and port.startswith("COM") and len(port) > 4:
port = "\\\\.\\%s" % port
if "GDB" in item['description']:
return port
for hwid in board_hwids:
hwid_str = ("%s:%s" % (hwid[0], hwid[1])).replace("0x", "")
if hwid_str in item['hwid']:
@@ -136,25 +147,22 @@ def AutodetectUploadPort(*args, **kwargs): # pylint: disable=unused-argument
return port
if "UPLOAD_PORT" in env and not _get_pattern():
print env.subst("Use manually specified: $UPLOAD_PORT")
print(env.subst("Use manually specified: $UPLOAD_PORT"))
return
if "mbed" in env.subst("$PIOFRAMEWORK"):
if (env.subst("$UPLOAD_PROTOCOL") == "mbed"
or ("mbed" in env.subst("$PIOFRAMEWORK")
and not env.subst("$UPLOAD_PROTOCOL"))):
env.Replace(UPLOAD_PORT=_look_for_mbed_disk())
else:
if (system() == "Linux" and not any([
isfile("/etc/udev/rules.d/99-platformio-udev.rules"),
isfile("/lib/udev/rules.d/99-platformio-udev.rules")
])):
sys.stderr.write(
"\nWarning! Please install `99-platformio-udev.rules` and "
"check that your board's PID and VID are listed in the rules."
"\n https://raw.githubusercontent.com/platformio/platformio"
"/develop/scripts/99-platformio-udev.rules\n")
try:
fs.ensure_udev_rules()
except exception.InvalidUdevRules as e:
sys.stderr.write("\n%s\n\n" % e)
env.Replace(UPLOAD_PORT=_look_for_serial_port())
if env.subst("$UPLOAD_PORT"):
print env.subst("Auto-detected: $UPLOAD_PORT")
print(env.subst("Auto-detected: $UPLOAD_PORT"))
else:
sys.stderr.write(
"Error: Please specify `upload_port` for environment or use "
@@ -164,7 +172,7 @@ def AutodetectUploadPort(*args, **kwargs): # pylint: disable=unused-argument
env.Exit(1)
def UploadToDisk(_, target, source, env): # pylint: disable=W0613,W0621
def UploadToDisk(_, target, source, env):
assert "UPLOAD_PORT" in env
progname = env.subst("$PROGNAME")
for ext in ("bin", "hex"):
@@ -173,39 +181,105 @@ def UploadToDisk(_, target, source, env): # pylint: disable=W0613,W0621
continue
copyfile(fpath,
join(env.subst("$UPLOAD_PORT"), "%s.%s" % (progname, ext)))
print "Firmware has been successfully uploaded.\n"\
"(Some boards may require manual hard reset)"
print("Firmware has been successfully uploaded.\n"
"(Some boards may require manual hard reset)")
def CheckUploadSize(_, target, source, env): # pylint: disable=W0613,W0621
if "BOARD" not in env:
return
max_size = int(env.BoardConfig().get("upload.maximum_size", 0))
if max_size == 0 or "SIZETOOL" not in env:
return
sysenv = environ.copy()
sysenv['PATH'] = str(env['ENV']['PATH'])
cmd = [
env.subst("$SIZETOOL"), "-B",
str(source[0] if isinstance(target[0], Alias) else target[0])
def CheckUploadSize(_, target, source, env):
check_conditions = [
env.get("BOARD"),
env.get("SIZETOOL") or env.get("SIZECHECKCMD")
]
result = util.exec_command(cmd, env=sysenv)
if result['returncode'] != 0:
if not all(check_conditions):
return
program_max_size = int(env.BoardConfig().get("upload.maximum_size", 0))
data_max_size = int(env.BoardConfig().get("upload.maximum_ram_size", 0))
if program_max_size == 0:
return
print result['out'].strip()
line = result['out'].strip().splitlines()[1]
values = [v.strip() for v in line.split("\t")]
used_size = int(values[0]) + int(values[1])
def _configure_defaults():
env.Replace(SIZECHECKCMD="$SIZETOOL -B -d $SOURCES",
SIZEPROGREGEXP=r"^(\d+)\s+(\d+)\s+\d+\s",
SIZEDATAREGEXP=r"^\d+\s+(\d+)\s+(\d+)\s+\d+")
if used_size > max_size:
def _get_size_output():
cmd = env.get("SIZECHECKCMD")
if not cmd:
return None
if not isinstance(cmd, list):
cmd = cmd.split()
cmd = [arg.replace("$SOURCES", str(source[0])) for arg in cmd if arg]
sysenv = environ.copy()
sysenv['PATH'] = str(env['ENV']['PATH'])
result = exec_command(env.subst(cmd), env=sysenv)
if result['returncode'] != 0:
return None
return result['out'].strip()
def _calculate_size(output, pattern):
if not output or not pattern:
return -1
size = 0
regexp = re.compile(pattern)
for line in output.split("\n"):
line = line.strip()
if not line:
continue
match = regexp.search(line)
if not match:
continue
size += sum(int(value) for value in match.groups())
return size
def _format_availale_bytes(value, total):
percent_raw = float(value) / float(total)
blocks_per_progress = 10
used_blocks = int(round(blocks_per_progress * percent_raw))
if used_blocks > blocks_per_progress:
used_blocks = blocks_per_progress
return "[{:{}}] {: 6.1%} (used {:d} bytes from {:d} bytes)".format(
"=" * used_blocks, blocks_per_progress, percent_raw, value, total)
if not env.get("SIZECHECKCMD") and not env.get("SIZEPROGREGEXP"):
_configure_defaults()
output = _get_size_output()
program_size = _calculate_size(output, env.get("SIZEPROGREGEXP"))
data_size = _calculate_size(output, env.get("SIZEDATAREGEXP"))
print("Memory Usage -> http://bit.ly/pio-memory-usage")
if data_max_size and data_size > -1:
print("DATA: %s" % _format_availale_bytes(data_size, data_max_size))
if program_size > -1:
print("PROGRAM: %s" %
_format_availale_bytes(program_size, program_max_size))
if int(ARGUMENTS.get("PIOVERBOSE", 0)):
print(output)
# raise error
# if data_max_size and data_size > data_max_size:
# sys.stderr.write(
# "Error: The data size (%d bytes) is greater "
# "than maximum allowed (%s bytes)\n" % (data_size, data_max_size))
# env.Exit(1)
if program_size > program_max_size:
sys.stderr.write("Error: The program size (%d bytes) is greater "
"than maximum allowed (%s bytes)\n" % (used_size,
max_size))
"than maximum allowed (%s bytes)\n" %
(program_size, program_max_size))
env.Exit(1)
def PrintUploadInfo(env):
configured = env.subst("$UPLOAD_PROTOCOL")
available = [configured] if configured else []
if "BOARD" in env:
available.extend(env.BoardConfig().get("upload",
{}).get("protocols", []))
if available:
print("AVAILABLE: %s" % ", ".join(sorted(set(available))))
if configured:
print("CURRENT: upload_protocol = %s" % configured)
def exists(_):
return True
@@ -217,4 +291,5 @@ def generate(env):
env.AddMethod(AutodetectUploadPort)
env.AddMethod(UploadToDisk)
env.AddMethod(CheckUploadSize)
env.AddMethod(PrintUploadInfo)
return env

View File

@@ -12,10 +12,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import absolute_import
from hashlib import md5
from os import makedirs
from os.path import isdir, isfile, join
from platform import system
from platformio.compat import WINDOWS, hashlib_encode_data
# Windows CLI has limit with command length to 8192
# Leave 2000 chars for flags and other options
@@ -58,7 +61,8 @@ def _file_long_data(env, data):
build_dir = env.subst("$BUILD_DIR")
if not isdir(build_dir):
makedirs(build_dir)
tmp_file = join(build_dir, "longcmd-%s" % md5(data).hexdigest())
tmp_file = join(build_dir,
"longcmd-%s" % md5(hashlib_encode_data(data)).hexdigest())
if isfile(tmp_file):
return tmp_file
with open(tmp_file, "w") as fp:
@@ -71,8 +75,8 @@ def exists(_):
def generate(env):
if system() != "Windows":
return
if not WINDOWS:
return None
env.Replace(_long_sources_hook=long_sources_hook)
env.Replace(_long_incflags_hook=long_incflags_hook)

View File

@@ -14,199 +14,225 @@
from __future__ import absolute_import
import re
import os
import sys
from glob import glob
from os import sep, walk
from os.path import basename, dirname, isdir, join, realpath
from SCons.Action import Action
from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild,
DefaultEnvironment, SConscript)
from SCons.Util import case_sensitive_suffixes, is_Sequence
from SCons import Builder, Util # pylint: disable=import-error
from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error
from SCons.Script import AlwaysBuild # pylint: disable=import-error
from SCons.Script import DefaultEnvironment # pylint: disable=import-error
from SCons.Script import Export # pylint: disable=import-error
from SCons.Script import SConscript # pylint: disable=import-error
from platformio.util import glob_escape, pioversion_to_intstr
from platformio import fs
from platformio.compat import string_types
from platformio.util import pioversion_to_intstr
SRC_BUILD_EXT = ["c", "cc", "cpp", "S", "spp", "SPP", "sx", "s", "asm", "ASM"]
SRC_HEADER_EXT = ["h", "hpp"]
SRC_FILTER_DEFAULT = ["+<*>", "-<.git%s>" % sep, "-<svn%s>" % sep]
SRC_C_EXT = ["c", "cc", "cpp"]
SRC_BUILD_EXT = SRC_C_EXT + ["S", "spp", "SPP", "sx", "s", "asm", "ASM"]
SRC_FILTER_DEFAULT = ["+<*>", "-<.git%s>" % os.sep, "-<.svn%s>" % os.sep]
def BuildProgram(env):
def scons_patched_match_splitext(path, suffixes=None):
"""Patch SCons Builder, append $OBJSUFFIX to the end of each target"""
tokens = Util.splitext(path)
if suffixes and tokens[1] and tokens[1] in suffixes:
return (path, tokens[1])
return tokens
def _append_pio_macros():
env.AppendUnique(CPPDEFINES=[
("PLATFORMIO",
int("{0:02d}{1:02d}{2:02d}".format(*pioversion_to_intstr())))
])
_append_pio_macros()
def _build_project_deps(env):
project_lib_builder = env.ConfigureProjectLibBuilder()
# fix ASM handling under non-casitive OS
if not case_sensitive_suffixes(".s", ".S"):
env.Replace(AS="$CC", ASCOM="$ASPPCOM")
# prepend project libs to the beginning of list
env.Prepend(LIBS=project_lib_builder.build())
# prepend extra linker related options from libs
env.PrependUnique(
**{
key: project_lib_builder.env.get(key)
for key in ("LIBS", "LIBPATH", "LINKFLAGS")
if project_lib_builder.env.get(key)
})
if "__debug" in COMMAND_LINE_TARGETS:
env.ProcessDebug()
projenv = env.Clone()
# process extra flags from board
if "BOARD" in env and "build.extra_flags" in env.BoardConfig():
env.ProcessFlags(env.BoardConfig().get("build.extra_flags"))
# remove base flags
env.ProcessUnFlags(env.get("BUILD_UNFLAGS"))
# apply user flags
env.ProcessFlags(env.get("BUILD_FLAGS"))
# CPPPATH from dependencies
projenv.PrependUnique(CPPPATH=project_lib_builder.env.get("CPPPATH"))
# extra build flags from `platformio.ini`
projenv.ProcessFlags(env.get("SRC_BUILD_FLAGS"))
env.BuildFrameworks(env.get("PIOFRAMEWORK"))
is_test = "__test" in COMMAND_LINE_TARGETS
if is_test:
projenv.BuildSources("$BUILDTEST_DIR", "$PROJECTTEST_DIR",
"$PIOTEST_SRC_FILTER")
if not is_test or env.GetProjectOption("test_build_project_src", False):
projenv.BuildSources("$BUILDSRC_DIR", "$PROJECTSRC_DIR",
env.get("SRC_FILTER"))
# restore PIO macros if it was deleted by framework
_append_pio_macros()
# build dependent libs
deplibs = env.BuildDependentLibraries("$PROJECTSRC_DIR")
# append specified LD_SCRIPT
if ("LDSCRIPT_PATH" in env and
not any(["-Wl,-T" in f for f in env['LINKFLAGS']])):
env.Append(LINKFLAGS=['-Wl,-T"$LDSCRIPT_PATH"'])
# enable "cyclic reference" for linker
if env.get("LIBS", deplibs) and env.GetCompilerType() == "gcc":
env.Prepend(_LIBFLAGS="-Wl,--start-group ")
env.Append(_LIBFLAGS=" -Wl,--end-group")
# Handle SRC_BUILD_FLAGS
env.ProcessFlags(env.get("SRC_BUILD_FLAGS"))
env.Append(
CPPPATH=["$PROJECTSRC_DIR"],
LIBS=deplibs,
LIBPATH=["$BUILD_DIR"],
PIOBUILDFILES=env.CollectBuildFiles(
"$BUILDSRC_DIR",
"$PROJECTSRC_DIR",
src_filter=env.get("SRC_FILTER"),
duplicate=False))
if "__test" in COMMAND_LINE_TARGETS:
env.Append(PIOBUILDFILES=env.ProcessTest())
if not env['PIOBUILDFILES'] and not COMMAND_LINE_TARGETS:
if not env.get("PIOBUILDFILES") and not COMMAND_LINE_TARGETS:
sys.stderr.write(
"Error: Nothing to build. Please put your source code files "
"to '%s' folder\n" % env.subst("$PROJECTSRC_DIR"))
env.Exit(1)
program = env.Program(
join("$BUILD_DIR", env.subst("$PROGNAME")), env['PIOBUILDFILES'])
Export("projenv")
checksize_action = Action(env.CheckUploadSize, "Checking program size")
AlwaysBuild(env.Alias("checkprogsize", program, checksize_action))
if set(["upload", "program"]) & set(COMMAND_LINE_TARGETS):
env.AddPostAction(program, checksize_action)
def BuildProgram(env):
def _append_pio_macros():
env.AppendUnique(CPPDEFINES=[(
"PLATFORMIO",
int("{0:02d}{1:02d}{2:02d}".format(*pioversion_to_intstr())))])
_append_pio_macros()
env.PrintConfiguration()
# fix ASM handling under non case-sensitive OS
if not Util.case_sensitive_suffixes(".s", ".S"):
env.Replace(AS="$CC", ASCOM="$ASPPCOM")
if ("debug" in COMMAND_LINE_TARGETS
or env.GetProjectOption("build_type") == "debug"):
env.ProcessDebug()
# process extra flags from board
if "BOARD" in env and "build.extra_flags" in env.BoardConfig():
env.ProcessFlags(env.BoardConfig().get("build.extra_flags"))
# apply user flags
env.ProcessFlags(env.get("BUILD_FLAGS"))
# process framework scripts
env.BuildFrameworks(env.get("PIOFRAMEWORK"))
# restore PIO macros if it was deleted by framework
_append_pio_macros()
# remove specified flags
env.ProcessUnFlags(env.get("BUILD_UNFLAGS"))
if "__test" in COMMAND_LINE_TARGETS:
env.ProcessTest()
# build project with dependencies
_build_project_deps(env)
# append into the beginning a main LD script
if (env.get("LDSCRIPT_PATH")
and not any("-Wl,-T" in f for f in env['LINKFLAGS'])):
env.Prepend(LINKFLAGS=["-T", "$LDSCRIPT_PATH"])
# enable "cyclic reference" for linker
if env.get("LIBS") and env.GetCompilerType() == "gcc":
env.Prepend(_LIBFLAGS="-Wl,--start-group ")
env.Append(_LIBFLAGS=" -Wl,--end-group")
program = env.Program(join("$BUILD_DIR", env.subst("$PROGNAME")),
env['PIOBUILDFILES'])
env.Replace(PIOMAINPROG=program)
AlwaysBuild(
env.Alias(
"checkprogsize", program,
env.VerboseAction(env.CheckUploadSize,
"Checking size $PIOMAINPROG")))
return program
def ParseFlagsExtended(env, flags): # pylint: disable=too-many-branches
if not isinstance(flags, list):
flags = [flags]
result = {}
for raw in flags:
for key, value in env.ParseFlags(str(raw)).items():
if key not in result:
result[key] = []
result[key].extend(value)
cppdefines = []
for item in result['CPPDEFINES']:
if not Util.is_Sequence(item):
cppdefines.append(item)
continue
name, value = item[:2]
if '\"' in value:
value = value.replace('\"', '\\\"')
elif value.isdigit():
value = int(value)
elif value.replace(".", "", 1).isdigit():
value = float(value)
cppdefines.append((name, value))
result['CPPDEFINES'] = cppdefines
# fix relative CPPPATH & LIBPATH
for k in ("CPPPATH", "LIBPATH"):
for i, p in enumerate(result.get(k, [])):
if isdir(p):
result[k][i] = realpath(p)
# fix relative path for "-include"
for i, f in enumerate(result.get("CCFLAGS", [])):
if isinstance(f, tuple) and f[0] == "-include":
result['CCFLAGS'][i] = (f[0], env.File(realpath(f[1].get_path())))
return result
def ProcessFlags(env, flags): # pylint: disable=too-many-branches
if not flags:
return
if isinstance(flags, list):
flags = " ".join(flags)
parsed_flags = env.ParseFlags(str(flags))
for flag in parsed_flags.pop("CPPDEFINES"):
if not is_Sequence(flag):
env.Append(CPPDEFINES=flag)
continue
_key, _value = flag[:2]
if '\"' in _value:
_value = _value.replace('\"', '\\\"')
elif _value.isdigit():
_value = int(_value)
elif _value.replace(".", "", 1).isdigit():
_value = float(_value)
env.Append(CPPDEFINES=(_key, _value))
env.Append(**parsed_flags)
# fix relative CPPPATH & LIBPATH
for k in ("CPPPATH", "LIBPATH"):
for i, p in enumerate(env.get(k, [])):
if isdir(p):
env[k][i] = realpath(p)
# fix relative path for "-include"
for i, f in enumerate(env.get("CCFLAGS", [])):
if isinstance(f, tuple) and f[0] == "-include":
env['CCFLAGS'][i] = (f[0], env.File(realpath(f[1].get_path())))
env.Append(**env.ParseFlagsExtended(flags))
# Cancel any previous definition of name, either built in or
# provided with a -D option // Issue #191
# provided with a -U option // Issue #191
undefines = [
u for u in env.get("CCFLAGS", [])
if isinstance(u, basestring) and u.startswith("-U")
if isinstance(u, string_types) and u.startswith("-U")
]
if undefines:
for undef in undefines:
env['CCFLAGS'].remove(undef)
if undef[2:] in env['CPPDEFINES']:
env['CPPDEFINES'].remove(undef[2:])
env.Append(_CPPDEFFLAGS=" %s" % " ".join(undefines))
def ProcessUnFlags(env, flags):
if not flags:
return
if isinstance(flags, list):
flags = " ".join(flags)
parsed_flags = env.ParseFlags(str(flags))
parsed = env.ParseFlagsExtended(flags)
# get all flags and copy them to each "*FLAGS" variable
all_flags = []
for items in parsed_flags.values():
all_flags.extend(items)
all_flags = set(all_flags)
for key, unflags in parsed.items():
if key.endswith("FLAGS"):
all_flags.extend(unflags)
for key, unflags in parsed.items():
if key.endswith("FLAGS"):
parsed[key].extend(all_flags)
for key in parsed_flags:
cur_flags = set(env.Flatten(env.get(key, [])))
for item in cur_flags & all_flags:
while item in env[key]:
env[key].remove(item)
def IsFileWithExt(env, file_, ext): # pylint: disable=W0613
if basename(file_).startswith("."):
return False
for e in ext:
if file_.endswith(".%s" % e):
return True
return False
for key, unflags in parsed.items():
for unflag in unflags:
for current in env.get(key, []):
conditions = [
unflag == current,
isinstance(current, (tuple, list))
and unflag[0] == current[0]
]
if any(conditions):
env[key].remove(current)
def MatchSourceFiles(env, src_dir, src_filter=None):
SRC_FILTER_PATTERNS_RE = re.compile(r"(\+|\-)<([^>]+)>")
def _append_build_item(items, item, src_dir):
if env.IsFileWithExt(item, SRC_BUILD_EXT + SRC_HEADER_EXT):
items.add(item.replace(src_dir + sep, ""))
src_dir = env.subst(src_dir)
src_filter = env.subst(src_filter) if src_filter else None
src_filter = src_filter or SRC_FILTER_DEFAULT
if isinstance(src_filter, (list, tuple)):
src_filter = " ".join(src_filter)
matches = set()
# correct fs directory separator
src_filter = src_filter.replace("/", sep).replace("\\", sep)
for (action, pattern) in SRC_FILTER_PATTERNS_RE.findall(src_filter):
items = set()
for item in glob(join(glob_escape(src_dir), pattern)):
if isdir(item):
for root, _, files in walk(item, followlinks=True):
for f in files:
_append_build_item(items, join(root, f), src_dir)
else:
_append_build_item(items, item, src_dir)
if action == "+":
matches |= items
else:
matches -= items
return sorted(list(matches))
return fs.match_src_files(env.subst(src_dir), src_filter,
SRC_BUILD_EXT + SRC_HEADER_EXT)
def CollectBuildFiles(env,
@@ -218,7 +244,7 @@ def CollectBuildFiles(env,
variants = []
src_dir = env.subst(src_dir)
if src_dir.endswith(sep):
if src_dir.endswith(os.sep):
src_dir = src_dir[:-1]
for item in env.MatchSourceFiles(src_dir, src_filter):
@@ -230,7 +256,7 @@ def CollectBuildFiles(env,
variants.append(_var_dir)
env.VariantDir(_var_dir, _src_dir, duplicate)
if env.IsFileWithExt(item, SRC_BUILD_EXT):
if fs.path_endswith_ext(item, SRC_BUILD_EXT):
sources.append(env.File(join(_var_dir, basename(item))))
return sources
@@ -255,11 +281,14 @@ def BuildFrameworks(env, frameworks):
env.Exit(1)
for f in frameworks:
if f in ("arduino", "energia"):
env.ConvertInoToCpp()
if f == "arduino":
# Arduino IDE appends .o the end of filename
Builder.match_splitext = scons_patched_match_splitext
if "nobuild" not in COMMAND_LINE_TARGETS:
env.ConvertInoToCpp()
if f in board_frameworks:
SConscript(env.GetFrameworkScript(f))
SConscript(env.GetFrameworkScript(f), exports="env")
else:
sys.stderr.write(
"Error: This board doesn't support %s framework!\n" % f)
@@ -267,15 +296,16 @@ def BuildFrameworks(env, frameworks):
def BuildLibrary(env, variant_dir, src_dir, src_filter=None):
lib = env.Clone()
return lib.StaticLibrary(
lib.subst(variant_dir),
lib.CollectBuildFiles(variant_dir, src_dir, src_filter=src_filter))
env.ProcessUnFlags(env.get("BUILD_UNFLAGS"))
return env.StaticLibrary(
env.subst(variant_dir),
env.CollectBuildFiles(variant_dir, src_dir, src_filter))
def BuildSources(env, variant_dir, src_dir, src_filter=None):
DefaultEnvironment().Append(PIOBUILDFILES=env.Clone().CollectBuildFiles(
variant_dir, src_dir, src_filter=src_filter))
nodes = env.CollectBuildFiles(variant_dir, src_dir, src_filter)
DefaultEnvironment().Append(
PIOBUILDFILES=[env.Object(node) for node in nodes])
def exists(_):
@@ -284,9 +314,9 @@ def exists(_):
def generate(env):
env.AddMethod(BuildProgram)
env.AddMethod(ParseFlagsExtended)
env.AddMethod(ProcessFlags)
env.AddMethod(ProcessUnFlags)
env.AddMethod(IsFileWithExt)
env.AddMethod(MatchSourceFiles)
env.AddMethod(CollectBuildFiles)
env.AddMethod(BuildFrameworks)

View File

@@ -11,3 +11,62 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from os.path import dirname, isfile, join
import click
class PlatformioCLI(click.MultiCommand):
leftover_args = []
@staticmethod
def in_silence():
args = PlatformioCLI.leftover_args
return args and any([
args[0] == "debug" and "--interpreter" in " ".join(args),
args[0] == "upgrade", "--json-output" in args, "--version" in args
])
def invoke(self, ctx):
PlatformioCLI.leftover_args = ctx.args
if hasattr(ctx, "protected_args"):
PlatformioCLI.leftover_args = ctx.protected_args + ctx.args
return super(PlatformioCLI, self).invoke(ctx)
def list_commands(self, ctx):
cmds = []
cmds_dir = dirname(__file__)
for name in os.listdir(cmds_dir):
if name.startswith("__init__"):
continue
if isfile(join(cmds_dir, name, "command.py")):
cmds.append(name)
elif name.endswith(".py"):
cmds.append(name[:-3])
cmds.sort()
return cmds
def get_command(self, ctx, cmd_name):
mod = None
try:
mod = __import__("platformio.commands." + cmd_name, None, None,
["cli"])
except ImportError:
try:
return self._handle_obsolate_command(cmd_name)
except AttributeError:
raise click.UsageError('No such command "%s"' % cmd_name, ctx)
return mod.cli
@staticmethod
def _handle_obsolate_command(name):
if name == "platforms":
from platformio.commands import platform
return platform.cli
if name == "serialports":
from platformio.commands import device
return device.cli
raise AttributeError()

View File

@@ -15,8 +15,10 @@
import json
import click
from tabulate import tabulate
from platformio.exception import APIRequestError, InternetIsOffline
from platformio import fs
from platformio.compat import dump_json_to_unicode
from platformio.managers.platform import PlatformManager
@@ -41,69 +43,31 @@ def cli(query, installed, json_output): # pylint: disable=R0912
click.echo("")
click.echo("Platform: ", nl=False)
click.secho(platform, bold=True)
click.echo("-" * terminal_width)
click.echo("=" * terminal_width)
print_boards(boards)
return True
def print_boards(boards):
terminal_width, _ = click.get_terminal_size()
BOARDLIST_TPL = ("{type:<30} {mcu:<14} {frequency:<8} "
" {flash:<7} {ram:<6} {name}")
click.echo(
BOARDLIST_TPL.format(
type=click.style("ID", fg="cyan"),
mcu="MCU",
frequency="Frequency",
flash="Flash",
ram="RAM",
name="Name"))
click.echo("-" * terminal_width)
for board in boards:
ram_size = board['ram']
if ram_size >= 1024:
if ram_size % 1024:
ram_size = "%.1fkB" % (ram_size / 1024.0)
else:
ram_size = "%dkB" % (ram_size / 1024)
else:
ram_size = "%dB" % ram_size
click.echo(
BOARDLIST_TPL.format(
type=click.style(board['id'], fg="cyan"),
mcu=board['mcu'],
frequency="%dMhz" % (board['fcpu'] / 1000000),
flash="%dkB" % (board['rom'] / 1024),
ram=ram_size,
name=board['name']))
tabulate([(click.style(b['id'], fg="cyan"), b['mcu'], "%dMHz" %
(b['fcpu'] / 1000000), fs.format_filesize(
b['rom']), fs.format_filesize(b['ram']), b['name'])
for b in boards],
headers=["ID", "MCU", "Frequency", "Flash", "RAM", "Name"]))
def _get_boards(installed=False):
boards = PlatformManager().get_installed_boards()
if not installed:
know_boards = ["%s:%s" % (b['platform'], b['id']) for b in boards]
try:
for board in PlatformManager().get_registered_boards():
key = "%s:%s" % (board['platform'], board['id'])
if key not in know_boards:
boards.append(board)
except InternetIsOffline:
pass
return sorted(boards, key=lambda b: b['name'])
pm = PlatformManager()
return pm.get_installed_boards() if installed else pm.get_all_boards()
def _print_boards_json(query, installed=False):
result = []
try:
boards = _get_boards(installed)
except APIRequestError:
if not installed:
boards = _get_boards(True)
for board in boards:
for board in _get_boards(installed):
if query:
search_data = "%s %s" % (board['id'], json.dumps(board).lower())
if query.lower() not in search_data.lower():
continue
result.append(board)
click.echo(json.dumps(result))
click.echo(dump_json_to_unicode(result))

View File

@@ -20,11 +20,13 @@ from tempfile import mkdtemp
import click
from platformio import app, util
from platformio import app, fs
from platformio.commands.init import cli as cmd_init
from platformio.commands.init import validate_boards
from platformio.commands.run import cli as cmd_run
from platformio.compat import glob_escape
from platformio.exception import CIBuildEnvsEmpty
from platformio.project.config import ProjectConfig
def validate_path(ctx, param, value): # pylint: disable=unused-argument
@@ -46,34 +48,35 @@ def validate_path(ctx, param, value): # pylint: disable=unused-argument
@click.command("ci", short_help="Continuous Integration")
@click.argument("src", nargs=-1, callback=validate_path)
@click.option(
"-l", "--lib", multiple=True, callback=validate_path, metavar="DIRECTORY")
@click.option("-l",
"--lib",
multiple=True,
callback=validate_path,
metavar="DIRECTORY")
@click.option("--exclude", multiple=True)
@click.option(
"-b", "--board", multiple=True, metavar="ID", callback=validate_boards)
@click.option(
"--build-dir",
default=mkdtemp,
type=click.Path(
exists=True,
file_okay=False,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option("-b",
"--board",
multiple=True,
metavar="ID",
callback=validate_boards)
@click.option("--build-dir",
default=mkdtemp,
type=click.Path(file_okay=False,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option("--keep-build-dir", is_flag=True)
@click.option(
"-C",
"--project-conf",
type=click.Path(
exists=True,
file_okay=True,
dir_okay=False,
readable=True,
resolve_path=True))
@click.option("-c",
"--project-conf",
type=click.Path(exists=True,
file_okay=True,
dir_okay=False,
readable=True,
resolve_path=True))
@click.option("-O", "--project-option", multiple=True)
@click.option("-v", "--verbose", is_flag=True)
@click.pass_context
def cli( # pylint: disable=too-many-arguments
def cli( # pylint: disable=too-many-arguments, too-many-branches
ctx, src, lib, exclude, board, build_dir, keep_build_dir, project_conf,
project_option, verbose):
@@ -84,9 +87,13 @@ def cli( # pylint: disable=too-many-arguments
try:
app.set_session_var("force_option", True)
_clean_dir(build_dir)
for dir_name, patterns in dict(lib=lib, src=src).iteritems():
if not keep_build_dir and isdir(build_dir):
fs.rmtree(build_dir)
if not isdir(build_dir):
makedirs(build_dir)
for dir_name, patterns in dict(lib=lib, src=src).items():
if not patterns:
continue
contents = []
@@ -103,22 +110,16 @@ def cli( # pylint: disable=too-many-arguments
_exclude_contents(build_dir, exclude)
# initialise project
ctx.invoke(
cmd_init,
project_dir=build_dir,
board=board,
project_option=project_option)
ctx.invoke(cmd_init,
project_dir=build_dir,
board=board,
project_option=project_option)
# process project
ctx.invoke(cmd_run, project_dir=build_dir, verbose=verbose)
finally:
if not keep_build_dir:
util.rmtree_(build_dir)
def _clean_dir(dirpath):
util.rmtree_(dirpath)
makedirs(dirpath)
fs.rmtree(build_dir)
def _copy_contents(dst_dir, contents):
@@ -135,7 +136,8 @@ def _copy_contents(dst_dir, contents):
if dst_dir_name == "src" and len(items['dirs']) == 1:
copytree(list(items['dirs']).pop(), dst_dir, symlinks=True)
else:
makedirs(dst_dir)
if not isdir(dst_dir):
makedirs(dst_dir)
for d in items['dirs']:
copytree(d, join(dst_dir, basename(d)), symlinks=True)
@@ -146,24 +148,26 @@ def _copy_contents(dst_dir, contents):
dst_dir = join(dst_dir, mkdtemp(dir=dst_dir))
for f in items['files']:
copyfile(f, join(dst_dir, basename(f)))
dst_file = join(dst_dir, basename(f))
if f == dst_file:
continue
copyfile(f, dst_file)
def _exclude_contents(dst_dir, patterns):
contents = []
for p in patterns:
contents += glob(join(util.glob_escape(dst_dir), p))
contents += glob(join(glob_escape(dst_dir), p))
for path in contents:
path = abspath(path)
if isdir(path):
util.rmtree_(path)
fs.rmtree(path)
elif isfile(path):
remove(path)
def _copy_project_conf(build_dir, project_conf):
config = util.load_project_config(project_conf)
config = ProjectConfig(project_conf, parse_extra=False)
if config.has_section("platformio"):
config.remove_section("platformio")
with open(join(build_dir, "platformio.ini"), "w") as fp:
config.write(fp)
config.save(join(build_dir, "platformio.ini"))

View File

@@ -1,42 +0,0 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
from os import getcwd
import click
from platformio.managers.core import pioplus_call
@click.command(
"debug",
context_settings=dict(ignore_unknown_options=True),
short_help="PIO Unified Debugger")
@click.option(
"-d",
"--project-dir",
default=getcwd,
type=click.Path(
exists=True,
file_okay=False,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option("--environment", "-e", metavar="<environment>")
@click.option("--verbose", "-v", is_flag=True)
@click.option("--interface", type=click.Choice(["gdb"]))
@click.argument("__unprocessed", nargs=-1, type=click.UNPROCESSED)
def cli(*args, **kwargs): # pylint: disable=unused-argument
pioplus_call(sys.argv[1:])

View File

@@ -0,0 +1,15 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from platformio.commands.debug.command import cli

View File

@@ -0,0 +1,292 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import os
import re
import signal
import time
from hashlib import sha1
from os.path import abspath, basename, dirname, isdir, join, splitext
from tempfile import mkdtemp
from twisted.internet import protocol # pylint: disable=import-error
from twisted.internet import reactor # pylint: disable=import-error
from twisted.internet import stdio # pylint: disable=import-error
from twisted.internet import task # pylint: disable=import-error
from platformio import app, exception, fs, proc, util
from platformio.commands.debug import helpers, initcfgs
from platformio.commands.debug.process import BaseProcess
from platformio.commands.debug.server import DebugServer
from platformio.compat import hashlib_encode_data
from platformio.project.helpers import get_project_cache_dir
from platformio.telemetry import MeasurementProtocol
LOG_FILE = None
class GDBClient(BaseProcess): # pylint: disable=too-many-instance-attributes
PIO_SRC_NAME = ".pioinit"
INIT_COMPLETED_BANNER = "PlatformIO: Initialization completed"
def __init__(self, project_dir, args, debug_options, env_options):
self.project_dir = project_dir
self.args = list(args)
self.debug_options = debug_options
self.env_options = env_options
self._debug_server = DebugServer(debug_options, env_options)
self._session_id = None
if not isdir(get_project_cache_dir()):
os.makedirs(get_project_cache_dir())
self._gdbsrc_dir = mkdtemp(dir=get_project_cache_dir(),
prefix=".piodebug-")
self._target_is_run = False
self._last_server_activity = 0
self._auto_continue_timer = None
def spawn(self, gdb_path, prog_path):
session_hash = gdb_path + prog_path
self._session_id = sha1(hashlib_encode_data(session_hash)).hexdigest()
self._kill_previous_session()
patterns = {
"PROJECT_DIR": self.project_dir,
"PROG_PATH": prog_path,
"PROG_DIR": dirname(prog_path),
"PROG_NAME": basename(splitext(prog_path)[0]),
"DEBUG_PORT": self.debug_options['port'],
"UPLOAD_PROTOCOL": self.debug_options['upload_protocol'],
"INIT_BREAK": self.debug_options['init_break'] or "",
"LOAD_CMDS": "\n".join(self.debug_options['load_cmds'] or []),
}
self._debug_server.spawn(patterns)
if not patterns['DEBUG_PORT']:
patterns['DEBUG_PORT'] = self._debug_server.get_debug_port()
self.generate_pioinit(self._gdbsrc_dir, patterns)
# start GDB client
args = [
"piogdb",
"-q",
"--directory", self._gdbsrc_dir,
"--directory", self.project_dir,
"-l", "10"
] # yapf: disable
args.extend(self.args)
if not gdb_path:
raise exception.DebugInvalidOptions("GDB client is not configured")
gdb_data_dir = self._get_data_dir(gdb_path)
if gdb_data_dir:
args.extend(["--data-directory", gdb_data_dir])
args.append(patterns['PROG_PATH'])
return reactor.spawnProcess(self,
gdb_path,
args,
path=self.project_dir,
env=os.environ)
@staticmethod
def _get_data_dir(gdb_path):
if "msp430" in gdb_path:
return None
gdb_data_dir = abspath(join(dirname(gdb_path), "..", "share", "gdb"))
return gdb_data_dir if isdir(gdb_data_dir) else None
def generate_pioinit(self, dst_dir, patterns):
server_exe = (self.debug_options.get("server")
or {}).get("executable", "").lower()
if "jlink" in server_exe:
cfg = initcfgs.GDB_JLINK_INIT_CONFIG
elif "st-util" in server_exe:
cfg = initcfgs.GDB_STUTIL_INIT_CONFIG
elif "mspdebug" in server_exe:
cfg = initcfgs.GDB_MSPDEBUG_INIT_CONFIG
elif "qemu" in server_exe:
cfg = initcfgs.GDB_QEMU_INIT_CONFIG
elif self.debug_options['require_debug_port']:
cfg = initcfgs.GDB_BLACKMAGIC_INIT_CONFIG
else:
cfg = initcfgs.GDB_DEFAULT_INIT_CONFIG
commands = cfg.split("\n")
if self.debug_options['init_cmds']:
commands = self.debug_options['init_cmds']
commands.extend(self.debug_options['extra_cmds'])
if not any("define pio_reset_target" in cmd for cmd in commands):
commands = [
"define pio_reset_target",
" echo Warning! Undefined pio_reset_target command\\n",
" mon reset",
"end"
] + commands # yapf: disable
if not any("define pio_reset_halt_target" in cmd for cmd in commands):
commands = [
"define pio_reset_halt_target",
" echo Warning! Undefined pio_reset_halt_target command\\n",
" mon reset halt",
"end"
] + commands # yapf: disable
if not any("define pio_restart_target" in cmd for cmd in commands):
commands += [
"define pio_restart_target",
" pio_reset_halt_target",
" $INIT_BREAK",
" %s" % ("continue" if patterns['INIT_BREAK'] else "next"),
"end"
] # yapf: disable
banner = [
"echo PlatformIO Unified Debugger -> http://bit.ly/pio-debug\\n",
"echo PlatformIO: debug_tool = %s\\n" % self.debug_options['tool'],
"echo PlatformIO: Initializing remote target...\\n"
]
footer = ["echo %s\\n" % self.INIT_COMPLETED_BANNER]
commands = banner + commands + footer
with open(join(dst_dir, self.PIO_SRC_NAME), "w") as fp:
fp.write("\n".join(self.apply_patterns(commands, patterns)))
def connectionMade(self):
self._lock_session(self.transport.pid)
p = protocol.Protocol()
p.dataReceived = self.onStdInData
stdio.StandardIO(p)
def onStdInData(self, data):
if LOG_FILE:
with open(LOG_FILE, "ab") as fp:
fp.write(data)
self._last_server_activity = time.time()
if b"-exec-run" in data:
if self._target_is_run:
token, _ = data.split(b"-", 1)
self.outReceived(token + b"^running\n")
return
data = data.replace(b"-exec-run", b"-exec-continue")
if b"-exec-continue" in data:
self._target_is_run = True
if b"-gdb-exit" in data or data.strip() in (b"q", b"quit"):
# Allow terminating via SIGINT/CTRL+C
signal.signal(signal.SIGINT, signal.default_int_handler)
self.transport.write(b"pio_reset_target\n")
self.transport.write(data)
def processEnded(self, reason): # pylint: disable=unused-argument
self._unlock_session()
if self._gdbsrc_dir and isdir(self._gdbsrc_dir):
fs.rmtree(self._gdbsrc_dir)
if self._debug_server:
self._debug_server.terminate()
reactor.stop()
def outReceived(self, data):
if LOG_FILE:
with open(LOG_FILE, "ab") as fp:
fp.write(data)
self._last_server_activity = time.time()
super(GDBClient, self).outReceived(data)
self._handle_error(data)
# go to init break automatically
if self.INIT_COMPLETED_BANNER.encode() in data:
self._auto_continue_timer = task.LoopingCall(
self._auto_exec_continue)
self._auto_continue_timer.start(0.1)
def errReceived(self, data):
super(GDBClient, self).errReceived(data)
self._handle_error(data)
def console_log(self, msg):
if helpers.is_mi_mode(self.args):
self.outReceived(('~"%s\\n"\n' % msg).encode())
else:
self.outReceived(("%s\n" % msg).encode())
def _auto_exec_continue(self):
auto_exec_delay = 0.5 # in seconds
if self._last_server_activity > (time.time() - auto_exec_delay):
return
if self._auto_continue_timer:
self._auto_continue_timer.stop()
self._auto_continue_timer = None
if not self.debug_options['init_break'] or self._target_is_run:
return
self.console_log(
"PlatformIO: Resume the execution to `debug_init_break = %s`" %
self.debug_options['init_break'])
self.console_log("PlatformIO: More configuration options -> "
"http://bit.ly/pio-debug")
self.transport.write(b"0-exec-continue\n" if helpers.
is_mi_mode(self.args) else b"continue\n")
self._target_is_run = True
def _handle_error(self, data):
if (self.PIO_SRC_NAME.encode() not in data
or b"Error in sourced" not in data):
return
configuration = {"debug": self.debug_options, "env": self.env_options}
exd = re.sub(r'\\(?!")', "/", json.dumps(configuration))
exd = re.sub(r'"(?:[a-z]\:)?((/[^"/]+)+)"',
lambda m: '"%s"' % join(*m.group(1).split("/")[-2:]), exd,
re.I | re.M)
mp = MeasurementProtocol()
mp['exd'] = "DebugGDBPioInitError: %s" % exd
mp['exf'] = 1
mp.send("exception")
self.transport.loseConnection()
def _kill_previous_session(self):
assert self._session_id
pid = None
with app.ContentCache() as cc:
pid = cc.get(self._session_id)
cc.delete(self._session_id)
if not pid:
return
if "windows" in util.get_systype():
kill = ["Taskkill", "/PID", pid, "/F"]
else:
kill = ["kill", pid]
try:
proc.exec_command(kill)
except: # pylint: disable=bare-except
pass
def _lock_session(self, pid):
if not self._session_id:
return
with app.ContentCache() as cc:
cc.set(self._session_id, str(pid), "1h")
def _unlock_session(self):
if not self._session_id:
return
with app.ContentCache() as cc:
cc.delete(self._session_id)

View File

@@ -0,0 +1,151 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# pylint: disable=too-many-arguments, too-many-statements
# pylint: disable=too-many-locals, too-many-branches
import os
import signal
from os.path import isfile, join
import click
from platformio import exception, fs, proc, util
from platformio.commands.debug import helpers
from platformio.managers.core import inject_contrib_pysite
from platformio.project.config import ProjectConfig
from platformio.project.helpers import (is_platformio_project,
load_project_ide_data)
@click.command("debug",
context_settings=dict(ignore_unknown_options=True),
short_help="PIO Unified Debugger")
@click.option("-d",
"--project-dir",
default=os.getcwd,
type=click.Path(exists=True,
file_okay=False,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option("-c",
"--project-conf",
type=click.Path(exists=True,
file_okay=True,
dir_okay=False,
readable=True,
resolve_path=True))
@click.option("--environment", "-e", metavar="<environment>")
@click.option("--verbose", "-v", is_flag=True)
@click.option("--interface", type=click.Choice(["gdb"]))
@click.argument("__unprocessed", nargs=-1, type=click.UNPROCESSED)
@click.pass_context
def cli(ctx, project_dir, project_conf, environment, verbose, interface,
__unprocessed):
# use env variables from Eclipse or CLion
for sysenv in ("CWD", "PWD", "PLATFORMIO_PROJECT_DIR"):
if is_platformio_project(project_dir):
break
if os.getenv(sysenv):
project_dir = os.getenv(sysenv)
with fs.cd(project_dir):
config = ProjectConfig.get_instance(
project_conf or join(project_dir, "platformio.ini"))
config.validate(envs=[environment] if environment else None)
env_name = environment or helpers.get_default_debug_env(config)
env_options = config.items(env=env_name, as_dict=True)
if not set(env_options.keys()) >= set(["platform", "board"]):
raise exception.ProjectEnvsNotAvailable()
debug_options = helpers.validate_debug_options(ctx, env_options)
assert debug_options
if not interface:
return helpers.predebug_project(ctx, project_dir, env_name, False,
verbose)
configuration = load_project_ide_data(project_dir, env_name)
if not configuration:
raise exception.DebugInvalidOptions(
"Could not load debug configuration")
if "--version" in __unprocessed:
result = proc.exec_command([configuration['gdb_path'], "--version"])
if result['returncode'] == 0:
return click.echo(result['out'])
raise exception.PlatformioException("\n".join(
[result['out'], result['err']]))
try:
fs.ensure_udev_rules()
except exception.InvalidUdevRules as e:
for line in str(e).split("\n") + [""]:
click.echo(
('~"%s\\n"' if helpers.is_mi_mode(__unprocessed) else "%s") %
line)
debug_options['load_cmds'] = helpers.configure_esp32_load_cmds(
debug_options, configuration)
rebuild_prog = False
preload = debug_options['load_cmds'] == ["preload"]
load_mode = debug_options['load_mode']
if load_mode == "always":
rebuild_prog = (
preload
or not helpers.has_debug_symbols(configuration['prog_path']))
elif load_mode == "modified":
rebuild_prog = (
helpers.is_prog_obsolete(configuration['prog_path'])
or not helpers.has_debug_symbols(configuration['prog_path']))
else:
rebuild_prog = not isfile(configuration['prog_path'])
if preload or (not rebuild_prog and load_mode != "always"):
# don't load firmware through debug server
debug_options['load_cmds'] = []
if rebuild_prog:
if helpers.is_mi_mode(__unprocessed):
click.echo('~"Preparing firmware for debugging...\\n"')
output = helpers.GDBBytesIO()
with util.capture_std_streams(output):
helpers.predebug_project(ctx, project_dir, env_name, preload,
verbose)
output.close()
else:
click.echo("Preparing firmware for debugging...")
helpers.predebug_project(ctx, project_dir, env_name, preload,
verbose)
# save SHA sum of newly created prog
if load_mode == "modified":
helpers.is_prog_obsolete(configuration['prog_path'])
if not isfile(configuration['prog_path']):
raise exception.DebugInvalidOptions("Program/firmware is missed")
# run debugging client
inject_contrib_pysite()
from platformio.commands.debug.client import GDBClient, reactor
client = GDBClient(project_dir, __unprocessed, debug_options, env_options)
client.spawn(configuration['gdb_path'], configuration['prog_path'])
signal.signal(signal.SIGINT, lambda *args, **kwargs: None)
reactor.run()
return True

View File

@@ -0,0 +1,265 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
import time
from fnmatch import fnmatch
from hashlib import sha1
from io import BytesIO
from os.path import isfile
from platformio import exception, util
from platformio.commands.platform import \
platform_install as cmd_platform_install
from platformio.commands.run import cli as cmd_run
from platformio.managers.platform import PlatformFactory
from platformio.project.config import ProjectConfig
class GDBBytesIO(BytesIO): # pylint: disable=too-few-public-methods
STDOUT = sys.stdout
def write(self, text):
if "\n" in text:
for line in text.strip().split("\n"):
self.STDOUT.write('~"%s\\n"\n' % line)
else:
self.STDOUT.write('~"%s"' % text)
self.STDOUT.flush()
def is_mi_mode(args):
return "--interpreter" in " ".join(args)
def get_default_debug_env(config):
default_envs = config.default_envs()
all_envs = config.envs()
for env in default_envs:
if config.get("env:" + env, "build_type") == "debug":
return env
for env in all_envs:
if config.get("env:" + env, "build_type") == "debug":
return env
return default_envs[0] if default_envs else all_envs[0]
def predebug_project(ctx, project_dir, env_name, preload, verbose):
ctx.invoke(cmd_run,
project_dir=project_dir,
environment=[env_name],
target=["debug"] + (["upload"] if preload else []),
verbose=verbose)
if preload:
time.sleep(5)
def validate_debug_options(cmd_ctx, env_options):
def _cleanup_cmds(items):
items = ProjectConfig.parse_multi_values(items)
return [
"$LOAD_CMDS" if item == "$LOAD_CMD" else item for item in items
]
try:
platform = PlatformFactory.newPlatform(env_options['platform'])
except exception.UnknownPlatform:
cmd_ctx.invoke(cmd_platform_install,
platforms=[env_options['platform']],
skip_default_package=True)
platform = PlatformFactory.newPlatform(env_options['platform'])
board_config = platform.board_config(env_options['board'])
tool_name = board_config.get_debug_tool_name(env_options.get("debug_tool"))
tool_settings = board_config.get("debug", {}).get("tools",
{}).get(tool_name, {})
server_options = None
# specific server per a system
if isinstance(tool_settings.get("server", {}), list):
for item in tool_settings['server'][:]:
tool_settings['server'] = item
if util.get_systype() in item.get("system", []):
break
# user overwrites debug server
if env_options.get("debug_server"):
server_options = {
"cwd": None,
"executable": None,
"arguments": env_options.get("debug_server")
}
server_options['executable'] = server_options['arguments'][0]
server_options['arguments'] = server_options['arguments'][1:]
elif "server" in tool_settings:
server_package = tool_settings['server'].get("package")
server_package_dir = platform.get_package_dir(
server_package) if server_package else None
if server_package and not server_package_dir:
platform.install_packages(with_packages=[server_package],
skip_default_package=True,
silent=True)
server_package_dir = platform.get_package_dir(server_package)
server_options = dict(
cwd=server_package_dir if server_package else None,
executable=tool_settings['server'].get("executable"),
arguments=[
a.replace("$PACKAGE_DIR", server_package_dir)
if server_package_dir else a
for a in tool_settings['server'].get("arguments", [])
])
extra_cmds = _cleanup_cmds(env_options.get("debug_extra_cmds"))
extra_cmds.extend(_cleanup_cmds(tool_settings.get("extra_cmds")))
result = dict(
tool=tool_name,
upload_protocol=env_options.get(
"upload_protocol",
board_config.get("upload", {}).get("protocol")),
load_cmds=_cleanup_cmds(
env_options.get(
"debug_load_cmds",
tool_settings.get("load_cmds",
tool_settings.get("load_cmd", "load")))),
load_mode=env_options.get("debug_load_mode",
tool_settings.get("load_mode", "always")),
init_break=env_options.get(
"debug_init_break", tool_settings.get("init_break",
"tbreak main")),
init_cmds=_cleanup_cmds(
env_options.get("debug_init_cmds",
tool_settings.get("init_cmds"))),
extra_cmds=extra_cmds,
require_debug_port=tool_settings.get("require_debug_port", False),
port=reveal_debug_port(
env_options.get("debug_port", tool_settings.get("port")),
tool_name, tool_settings),
server=server_options)
return result
def configure_esp32_load_cmds(debug_options, configuration):
ignore_conds = [
debug_options['load_cmds'] != ["load"],
"xtensa-esp32" not in configuration.get("cc_path", ""),
not configuration.get("flash_extra_images"), not all([
isfile(item['path'])
for item in configuration.get("flash_extra_images")
])
]
if any(ignore_conds):
return debug_options['load_cmds']
mon_cmds = [
'monitor program_esp32 "{{{path}}}" {offset} verify'.format(
path=item['path'], offset=item['offset'])
for item in configuration.get("flash_extra_images")
]
mon_cmds.append('monitor program_esp32 "{%s.bin}" 0x10000 verify' %
configuration['prog_path'][:-4])
return mon_cmds
def has_debug_symbols(prog_path):
if not isfile(prog_path):
return False
matched = {
b".debug_info": False,
b".debug_abbrev": False,
b" -Og": False,
b" -g": False,
b"__PLATFORMIO_BUILD_DEBUG__": False
}
with open(prog_path, "rb") as fp:
last_data = b""
while True:
data = fp.read(1024)
if not data:
break
for pattern, found in matched.items():
if found:
continue
if pattern in last_data + data:
matched[pattern] = True
last_data = data
return all(matched.values())
def is_prog_obsolete(prog_path):
prog_hash_path = prog_path + ".sha1"
if not isfile(prog_path):
return True
shasum = sha1()
with open(prog_path, "rb") as fp:
while True:
data = fp.read(1024)
if not data:
break
shasum.update(data)
new_digest = shasum.hexdigest()
old_digest = None
if isfile(prog_hash_path):
with open(prog_hash_path, "r") as fp:
old_digest = fp.read()
if new_digest == old_digest:
return False
with open(prog_hash_path, "w") as fp:
fp.write(new_digest)
return True
def reveal_debug_port(env_debug_port, tool_name, tool_settings):
def _get_pattern():
if not env_debug_port:
return None
if set(["*", "?", "[", "]"]) & set(env_debug_port):
return env_debug_port
return None
def _is_match_pattern(port):
pattern = _get_pattern()
if not pattern:
return True
return fnmatch(port, pattern)
def _look_for_serial_port(hwids):
for item in util.get_serialports(filter_hwid=True):
if not _is_match_pattern(item['port']):
continue
port = item['port']
if tool_name.startswith("blackmagic"):
if "windows" in util.get_systype() and \
port.startswith("COM") and len(port) > 4:
port = "\\\\.\\%s" % port
if "GDB" in item['description']:
return port
for hwid in hwids:
hwid_str = ("%s:%s" % (hwid[0], hwid[1])).replace("0x", "")
if hwid_str in item['hwid']:
return port
return None
if env_debug_port and not _get_pattern():
return env_debug_port
if not tool_settings.get("require_debug_port"):
return None
debug_port = _look_for_serial_port(tool_settings.get("hwids", []))
if not debug_port:
raise exception.DebugInvalidOptions(
"Please specify `debug_port` for environment")
return debug_port

View File

@@ -0,0 +1,124 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
GDB_DEFAULT_INIT_CONFIG = """
define pio_reset_halt_target
monitor reset halt
end
define pio_reset_target
monitor reset
end
target extended-remote $DEBUG_PORT
$INIT_BREAK
pio_reset_halt_target
$LOAD_CMDS
monitor init
pio_reset_halt_target
"""
GDB_STUTIL_INIT_CONFIG = """
define pio_reset_halt_target
monitor halt
monitor reset
end
define pio_reset_target
monitor reset
end
target extended-remote $DEBUG_PORT
$INIT_BREAK
pio_reset_halt_target
$LOAD_CMDS
pio_reset_halt_target
"""
GDB_JLINK_INIT_CONFIG = """
define pio_reset_halt_target
monitor halt
monitor reset
end
define pio_reset_target
monitor reset
end
target extended-remote $DEBUG_PORT
$INIT_BREAK
pio_reset_halt_target
$LOAD_CMDS
pio_reset_halt_target
"""
GDB_BLACKMAGIC_INIT_CONFIG = """
define pio_reset_halt_target
set language c
set *0xE000ED0C = 0x05FA0004
set $busy = (*0xE000ED0C & 0x4)
while ($busy)
set $busy = (*0xE000ED0C & 0x4)
end
set language auto
end
define pio_reset_target
pio_reset_halt_target
end
target extended-remote $DEBUG_PORT
monitor swdp_scan
attach 1
set mem inaccessible-by-default off
$INIT_BREAK
$LOAD_CMDS
set language c
set *0xE000ED0C = 0x05FA0004
set $busy = (*0xE000ED0C & 0x4)
while ($busy)
set $busy = (*0xE000ED0C & 0x4)
end
set language auto
"""
GDB_MSPDEBUG_INIT_CONFIG = """
define pio_reset_halt_target
end
define pio_reset_target
end
target extended-remote $DEBUG_PORT
$INIT_BREAK
monitor erase
$LOAD_CMDS
pio_reset_halt_target
"""
GDB_QEMU_INIT_CONFIG = """
define pio_reset_halt_target
monitor system_reset
end
define pio_reset_target
pio_reset_halt_target
end
target extended-remote $DEBUG_PORT
$INIT_BREAK
$LOAD_CMDS
pio_reset_halt_target
"""

View File

@@ -0,0 +1,79 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import signal
import click
from twisted.internet import protocol # pylint: disable=import-error
from platformio.compat import string_types
from platformio.proc import get_pythonexe_path
from platformio.project.helpers import get_project_core_dir
LOG_FILE = None
class BaseProcess(protocol.ProcessProtocol, object):
STDOUT_CHUNK_SIZE = 2048
COMMON_PATTERNS = {
"PLATFORMIO_HOME_DIR": get_project_core_dir(),
"PLATFORMIO_CORE_DIR": get_project_core_dir(),
"PYTHONEXE": get_pythonexe_path()
}
def apply_patterns(self, source, patterns=None):
_patterns = self.COMMON_PATTERNS.copy()
_patterns.update(patterns or {})
def _replace(text):
for key, value in _patterns.items():
pattern = "$%s" % key
text = text.replace(pattern, value or "")
return text
if isinstance(source, string_types):
source = _replace(source)
elif isinstance(source, (list, dict)):
items = enumerate(source) if isinstance(source,
list) else source.items()
for key, value in items:
if isinstance(value, string_types):
source[key] = _replace(value)
elif isinstance(value, (list, dict)):
source[key] = self.apply_patterns(value, patterns)
return source
def outReceived(self, data):
if LOG_FILE:
with open(LOG_FILE, "ab") as fp:
fp.write(data)
while data:
chunk = data[:self.STDOUT_CHUNK_SIZE]
click.echo(chunk, nl=False)
data = data[self.STDOUT_CHUNK_SIZE:]
@staticmethod
def errReceived(data):
if LOG_FILE:
with open(LOG_FILE, "ab") as fp:
fp.write(data)
click.echo(data, nl=False, err=True)
@staticmethod
def processEnded(_):
# Allow terminating via SIGINT/CTRL+C
signal.signal(signal.SIGINT, signal.default_int_handler)

View File

@@ -0,0 +1,122 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from os.path import isdir, isfile, join
from twisted.internet import error # pylint: disable=import-error
from twisted.internet import reactor # pylint: disable=import-error
from platformio import exception, util
from platformio.commands.debug.process import BaseProcess
from platformio.proc import where_is_program
class DebugServer(BaseProcess):
def __init__(self, debug_options, env_options):
self.debug_options = debug_options
self.env_options = env_options
self._debug_port = None
self._transport = None
self._process_ended = False
def spawn(self, patterns): # pylint: disable=too-many-branches
systype = util.get_systype()
server = self.debug_options.get("server")
if not server:
return None
server = self.apply_patterns(server, patterns)
server_executable = server['executable']
if not server_executable:
return None
if server['cwd']:
server_executable = join(server['cwd'], server_executable)
if ("windows" in systype and not server_executable.endswith(".exe")
and isfile(server_executable + ".exe")):
server_executable = server_executable + ".exe"
if not isfile(server_executable):
server_executable = where_is_program(server_executable)
if not isfile(server_executable):
raise exception.DebugInvalidOptions(
"\nCould not launch Debug Server '%s'. Please check that it "
"is installed and is included in a system PATH\n\n"
"See documentation or contact contact@platformio.org:\n"
"http://docs.platformio.org/page/plus/debugging.html\n" %
server_executable)
self._debug_port = ":3333"
openocd_pipe_allowed = all([
not self.debug_options['port'],
"openocd" in server_executable
]) # yapf: disable
if openocd_pipe_allowed:
args = []
if server['cwd']:
args.extend(["-s", server['cwd']])
args.extend([
"-c", "gdb_port pipe; tcl_port disabled; telnet_port disabled"
])
args.extend(server['arguments'])
str_args = " ".join(
[arg if arg.startswith("-") else '"%s"' % arg for arg in args])
self._debug_port = '| "%s" %s' % (server_executable, str_args)
self._debug_port = self._debug_port.replace("\\", "\\\\")
else:
env = os.environ.copy()
# prepend server "lib" folder to LD path
if ("windows" not in systype and server['cwd']
and isdir(join(server['cwd'], "lib"))):
ld_key = ("DYLD_LIBRARY_PATH"
if "darwin" in systype else "LD_LIBRARY_PATH")
env[ld_key] = join(server['cwd'], "lib")
if os.environ.get(ld_key):
env[ld_key] = "%s:%s" % (env[ld_key],
os.environ.get(ld_key))
# prepend BIN to PATH
if server['cwd'] and isdir(join(server['cwd'], "bin")):
env['PATH'] = "%s%s%s" % (
join(server['cwd'], "bin"), os.pathsep,
os.environ.get("PATH", os.environ.get("Path", "")))
self._transport = reactor.spawnProcess(
self,
server_executable, [server_executable] + server['arguments'],
path=server['cwd'],
env=env)
if "mspdebug" in server_executable.lower():
self._debug_port = ":2000"
elif "jlink" in server_executable.lower():
self._debug_port = ":2331"
elif "qemu" in server_executable.lower():
self._debug_port = ":1234"
return self._transport
def get_debug_port(self):
return self._debug_port
def processEnded(self, reason):
self._process_ended = True
super(DebugServer, self).processEnded(reason)
def terminate(self):
if self._process_ended or not self._transport:
return
try:
self._transport.signalProcess("KILL")
except (OSError, error.ProcessExitedAlready):
pass

View File

@@ -12,14 +12,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import sys
from fnmatch import fnmatch
from os import getcwd
from os.path import join
import click
from serial.tools import miniterm
from platformio import exception, util
from platformio.compat import dump_json_to_unicode
from platformio.project.config import ProjectConfig
@click.group(short_help="Monitor device or list existing")
@@ -28,110 +31,160 @@ def cli():
@cli.command("list", short_help="List devices")
@click.option("--serial", is_flag=True, help="List serial ports, default")
@click.option("--logical", is_flag=True, help="List logical devices")
@click.option("--mdns", is_flag=True, help="List multicast DNS services")
@click.option("--json-output", is_flag=True)
def device_list(json_output):
def device_list( # pylint: disable=too-many-branches
serial, logical, mdns, json_output):
if not logical and not mdns:
serial = True
data = {}
if serial:
data['serial'] = util.get_serial_ports()
if logical:
data['logical'] = util.get_logical_devices()
if mdns:
data['mdns'] = util.get_mdns_services()
single_key = list(data)[0] if len(list(data)) == 1 else None
if json_output:
click.echo(json.dumps(util.get_serialports()))
return
return click.echo(
dump_json_to_unicode(data[single_key] if single_key else data))
for item in util.get_serialports():
click.secho(item['port'], fg="cyan")
click.echo("-" * len(item['port']))
click.echo("Hardware ID: %s" % item['hwid'])
click.echo("Description: %s" % item['description'])
click.echo("")
titles = {
"serial": "Serial Ports",
"logical": "Logical Devices",
"mdns": "Multicast DNS Services"
}
for key, value in data.items():
if not single_key:
click.secho(titles[key], bold=True)
click.echo("=" * len(titles[key]))
if key == "serial":
for item in value:
click.secho(item['port'], fg="cyan")
click.echo("-" * len(item['port']))
click.echo("Hardware ID: %s" % item['hwid'])
click.echo("Description: %s" % item['description'])
click.echo("")
if key == "logical":
for item in value:
click.secho(item['path'], fg="cyan")
click.echo("-" * len(item['path']))
click.echo("Name: %s" % item['name'])
click.echo("")
if key == "mdns":
for item in value:
click.secho(item['name'], fg="cyan")
click.echo("-" * len(item['name']))
click.echo("Type: %s" % item['type'])
click.echo("IP: %s" % item['ip'])
click.echo("Port: %s" % item['port'])
if item['properties']:
click.echo("Properties: %s" % ("; ".join([
"%s=%s" % (k, v)
for k, v in item['properties'].items()
])))
click.echo("")
if single_key:
click.echo("")
return True
@cli.command("monitor", short_help="Monitor device (Serial)")
@click.option("--port", "-p", help="Port, a number or a device name")
@click.option("--baud", "-b", type=int, help="Set baud rate, default=9600")
@click.option(
"--parity",
default="N",
type=click.Choice(["N", "E", "O", "S", "M"]),
help="Set parity, default=N")
@click.option(
"--rtscts", is_flag=True, help="Enable RTS/CTS flow control, default=Off")
@click.option(
"--xonxoff",
is_flag=True,
help="Enable software flow control, default=Off")
@click.option(
"--rts",
default=None,
type=click.IntRange(0, 1),
help="Set initial RTS line state")
@click.option(
"--dtr",
default=None,
type=click.IntRange(0, 1),
help="Set initial DTR line state")
@click.option("--parity",
default="N",
type=click.Choice(["N", "E", "O", "S", "M"]),
help="Set parity, default=N")
@click.option("--rtscts",
is_flag=True,
help="Enable RTS/CTS flow control, default=Off")
@click.option("--xonxoff",
is_flag=True,
help="Enable software flow control, default=Off")
@click.option("--rts",
default=None,
type=click.IntRange(0, 1),
help="Set initial RTS line state")
@click.option("--dtr",
default=None,
type=click.IntRange(0, 1),
help="Set initial DTR line state")
@click.option("--echo", is_flag=True, help="Enable local echo, default=Off")
@click.option(
"--encoding",
default="UTF-8",
help="Set the encoding for the serial port (e.g. hexlify, "
"Latin1, UTF-8), default: UTF-8")
@click.option("--encoding",
default="UTF-8",
help="Set the encoding for the serial port (e.g. hexlify, "
"Latin1, UTF-8), default: UTF-8")
@click.option("--filter", "-f", multiple=True, help="Add text transformation")
@click.option(
"--eol",
default="CRLF",
type=click.Choice(["CR", "LF", "CRLF"]),
help="End of line mode, default=CRLF")
@click.option(
"--raw", is_flag=True, help="Do not apply any encodings/transformations")
@click.option(
"--exit-char",
type=int,
default=3,
help="ASCII code of special character that is used to exit "
"the application, default=3 (Ctrl+C)")
@click.option(
"--menu-char",
type=int,
default=20,
help="ASCII code of special character that is used to "
"control miniterm (menu), default=20 (DEC)")
@click.option(
"--quiet",
is_flag=True,
help="Diagnostics: suppress non-error messages, default=Off")
@click.option(
"-d",
"--project-dir",
default=getcwd,
type=click.Path(
exists=True, file_okay=False, dir_okay=True, resolve_path=True))
@click.option("--eol",
default="CRLF",
type=click.Choice(["CR", "LF", "CRLF"]),
help="End of line mode, default=CRLF")
@click.option("--raw",
is_flag=True,
help="Do not apply any encodings/transformations")
@click.option("--exit-char",
type=int,
default=3,
help="ASCII code of special character that is used to exit "
"the application, default=3 (Ctrl+C)")
@click.option("--menu-char",
type=int,
default=20,
help="ASCII code of special character that is used to "
"control miniterm (menu), default=20 (DEC)")
@click.option("--quiet",
is_flag=True,
help="Diagnostics: suppress non-error messages, default=Off")
@click.option("-d",
"--project-dir",
default=getcwd,
type=click.Path(exists=True,
file_okay=False,
dir_okay=True,
resolve_path=True))
@click.option(
"-e",
"--environment",
help="Load configuration from `platformio.ini` and specified environment")
def device_monitor(**kwargs): # pylint: disable=too-many-branches
env_options = {}
try:
project_options = get_project_options(kwargs['project_dir'],
kwargs['environment'])
monitor_options = {k: v for k, v in project_options or []}
if monitor_options:
for k in ("port", "baud", "rts", "dtr"):
k2 = "monitor_%s" % k
if kwargs[k] is None and k2 in monitor_options:
kwargs[k] = monitor_options[k2]
if k != "port":
kwargs[k] = int(kwargs[k])
env_options = get_project_options(kwargs['project_dir'],
kwargs['environment'])
for k in ("port", "speed", "rts", "dtr"):
k2 = "monitor_%s" % k
if k == "speed":
k = "baud"
if kwargs[k] is None and k2 in env_options:
kwargs[k] = env_options[k2]
if k != "port":
kwargs[k] = int(kwargs[k])
except exception.NotPlatformIOProject:
pass
if not kwargs['port']:
ports = util.get_serialports(filter_hwid=True)
ports = util.get_serial_ports(filter_hwid=True)
if len(ports) == 1:
kwargs['port'] = ports[0]['port']
sys.argv = ["monitor"]
for k, v in kwargs.iteritems():
sys.argv = ["monitor"] + env_options.get("monitor_flags", [])
for k, v in kwargs.items():
if k in ("port", "baud", "rts", "dtr", "environment", "project_dir"):
continue
k = "--" + k.replace("_", "-")
if k in env_options.get("monitor_flags", []):
continue
if isinstance(v, bool):
if v:
sys.argv.append(k)
@@ -141,34 +194,28 @@ def device_monitor(**kwargs): # pylint: disable=too-many-branches
else:
sys.argv.extend([k, str(v)])
if kwargs['port'] and (set(["*", "?", "[", "]"]) & set(kwargs['port'])):
for item in util.get_serial_ports():
if fnmatch(item['port'], kwargs['port']):
kwargs['port'] = item['port']
break
try:
miniterm.main(
default_port=kwargs['port'],
default_baudrate=kwargs['baud'] or 9600,
default_rts=kwargs['rts'],
default_dtr=kwargs['dtr'])
miniterm.main(default_port=kwargs['port'],
default_baudrate=kwargs['baud'] or 9600,
default_rts=kwargs['rts'],
default_dtr=kwargs['dtr'])
except Exception as e:
raise exception.MinitermException(e)
def get_project_options(project_dir, environment):
config = util.load_project_config(project_dir)
if not config.sections():
return
known_envs = [s[4:] for s in config.sections() if s.startswith("env:")]
if environment:
if environment in known_envs:
return config.items("env:%s" % environment)
raise exception.UnknownEnvNames(environment, ", ".join(known_envs))
if not known_envs:
return
if config.has_option("platformio", "env_default"):
env_default = config.get("platformio",
"env_default").split(", ")[0].strip()
if env_default and env_default in known_envs:
return config.items("env:%s" % env_default)
return config.items("env:%s" % known_envs[0])
def get_project_options(project_dir, environment=None):
config = ProjectConfig.get_instance(join(project_dir, "platformio.ini"))
config.validate(envs=[environment] if environment else None)
if not environment:
default_envs = config.default_envs()
if default_envs:
environment = default_envs[0]
else:
environment = config.envs()[0]
return config.items(env=environment, as_dict=True)

View File

@@ -0,0 +1,15 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from platformio.commands.home.command import cli

View File

@@ -0,0 +1,109 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import mimetypes
import socket
from os.path import isdir
import click
from platformio import exception
from platformio.managers.core import (get_core_package_dir,
inject_contrib_pysite)
@click.command("home", short_help="PIO Home")
@click.option("--port", type=int, default=8008, help="HTTP port, default=8008")
@click.option(
"--host",
default="127.0.0.1",
help="HTTP host, default=127.0.0.1. "
"You can open PIO Home for inbound connections with --host=0.0.0.0")
@click.option("--no-open", is_flag=True) # pylint: disable=too-many-locals
def cli(port, host, no_open):
# import contrib modules
inject_contrib_pysite()
# pylint: disable=import-error
from autobahn.twisted.resource import WebSocketResource
from twisted.internet import reactor
from twisted.web import server
# pylint: enable=import-error
from platformio.commands.home.rpc.handlers.app import AppRPC
from platformio.commands.home.rpc.handlers.ide import IDERPC
from platformio.commands.home.rpc.handlers.misc import MiscRPC
from platformio.commands.home.rpc.handlers.os import OSRPC
from platformio.commands.home.rpc.handlers.piocore import PIOCoreRPC
from platformio.commands.home.rpc.handlers.project import ProjectRPC
from platformio.commands.home.rpc.server import JSONRPCServerFactory
from platformio.commands.home.web import WebRoot
factory = JSONRPCServerFactory()
factory.addHandler(AppRPC(), namespace="app")
factory.addHandler(IDERPC(), namespace="ide")
factory.addHandler(MiscRPC(), namespace="misc")
factory.addHandler(OSRPC(), namespace="os")
factory.addHandler(PIOCoreRPC(), namespace="core")
factory.addHandler(ProjectRPC(), namespace="project")
contrib_dir = get_core_package_dir("contrib-piohome")
if not isdir(contrib_dir):
raise exception.PlatformioException("Invalid path to PIO Home Contrib")
# Ensure PIO Home mimetypes are known
mimetypes.add_type("text/html", ".html")
mimetypes.add_type("text/css", ".css")
mimetypes.add_type("application/javascript", ".js")
root = WebRoot(contrib_dir)
root.putChild(b"wsrpc", WebSocketResource(factory))
site = server.Site(root)
# hook for `platformio-node-helpers`
if host == "__do_not_start__":
return
# if already started
already_started = False
socket.setdefaulttimeout(1)
try:
socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port))
already_started = True
except: # pylint: disable=bare-except
pass
home_url = "http://%s:%d" % (host, port)
if not no_open:
if already_started:
click.launch(home_url)
else:
reactor.callLater(1, lambda: click.launch(home_url))
click.echo("\n".join([
"",
" ___I_",
" /\\-_--\\ PlatformIO Home",
"/ \\_-__\\",
"|[]| [] | %s" % home_url,
"|__|____|______________%s" % ("_" * len(host)),
]))
click.echo("")
click.echo("Open PIO Home in your browser by this URL => %s" % home_url)
if already_started:
return
click.echo("PIO Home has been started. Press Ctrl+C to shutdown.")
reactor.listenTCP(port, site, interface=host)
reactor.run()

View File

@@ -0,0 +1,71 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# pylint: disable=keyword-arg-before-vararg, arguments-differ
import os
import socket
import requests
from twisted.internet import defer # pylint: disable=import-error
from twisted.internet import reactor # pylint: disable=import-error
from twisted.internet import threads # pylint: disable=import-error
from platformio import util
from platformio.proc import where_is_program
class AsyncSession(requests.Session):
def __init__(self, n=None, *args, **kwargs):
if n:
pool = reactor.getThreadPool()
pool.adjustPoolsize(0, n)
super(AsyncSession, self).__init__(*args, **kwargs)
def request(self, *args, **kwargs):
func = super(AsyncSession, self).request
return threads.deferToThread(func, *args, **kwargs)
def wrap(self, *args, **kwargs): # pylint: disable=no-self-use
return defer.ensureDeferred(*args, **kwargs)
@util.memoized(expire="60s")
def requests_session():
return AsyncSession(n=5)
@util.memoized(expire="60s")
def get_core_fullpath():
return where_is_program(
"platformio" + (".exe" if "windows" in util.get_systype() else ""))
@util.memoized(expire="10s")
def is_twitter_blocked():
ip = "104.244.42.1"
timeout = 2
try:
if os.getenv("HTTP_PROXY", os.getenv("HTTPS_PROXY")):
requests.get("http://%s" % ip,
allow_redirects=False,
timeout=timeout)
else:
socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((ip, 80))
return False
except: # pylint: disable=bare-except
pass
return True

View File

@@ -0,0 +1,13 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

View File

@@ -0,0 +1,13 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

View File

@@ -0,0 +1,81 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import absolute_import
from os.path import expanduser, join
from platformio import __version__, app, util
from platformio.project.helpers import (get_project_core_dir,
is_platformio_project)
class AppRPC(object):
APPSTATE_PATH = join(get_project_core_dir(), "homestate.json")
IGNORE_STORAGE_KEYS = [
"cid", "coreVersion", "coreSystype", "coreCaller", "coreSettings",
"homeDir", "projectsDir"
]
@staticmethod
def load_state():
with app.State(AppRPC.APPSTATE_PATH, lock=True) as state:
storage = state.get("storage", {})
# base data
caller_id = app.get_session_var("caller_id")
storage['cid'] = app.get_cid()
storage['coreVersion'] = __version__
storage['coreSystype'] = util.get_systype()
storage['coreCaller'] = (str(caller_id).lower()
if caller_id else None)
storage['coreSettings'] = {
name: {
"description": data['description'],
"default_value": data['value'],
"value": app.get_setting(name)
}
for name, data in app.DEFAULT_SETTINGS.items()
}
storage['homeDir'] = expanduser("~")
storage['projectsDir'] = storage['coreSettings']['projects_dir'][
'value']
# skip non-existing recent projects
storage['recentProjects'] = [
p for p in storage.get("recentProjects", [])
if is_platformio_project(p)
]
state['storage'] = storage
state.modified = False # skip saving extra fields
return state.as_dict()
@staticmethod
def get_state():
return AppRPC.load_state()
@staticmethod
def save_state(state):
with app.State(AppRPC.APPSTATE_PATH, lock=True) as s:
s.clear()
s.update(state)
storage = s.get("storage", {})
for k in AppRPC.IGNORE_STORAGE_KEYS:
if k in storage:
del storage[k]
return True

View File

@@ -0,0 +1,44 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import time
import jsonrpc # pylint: disable=import-error
from twisted.internet import defer # pylint: disable=import-error
class IDERPC(object):
def __init__(self):
self._queue = {}
def send_command(self, command, params, sid=0):
if not self._queue.get(sid):
raise jsonrpc.exceptions.JSONRPCDispatchException(
code=4005, message="PIO Home IDE agent is not started")
while self._queue[sid]:
self._queue[sid].pop().callback({
"id": time.time(),
"method": command,
"params": params
})
def listen_commands(self, sid=0):
if sid not in self._queue:
self._queue[sid] = []
self._queue[sid].append(defer.Deferred())
return self._queue[sid][-1]
def open_project(self, project_dir, sid=0):
return self.send_command("open_project", project_dir, sid)

View File

@@ -0,0 +1,54 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import time
from twisted.internet import defer, reactor # pylint: disable=import-error
from platformio import app
from platformio.commands.home.rpc.handlers.os import OSRPC
class MiscRPC(object):
def load_latest_tweets(self, username):
cache_key = "piohome_latest_tweets_" + str(username)
cache_valid = "7d"
with app.ContentCache() as cc:
cache_data = cc.get(cache_key)
if cache_data:
cache_data = json.loads(cache_data)
# automatically update cache in background every 12 hours
if cache_data['time'] < (time.time() - (3600 * 12)):
reactor.callLater(5, self._preload_latest_tweets, username,
cache_key, cache_valid)
return cache_data['result']
result = self._preload_latest_tweets(username, cache_key, cache_valid)
return result
@staticmethod
@defer.inlineCallbacks
def _preload_latest_tweets(username, cache_key, cache_valid):
result = yield OSRPC.fetch_content(
"https://api.platformio.org/tweets/" + username)
result = json.loads(result)
with app.ContentCache() as cc:
cc.set(cache_key,
json.dumps({
"time": int(time.time()),
"result": result
}), cache_valid)
defer.returnValue(result)

View File

@@ -0,0 +1,152 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import absolute_import
import codecs
import glob
import os
import shutil
from functools import cmp_to_key
from os.path import expanduser, isdir, isfile, join
import click
from twisted.internet import defer # pylint: disable=import-error
from platformio import app, util
from platformio.commands.home import helpers
from platformio.compat import PY2, get_filesystem_encoding
class OSRPC(object):
@staticmethod
@defer.inlineCallbacks
def fetch_content(uri, data=None, headers=None, cache_valid=None):
if not headers:
headers = {
"User-Agent":
("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) "
"AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 "
"Safari/603.3.8")
}
cache_key = (app.ContentCache.key_from_args(uri, data)
if cache_valid else None)
with app.ContentCache() as cc:
if cache_key:
result = cc.get(cache_key)
if result is not None:
defer.returnValue(result)
# check internet before and resolve issue with 60 seconds timeout
util.internet_on(raise_exception=True)
session = helpers.requests_session()
if data:
r = yield session.post(uri, data=data, headers=headers)
else:
r = yield session.get(uri, headers=headers)
r.raise_for_status()
result = r.text
if cache_valid:
with app.ContentCache() as cc:
cc.set(cache_key, result, cache_valid)
defer.returnValue(result)
def request_content(self, uri, data=None, headers=None, cache_valid=None):
if uri.startswith('http'):
return self.fetch_content(uri, data, headers, cache_valid)
if not isfile(uri):
return None
with codecs.open(uri, encoding="utf-8") as fp:
return fp.read()
@staticmethod
def open_url(url):
return click.launch(url)
@staticmethod
def reveal_file(path):
return click.launch(
path.encode(get_filesystem_encoding()) if PY2 else path,
locate=True)
@staticmethod
def is_file(path):
return isfile(path)
@staticmethod
def is_dir(path):
return isdir(path)
@staticmethod
def make_dirs(path):
return os.makedirs(path)
@staticmethod
def rename(src, dst):
return os.rename(src, dst)
@staticmethod
def copy(src, dst):
return shutil.copytree(src, dst)
@staticmethod
def glob(pathnames, root=None):
if not isinstance(pathnames, list):
pathnames = [pathnames]
result = set()
for pathname in pathnames:
result |= set(
glob.glob(join(root, pathname) if root else pathname))
return list(result)
@staticmethod
def list_dir(path):
def _cmp(x, y):
if x[1] and not y[1]:
return -1
if not x[1] and y[1]:
return 1
if x[0].lower() > y[0].lower():
return 1
if x[0].lower() < y[0].lower():
return -1
return 0
items = []
if path.startswith("~"):
path = expanduser(path)
if not isdir(path):
return items
for item in os.listdir(path):
try:
item_is_dir = isdir(join(path, item))
if item_is_dir:
os.listdir(join(path, item))
items.append((item, item_is_dir))
except OSError:
pass
return sorted(items, key=cmp_to_key(_cmp))
@staticmethod
def get_logical_devices():
items = []
for item in util.get_logical_devices():
if item['name']:
item['name'] = item['name']
items.append(item)
return items

View File

@@ -0,0 +1,162 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import absolute_import
import json
import os
import sys
from io import BytesIO, StringIO
import click
import jsonrpc # pylint: disable=import-error
from twisted.internet import defer # pylint: disable=import-error
from twisted.internet import threads # pylint: disable=import-error
from twisted.internet import utils # pylint: disable=import-error
from platformio import __main__, __version__, fs
from platformio.commands.home import helpers
from platformio.compat import (PY2, get_filesystem_encoding, is_bytes,
string_types)
try:
from thread import get_ident as thread_get_ident
except ImportError:
from threading import get_ident as thread_get_ident
class MultiThreadingStdStream(object):
def __init__(self, parent_stream):
self._buffers = {thread_get_ident(): parent_stream}
def __getattr__(self, name):
thread_id = thread_get_ident()
self._ensure_thread_buffer(thread_id)
return getattr(self._buffers[thread_id], name)
def _ensure_thread_buffer(self, thread_id):
if thread_id not in self._buffers:
self._buffers[thread_id] = BytesIO() if PY2 else StringIO()
def write(self, value):
thread_id = thread_get_ident()
self._ensure_thread_buffer(thread_id)
return self._buffers[thread_id].write(
value.decode() if is_bytes(value) else value)
def get_value_and_reset(self):
result = ""
try:
result = self.getvalue()
self.truncate(0)
self.seek(0)
except AttributeError:
pass
return result
class PIOCoreRPC(object):
@staticmethod
def version():
return __version__
@staticmethod
def setup_multithreading_std_streams():
if isinstance(sys.stdout, MultiThreadingStdStream):
return
PIOCoreRPC.thread_stdout = MultiThreadingStdStream(sys.stdout)
PIOCoreRPC.thread_stderr = MultiThreadingStdStream(sys.stderr)
sys.stdout = PIOCoreRPC.thread_stdout
sys.stderr = PIOCoreRPC.thread_stderr
@staticmethod
def call(args, options=None):
return defer.maybeDeferred(PIOCoreRPC._call_generator, args, options)
@staticmethod
@defer.inlineCallbacks
def _call_generator(args, options=None):
for i, arg in enumerate(args):
if isinstance(arg, string_types):
args[i] = arg.encode(get_filesystem_encoding()) if PY2 else arg
else:
args[i] = str(arg)
to_json = "--json-output" in args
try:
if args and args[0] in ("account", "remote"):
result = yield PIOCoreRPC._call_subprocess(args, options)
defer.returnValue(PIOCoreRPC._process_result(result, to_json))
else:
result = yield PIOCoreRPC._call_inline(args, options)
try:
defer.returnValue(
PIOCoreRPC._process_result(result, to_json))
except ValueError:
# fall-back to subprocess method
result = yield PIOCoreRPC._call_subprocess(args, options)
defer.returnValue(
PIOCoreRPC._process_result(result, to_json))
except Exception as e: # pylint: disable=bare-except
raise jsonrpc.exceptions.JSONRPCDispatchException(
code=4003, message="PIO Core Call Error", data=str(e))
@staticmethod
def _call_inline(args, options):
PIOCoreRPC.setup_multithreading_std_streams()
cwd = (options or {}).get("cwd") or os.getcwd()
def _thread_task():
with fs.cd(cwd):
exit_code = __main__.main(["-c"] + args)
return (PIOCoreRPC.thread_stdout.get_value_and_reset(),
PIOCoreRPC.thread_stderr.get_value_and_reset(), exit_code)
return threads.deferToThread(_thread_task)
@staticmethod
def _call_subprocess(args, options):
cwd = (options or {}).get("cwd") or os.getcwd()
return utils.getProcessOutputAndValue(
helpers.get_core_fullpath(),
args,
path=cwd,
env={k: v
for k, v in os.environ.items() if "%" not in k})
@staticmethod
def _process_result(result, to_json=False):
out, err, code = result
text = ("%s\n\n%s" % (out, err)).strip()
if code != 0:
raise Exception(text)
if not to_json:
return text
try:
return json.loads(out)
except ValueError as e:
click.secho("%s => `%s`" % (e, out), fg="red", err=True)
# if PIO Core prints unhandled warnings
for line in out.split("\n"):
line = line.strip()
if not line:
continue
try:
return json.loads(line)
except ValueError:
pass
raise e

View File

@@ -0,0 +1,277 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import absolute_import
import os
import shutil
import time
from os.path import (basename, expanduser, getmtime, isdir, isfile, join,
realpath, sep)
import jsonrpc # pylint: disable=import-error
from platformio import exception, fs
from platformio.commands.home.rpc.handlers.app import AppRPC
from platformio.commands.home.rpc.handlers.piocore import PIOCoreRPC
from platformio.compat import PY2, get_filesystem_encoding
from platformio.ide.projectgenerator import ProjectGenerator
from platformio.managers.platform import PlatformManager
from platformio.project.config import ProjectConfig
from platformio.project.helpers import (get_project_libdeps_dir,
get_project_src_dir,
is_platformio_project)
class ProjectRPC(object):
@staticmethod
def _get_projects(project_dirs=None):
def _get_project_data(project_dir):
data = {"boards": [], "envLibdepsDirs": [], "libExtraDirs": []}
config = ProjectConfig(join(project_dir, "platformio.ini"))
libdeps_dir = get_project_libdeps_dir()
data['libExtraDirs'].extend(
config.get("platformio", "lib_extra_dirs", []))
for section in config.sections():
if not section.startswith("env:"):
continue
data['envLibdepsDirs'].append(join(libdeps_dir, section[4:]))
if config.has_option(section, "board"):
data['boards'].append(config.get(section, "board"))
data['libExtraDirs'].extend(
config.get(section, "lib_extra_dirs", []))
# skip non existing folders and resolve full path
for key in ("envLibdepsDirs", "libExtraDirs"):
data[key] = [
expanduser(d) if d.startswith("~") else realpath(d)
for d in data[key] if isdir(d)
]
return data
def _path_to_name(path):
return (sep).join(path.split(sep)[-2:])
if not project_dirs:
project_dirs = AppRPC.load_state()['storage']['recentProjects']
result = []
pm = PlatformManager()
for project_dir in project_dirs:
data = {}
boards = []
try:
with fs.cd(project_dir):
data = _get_project_data(project_dir)
except exception.PlatformIOProjectException:
continue
for board_id in data.get("boards", []):
name = board_id
try:
name = pm.board_config(board_id)['name']
except exception.PlatformioException:
pass
boards.append({"id": board_id, "name": name})
result.append({
"path":
project_dir,
"name":
_path_to_name(project_dir),
"modified":
int(getmtime(project_dir)),
"boards":
boards,
"envLibStorages": [{
"name": basename(d),
"path": d
} for d in data.get("envLibdepsDirs", [])],
"extraLibStorages": [{
"name": _path_to_name(d),
"path": d
} for d in data.get("libExtraDirs", [])]
})
return result
def get_projects(self, project_dirs=None):
return self._get_projects(project_dirs)
@staticmethod
def get_project_examples():
result = []
for manifest in PlatformManager().get_installed():
examples_dir = join(manifest['__pkg_dir'], "examples")
if not isdir(examples_dir):
continue
items = []
for project_dir, _, __ in os.walk(examples_dir):
project_description = None
try:
config = ProjectConfig(join(project_dir, "platformio.ini"))
config.validate(silent=True)
project_description = config.get("platformio",
"description")
except exception.PlatformIOProjectException:
continue
path_tokens = project_dir.split(sep)
items.append({
"name":
"/".join(path_tokens[path_tokens.index("examples") + 1:]),
"path":
project_dir,
"description":
project_description
})
result.append({
"platform": {
"title": manifest['title'],
"version": manifest['version']
},
"items": sorted(items, key=lambda item: item['name'])
})
return sorted(result, key=lambda data: data['platform']['title'])
def init(self, board, framework, project_dir):
assert project_dir
state = AppRPC.load_state()
if not isdir(project_dir):
os.makedirs(project_dir)
args = ["init", "--board", board]
if framework:
args.extend(["--project-option", "framework = %s" % framework])
if (state['storage']['coreCaller'] and state['storage']['coreCaller']
in ProjectGenerator.get_supported_ides()):
args.extend(["--ide", state['storage']['coreCaller']])
d = PIOCoreRPC.call(args, options={"cwd": project_dir})
d.addCallback(self._generate_project_main, project_dir, framework)
return d
@staticmethod
def _generate_project_main(_, project_dir, framework):
main_content = None
if framework == "arduino":
main_content = "\n".join([
"#include <Arduino.h>",
"",
"void setup() {",
" // put your setup code here, to run once:",
"}",
"",
"void loop() {",
" // put your main code here, to run repeatedly:",
"}"
""
]) # yapf: disable
elif framework == "mbed":
main_content = "\n".join([
"#include <mbed.h>",
"",
"int main() {",
"",
" // put your setup code here, to run once:",
"",
" while(1) {",
" // put your main code here, to run repeatedly:",
" }",
"}",
""
]) # yapf: disable
if not main_content:
return project_dir
with fs.cd(project_dir):
src_dir = get_project_src_dir()
main_path = join(src_dir, "main.cpp")
if isfile(main_path):
return project_dir
if not isdir(src_dir):
os.makedirs(src_dir)
with open(main_path, "w") as f:
f.write(main_content.strip())
return project_dir
def import_arduino(self, board, use_arduino_libs, arduino_project_dir):
board = str(board)
if arduino_project_dir and PY2:
arduino_project_dir = arduino_project_dir.encode(
get_filesystem_encoding())
# don't import PIO Project
if is_platformio_project(arduino_project_dir):
return arduino_project_dir
is_arduino_project = any([
isfile(
join(arduino_project_dir,
"%s.%s" % (basename(arduino_project_dir), ext)))
for ext in ("ino", "pde")
])
if not is_arduino_project:
raise jsonrpc.exceptions.JSONRPCDispatchException(
code=4000,
message="Not an Arduino project: %s" % arduino_project_dir)
state = AppRPC.load_state()
project_dir = join(state['storage']['projectsDir'],
time.strftime("%y%m%d-%H%M%S-") + board)
if not isdir(project_dir):
os.makedirs(project_dir)
args = ["init", "--board", board]
args.extend(["--project-option", "framework = arduino"])
if use_arduino_libs:
args.extend([
"--project-option",
"lib_extra_dirs = ~/Documents/Arduino/libraries"
])
if (state['storage']['coreCaller'] and state['storage']['coreCaller']
in ProjectGenerator.get_supported_ides()):
args.extend(["--ide", state['storage']['coreCaller']])
d = PIOCoreRPC.call(args, options={"cwd": project_dir})
d.addCallback(self._finalize_arduino_import, project_dir,
arduino_project_dir)
return d
@staticmethod
def _finalize_arduino_import(_, project_dir, arduino_project_dir):
with fs.cd(project_dir):
src_dir = get_project_src_dir()
if isdir(src_dir):
fs.rmtree(src_dir)
shutil.copytree(arduino_project_dir, src_dir)
return project_dir
@staticmethod
def import_pio(project_dir):
if not project_dir or not is_platformio_project(project_dir):
raise jsonrpc.exceptions.JSONRPCDispatchException(
code=4001,
message="Not an PlatformIO project: %s" % project_dir)
new_project_dir = join(
AppRPC.load_state()['storage']['projectsDir'],
time.strftime("%y%m%d-%H%M%S-") + basename(project_dir))
shutil.copytree(project_dir, new_project_dir)
state = AppRPC.load_state()
args = ["init"]
if (state['storage']['coreCaller'] and state['storage']['coreCaller']
in ProjectGenerator.get_supported_ides()):
args.extend(["--ide", state['storage']['coreCaller']])
d = PIOCoreRPC.call(args, options={"cwd": new_project_dir})
d.addCallback(lambda _: new_project_dir)
return d

View File

@@ -0,0 +1,77 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# pylint: disable=import-error
import click
import jsonrpc
from autobahn.twisted.websocket import (WebSocketServerFactory,
WebSocketServerProtocol)
from jsonrpc.exceptions import JSONRPCDispatchException
from twisted.internet import defer
from platformio.compat import PY2, dump_json_to_unicode, is_bytes
class JSONRPCServerProtocol(WebSocketServerProtocol):
def onMessage(self, payload, isBinary): # pylint: disable=unused-argument
# click.echo("> %s" % payload)
response = jsonrpc.JSONRPCResponseManager.handle(
payload, self.factory.dispatcher).data
# if error
if "result" not in response:
self.sendJSONResponse(response)
return None
d = defer.maybeDeferred(lambda: response['result'])
d.addCallback(self._callback, response)
d.addErrback(self._errback, response)
return None
def _callback(self, result, response):
response['result'] = result
self.sendJSONResponse(response)
def _errback(self, failure, response):
if isinstance(failure.value, JSONRPCDispatchException):
e = failure.value
else:
e = JSONRPCDispatchException(code=4999,
message=failure.getErrorMessage())
del response["result"]
response['error'] = e.error._data # pylint: disable=protected-access
self.sendJSONResponse(response)
def sendJSONResponse(self, response):
# click.echo("< %s" % response)
if "error" in response:
click.secho("Error: %s" % response['error'], fg="red", err=True)
response = dump_json_to_unicode(response)
if not PY2 and not is_bytes(response):
response = response.encode("utf-8")
self.sendMessage(response)
class JSONRPCServerFactory(WebSocketServerFactory):
protocol = JSONRPCServerProtocol
def __init__(self):
super(JSONRPCServerFactory, self).__init__()
self.dispatcher = jsonrpc.Dispatcher()
def addHandler(self, handler, namespace):
self.dispatcher.build_method_map(handler, prefix="%s." % namespace)

View File

@@ -0,0 +1,30 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from twisted.internet import reactor # pylint: disable=import-error
from twisted.web import static # pylint: disable=import-error
class WebRoot(static.File):
def render_GET(self, request):
if request.args.get("__shutdown__", False):
reactor.stop()
return "Server has been stopped"
request.setHeader("cache-control",
"no-cache, no-store, must-revalidate")
request.setHeader("pragma", "no-cache")
request.setHeader("expires", "0")
return static.File.render_GET(self, request)

View File

@@ -16,15 +16,20 @@
from os import getcwd, makedirs
from os.path import isdir, isfile, join
from shutil import copyfile
import click
from platformio import exception, util
from platformio import exception, fs
from platformio.commands.platform import \
platform_install as cli_platform_install
from platformio.ide.projectgenerator import ProjectGenerator
from platformio.managers.platform import PlatformManager
from platformio.project.config import ProjectConfig
from platformio.project.helpers import (get_project_include_dir,
get_project_lib_dir,
get_project_src_dir,
get_project_test_dir,
is_platformio_project)
def validate_boards(ctx, param, value): # pylint: disable=W0613
@@ -39,22 +44,23 @@ def validate_boards(ctx, param, value): # pylint: disable=W0613
return value
@click.command(
"init", short_help="Initialize PlatformIO project or update existing")
@click.option(
"--project-dir",
"-d",
default=getcwd,
type=click.Path(
exists=True,
file_okay=False,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option(
"-b", "--board", multiple=True, metavar="ID", callback=validate_boards)
@click.option(
"--ide", type=click.Choice(ProjectGenerator.get_supported_ides()))
@click.command("init",
short_help="Initialize PlatformIO project or update existing")
@click.option("--project-dir",
"-d",
default=getcwd,
type=click.Path(exists=True,
file_okay=False,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option("-b",
"--board",
multiple=True,
metavar="ID",
callback=validate_boards)
@click.option("--ide",
type=click.Choice(ProjectGenerator.get_supported_ides()))
@click.option("-O", "--project-option", multiple=True)
@click.option("--env-prefix", default="")
@click.option("-s", "--silent", is_flag=True)
@@ -67,142 +73,199 @@ def cli(
project_option,
env_prefix,
silent):
if not silent:
if project_dir == getcwd():
click.secho(
"\nThe current working directory", fg="yellow", nl=False)
click.secho("\nThe current working directory",
fg="yellow",
nl=False)
click.secho(" %s " % project_dir, fg="cyan", nl=False)
click.secho(
"will be used for project.\n"
"You can specify another project directory via\n"
"`platformio init -d %PATH_TO_THE_PROJECT_DIR%` command.",
fg="yellow")
click.secho("will be used for the project.", fg="yellow")
click.echo("")
click.echo("The next files/directories have been created in %s" %
click.style(project_dir, fg="cyan"))
click.echo("%s - Project Configuration File" % click.style(
"platformio.ini", fg="cyan"))
click.echo(
"%s - Put your source files here" % click.style("src", fg="cyan"))
click.echo("%s - Put project header files here" %
click.style("include", fg="cyan"))
click.echo("%s - Put here project specific (private) libraries" %
click.style("lib", fg="cyan"))
click.echo("%s - Put project source files here" %
click.style("src", fg="cyan"))
click.echo("%s - Project Configuration File" %
click.style("platformio.ini", fg="cyan"))
init_base_project(project_dir)
is_new_project = not is_platformio_project(project_dir)
if is_new_project:
init_base_project(project_dir)
if board:
fill_project_envs(ctx, project_dir, board, project_option, env_prefix,
ide is not None)
if ide:
env_name = get_best_envname(project_dir, board)
if not env_name:
raise exception.BoardNotDefined()
pg = ProjectGenerator(project_dir, ide, env_name)
pg = ProjectGenerator(project_dir, ide, board)
pg.generate()
if not silent:
if is_new_project:
init_ci_conf(project_dir)
init_cvs_ignore(project_dir)
if silent:
return
if ide:
click.secho(
"\nProject has been successfully initialized!\nUseful commands:\n"
"`platformio run` - process/build project from the current "
"directory\n"
"`platformio run --target upload` or `platformio run -t upload` "
"- upload firmware to embedded board\n"
"`platformio run --target clean` - clean project (remove compiled "
"files)\n"
"`platformio run --help` - additional information",
"\nProject has been successfully %s including configuration files "
"for `%s` IDE." %
("initialized" if is_new_project else "updated", ide),
fg="green")
else:
click.secho(
"\nProject has been successfully %s! Useful commands:\n"
"`pio run` - process/build project from the current directory\n"
"`pio run --target upload` or `pio run -t upload` "
"- upload firmware to a target\n"
"`pio run --target clean` - clean project (remove compiled files)"
"\n`pio run --help` - additional information" %
("initialized" if is_new_project else "updated"),
fg="green")
def get_best_envname(project_dir, boards=None):
config = util.load_project_config(project_dir)
env_default = None
if config.has_option("platformio", "env_default"):
env_default = config.get("platformio",
"env_default").split(", ")[0].strip()
if env_default:
return env_default
for section in config.sections():
if not section.startswith("env:"):
continue
elif config.has_option(section, "board") and (not boards or config.get(
section, "board") in boards):
return section[4:]
return None
def init_base_project(project_dir):
if not util.is_platformio_project(project_dir):
copyfile(
join(util.get_source_dir(), "projectconftpl.ini"),
join(project_dir, "platformio.ini"))
ProjectConfig(join(project_dir, "platformio.ini")).save()
with fs.cd(project_dir):
dir_to_readme = [
(get_project_src_dir(), None),
(get_project_include_dir(), init_include_readme),
(get_project_lib_dir(), init_lib_readme),
(get_project_test_dir(), init_test_readme),
]
for (path, cb) in dir_to_readme:
if isdir(path):
continue
makedirs(path)
if cb:
cb(path)
lib_dir = join(project_dir, "lib")
src_dir = join(project_dir, "src")
config = util.load_project_config(project_dir)
if config.has_option("platformio", "src_dir"):
src_dir = join(project_dir, config.get("platformio", "src_dir"))
for d in (src_dir, lib_dir):
if not isdir(d):
makedirs(d)
def init_include_readme(include_dir):
with open(join(include_dir, "README"), "w") as f:
f.write("""
This directory is intended for project header files.
init_lib_readme(lib_dir)
init_ci_conf(project_dir)
init_cvs_ignore(project_dir)
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
""")
def init_lib_readme(lib_dir):
if isfile(join(lib_dir, "readme.txt")):
return
with open(join(lib_dir, "readme.txt"), "w") as f:
with open(join(lib_dir, "README"), "w") as f:
f.write("""
This directory is intended for the project specific (private) libraries.
PlatformIO will compile them to static libraries and link to executable file.
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in separate directory, like
"lib/private_lib/[here are source files]".
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see how can be organized `Foo` and `Bar` libraries:
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |- readme.txt --> THIS FILE
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
Then in `src/main.c` you should use:
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
// rest H/C/CPP code
int main (void)
{
...
}
PlatformIO will find your libraries automatically, configure preprocessor's
include paths and build them.
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- http://docs.platformio.org/page/librarymanager/ldf.html
- https://docs.platformio.org/page/librarymanager/ldf.html
""")
def init_test_readme(test_dir):
with open(join(test_dir, "README"), "w") as f:
f.write("""
This directory is intended for PIO Unit Testing and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html
""")
def init_ci_conf(project_dir):
if isfile(join(project_dir, ".travis.yml")):
conf_path = join(project_dir, ".travis.yml")
if isfile(conf_path):
return
with open(join(project_dir, ".travis.yml"), "w") as f:
with open(conf_path, "w") as f:
f.write("""# Continuous Integration (CI) is the practice, in software
# engineering, of merging all developer working copies with a shared mainline
# several times a day < http://docs.platformio.org/page/ci/index.html >
# several times a day < https://docs.platformio.org/page/ci/index.html >
#
# Documentation:
#
@@ -210,13 +273,13 @@ def init_ci_conf(project_dir):
# < https://docs.travis-ci.com/user/integration/platformio/ >
#
# * PlatformIO integration with Travis CI
# < http://docs.platformio.org/page/ci/travis.html >
# < https://docs.platformio.org/page/ci/travis.html >
#
# * User Guide for `platformio ci` command
# < http://docs.platformio.org/page/userguide/cmd_ci.html >
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
#
#
# Please choice one of the following templates (proposed below) and uncomment
# Please choose one of the following templates (proposed below) and uncomment
# it (remove "# " before each line) or use own configuration according to the
# Travis CI documentation (see above).
#
@@ -237,13 +300,14 @@ def init_ci_conf(project_dir):
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio run
#
# Template #2: The project is intended to by used as a library with examples
# Template #2: The project is intended to be used as a library with examples.
#
# language: python
@@ -262,6 +326,7 @@ def init_ci_conf(project_dir):
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
@@ -269,32 +334,18 @@ def init_ci_conf(project_dir):
def init_cvs_ignore(project_dir):
ignore_path = join(project_dir, ".gitignore")
default = [".pioenvs\n", ".piolibdeps\n"]
current = []
modified = False
if isfile(ignore_path):
with open(ignore_path) as fp:
current = fp.readlines()
if current and not current[-1].endswith("\n"):
current[-1] += "\n"
for d in default:
if d not in current:
modified = True
current.append(d)
if not modified:
conf_path = join(project_dir, ".gitignore")
if isfile(conf_path):
return
with open(ignore_path, "w") as fp:
fp.writelines(current)
with open(conf_path, "w") as fp:
fp.write(".pio\n")
def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix,
force_download):
content = []
config = ProjectConfig(join(project_dir, "platformio.ini"),
parse_extra=False)
used_boards = []
used_platforms = []
config = util.load_project_config(project_dir)
for section in config.sections():
cond = [
section.startswith("env:"),
@@ -304,12 +355,15 @@ def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix,
used_boards.append(config.get(section, "board"))
pm = PlatformManager()
used_platforms = []
modified = False
for id_ in board_ids:
board_config = pm.board_config(id_)
used_platforms.append(board_config['platform'])
if id_ in used_boards:
continue
used_boards.append(id_)
modified = True
envopts = {"platform": board_config['platform'], "board": id_}
# find default framework for board
@@ -323,20 +377,18 @@ def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix,
_name, _value = item.split("=", 1)
envopts[_name.strip()] = _value.strip()
content.append("")
content.append("[env:%s%s]" % (env_prefix, id_))
for name, value in envopts.items():
content.append("%s = %s" % (name, value))
section = "env:%s%s" % (env_prefix, id_)
config.add_section(section)
for option, value in envopts.items():
config.set(section, option, value)
if force_download and used_platforms:
_install_dependent_platforms(ctx, used_platforms)
if not content:
return
with open(join(project_dir, "platformio.ini"), "a") as f:
content.append("")
f.write("\n".join(content))
if modified:
config.save()
config.reset_instances()
def _install_dependent_platforms(ctx, platforms):
@@ -345,6 +397,5 @@ def _install_dependent_platforms(ctx, platforms):
]
if set(platforms) <= set(installed_platforms):
return
ctx.invoke(
cli_platform_install,
platforms=list(set(platforms) - set(installed_platforms)))
ctx.invoke(cli_platform_install,
platforms=list(set(platforms) - set(installed_platforms)))

View File

@@ -14,197 +14,309 @@
# pylint: disable=too-many-branches, too-many-locals
import json
import time
from os.path import isdir, join
from time import sleep
from urllib import quote
import arrow
import click
import semantic_version
from tabulate import tabulate
from platformio import exception, util
from platformio.managers.lib import LibraryManager
from platformio.managers.platform import PlatformFactory, PlatformManager
from platformio.util import get_api_result
from platformio import exception, fs, util
from platformio.commands import PlatformioCLI
from platformio.compat import dump_json_to_unicode
from platformio.managers.lib import (LibraryManager, get_builtin_libs,
is_builtin_lib)
from platformio.proc import is_ci
from platformio.project.config import ProjectConfig
from platformio.project.helpers import (get_project_dir,
get_project_global_lib_dir,
get_project_libdeps_dir,
is_platformio_project)
try:
from urllib.parse import quote
except ImportError:
from urllib import quote
CTX_META_INPUT_DIRS_KEY = __name__ + ".input_dirs"
CTX_META_PROJECT_ENVIRONMENTS_KEY = __name__ + ".project_environments"
CTX_META_STORAGE_DIRS_KEY = __name__ + ".storage_dirs"
CTX_META_STORAGE_LIBDEPS_KEY = __name__ + ".storage_lib_deps"
@click.group(short_help="Library Manager")
@click.option("-d",
"--storage-dir",
multiple=True,
default=None,
type=click.Path(exists=True,
file_okay=False,
dir_okay=True,
writable=True,
resolve_path=True),
help="Manage custom library storage")
@click.option("-g",
"--global",
is_flag=True,
help="Manage global PlatformIO library storage")
@click.option(
"-g",
"--global",
is_flag=True,
help="Manage global PlatformIO"
" library storage `%s`" % join(util.get_home_dir(), "lib"))
@click.option(
"-d",
"--storage-dir",
default=None,
type=click.Path(
exists=True,
file_okay=False,
dir_okay=True,
writable=True,
resolve_path=True),
help="Manage custom library storage")
"-e",
"--environment",
multiple=True,
help=("Manage libraries for the specific project build environments "
"declared in `platformio.ini`"))
@click.pass_context
def cli(ctx, **options):
non_storage_cmds = ("search", "show", "register", "stats", "builtin")
storage_cmds = ("install", "uninstall", "update", "list")
# skip commands that don't need storage folder
if ctx.invoked_subcommand in non_storage_cmds or \
if ctx.invoked_subcommand not in storage_cmds or \
(len(ctx.args) == 2 and ctx.args[1] in ("-h", "--help")):
return
storage_dir = options['storage_dir']
if not storage_dir:
if options['global']:
storage_dir = join(util.get_home_dir(), "lib")
elif util.is_platformio_project():
storage_dir = util.get_projectlibdeps_dir()
elif util.is_ci():
storage_dir = join(util.get_home_dir(), "lib")
storage_dirs = list(options['storage_dir'])
if options['global']:
storage_dirs.append(get_project_global_lib_dir())
if not storage_dirs:
if is_platformio_project():
storage_dirs = [get_project_dir()]
elif is_ci():
storage_dirs = [get_project_global_lib_dir()]
click.secho(
"Warning! Global library storage is used automatically. "
"Please use `platformio lib --global %s` command to remove "
"this warning." % ctx.invoked_subcommand,
fg="yellow")
if not storage_dir and not util.is_platformio_project():
raise exception.NotGlobalLibDir(util.get_project_dir(),
join(util.get_home_dir(), "lib"),
if not storage_dirs:
raise exception.NotGlobalLibDir(get_project_dir(),
get_project_global_lib_dir(),
ctx.invoked_subcommand)
ctx.obj = LibraryManager(storage_dir)
if "--json-output" not in ctx.args:
click.echo("Library Storage: " + storage_dir)
in_silence = PlatformioCLI.in_silence()
ctx.meta[CTX_META_PROJECT_ENVIRONMENTS_KEY] = options['environment']
ctx.meta[CTX_META_INPUT_DIRS_KEY] = storage_dirs
ctx.meta[CTX_META_STORAGE_DIRS_KEY] = []
ctx.meta[CTX_META_STORAGE_LIBDEPS_KEY] = {}
for storage_dir in storage_dirs:
if not is_platformio_project(storage_dir):
ctx.meta[CTX_META_STORAGE_DIRS_KEY].append(storage_dir)
continue
with fs.cd(storage_dir):
libdeps_dir = get_project_libdeps_dir()
config = ProjectConfig.get_instance(join(storage_dir,
"platformio.ini"))
config.validate(options['environment'], silent=in_silence)
for env in config.envs():
if options['environment'] and env not in options['environment']:
continue
storage_dir = join(libdeps_dir, env)
ctx.meta[CTX_META_STORAGE_DIRS_KEY].append(storage_dir)
ctx.meta[CTX_META_STORAGE_LIBDEPS_KEY][storage_dir] = config.get(
"env:" + env, "lib_deps", [])
@cli.command("install", short_help="Install library")
@click.argument("libraries", required=False, nargs=-1, metavar="[LIBRARY...]")
# @click.option(
# "--save",
# is_flag=True,
# help="Save installed libraries into the project's platformio.ini "
# "library dependencies")
@click.option(
"-s", "--silent", is_flag=True, help="Suppress progress reporting")
@click.option(
"--interactive",
"--save",
is_flag=True,
help="Allow to make a choice for all prompts")
@click.pass_obj
def lib_install(lm, libraries, silent, interactive):
# @TODO "save" option
for library in libraries:
lm.install(library, silent=silent, interactive=interactive)
help="Save installed libraries into the `platformio.ini` dependency list")
@click.option("-s",
"--silent",
is_flag=True,
help="Suppress progress reporting")
@click.option("--interactive",
is_flag=True,
help="Allow to make a choice for all prompts")
@click.option("-f",
"--force",
is_flag=True,
help="Reinstall/redownload library if exists")
@click.pass_context
def lib_install( # pylint: disable=too-many-arguments
ctx, libraries, save, silent, interactive, force):
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
storage_libdeps = ctx.meta.get(CTX_META_STORAGE_LIBDEPS_KEY, [])
installed_manifests = {}
for storage_dir in storage_dirs:
if not silent and (libraries or storage_dir in storage_libdeps):
print_storage_header(storage_dirs, storage_dir)
lm = LibraryManager(storage_dir)
if libraries:
for library in libraries:
pkg_dir = lm.install(library,
silent=silent,
interactive=interactive,
force=force)
installed_manifests[library] = lm.load_manifest(pkg_dir)
elif storage_dir in storage_libdeps:
builtin_lib_storages = None
for library in storage_libdeps[storage_dir]:
try:
pkg_dir = lm.install(library,
silent=silent,
interactive=interactive,
force=force)
installed_manifests[library] = lm.load_manifest(pkg_dir)
except exception.LibNotFound as e:
if builtin_lib_storages is None:
builtin_lib_storages = get_builtin_libs()
if not silent or not is_builtin_lib(
builtin_lib_storages, library):
click.secho("Warning! %s" % e, fg="yellow")
if not save or not libraries:
return
input_dirs = ctx.meta.get(CTX_META_INPUT_DIRS_KEY, [])
project_environments = ctx.meta[CTX_META_PROJECT_ENVIRONMENTS_KEY]
for input_dir in input_dirs:
config = ProjectConfig.get_instance(join(input_dir, "platformio.ini"))
config.validate(project_environments)
for env in config.envs():
if project_environments and env not in project_environments:
continue
config.expand_interpolations = False
lib_deps = config.get("env:" + env, "lib_deps", [])
for library in libraries:
if library in lib_deps:
continue
manifest = installed_manifests[library]
try:
assert library.lower() == manifest['name'].lower()
assert semantic_version.Version(manifest['version'])
lib_deps.append("{name}@^{version}".format(**manifest))
except (AssertionError, ValueError):
lib_deps.append(library)
config.set("env:" + env, "lib_deps", lib_deps)
config.save()
@cli.command("uninstall", short_help="Uninstall libraries")
@click.argument("libraries", nargs=-1, metavar="[LIBRARY...]")
@click.pass_obj
def lib_uninstall(lm, libraries):
for library in libraries:
lm.uninstall(library)
@click.pass_context
def lib_uninstall(ctx, libraries):
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
for storage_dir in storage_dirs:
print_storage_header(storage_dirs, storage_dir)
lm = LibraryManager(storage_dir)
for library in libraries:
lm.uninstall(library)
@cli.command("update", short_help="Update installed libraries")
@click.argument("libraries", required=False, nargs=-1, metavar="[LIBRARY...]")
@click.option(
"-c",
"--only-check",
is_flag=True,
help="Do not update, only check for new version")
@click.option("-c",
"--only-check",
is_flag=True,
help="DEPRECATED. Please use `--dry-run` instead")
@click.option("--dry-run",
is_flag=True,
help="Do not update, only check for the new versions")
@click.option("--json-output", is_flag=True)
@click.pass_obj
def lib_update(lm, libraries, only_check, json_output):
if not libraries:
libraries = [manifest['__pkg_dir'] for manifest in lm.get_installed()]
@click.pass_context
def lib_update(ctx, libraries, only_check, dry_run, json_output):
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
only_check = dry_run or only_check
json_result = {}
for storage_dir in storage_dirs:
if not json_output:
print_storage_header(storage_dirs, storage_dir)
lm = LibraryManager(storage_dir)
if only_check and json_output:
result = []
for library in libraries:
pkg_dir = library if isdir(library) else None
requirements = None
url = None
if not pkg_dir:
name, requirements, url = lm.parse_pkg_input(library)
pkg_dir = lm.get_package_dir(name, requirements, url)
if not pkg_dir:
continue
latest = lm.outdated(pkg_dir, requirements)
if not latest:
continue
manifest = lm.load_manifest(pkg_dir)
manifest['versionLatest'] = latest
result.append(manifest)
return click.echo(json.dumps(result))
else:
for library in libraries:
lm.update(library, only_check=only_check)
_libraries = libraries
if not _libraries:
_libraries = [
manifest['__pkg_dir'] for manifest in lm.get_installed()
]
def print_lib_item(item):
click.secho(item['name'], fg="cyan")
click.echo("=" * len(item['name']))
if "id" in item:
click.secho("#ID: %d" % item['id'], bold=True)
if "description" in item or "url" in item:
click.echo(item.get("description", item.get("url", "")))
click.echo()
for key in ("version", "homepage", "license", "keywords"):
if key not in item or not item[key]:
continue
if isinstance(item[key], list):
click.echo("%s: %s" % (key.title(), ", ".join(item[key])))
if only_check and json_output:
result = []
for library in _libraries:
pkg_dir = library if isdir(library) else None
requirements = None
url = None
if not pkg_dir:
name, requirements, url = lm.parse_pkg_uri(library)
pkg_dir = lm.get_package_dir(name, requirements, url)
if not pkg_dir:
continue
latest = lm.outdated(pkg_dir, requirements)
if not latest:
continue
manifest = lm.load_manifest(pkg_dir)
manifest['versionLatest'] = latest
result.append(manifest)
json_result[storage_dir] = result
else:
click.echo("%s: %s" % (key.title(), item[key]))
for library in _libraries:
lm.update(library, only_check=only_check)
for key in ("frameworks", "platforms"):
if key not in item:
continue
click.echo("Compatible %s: %s" % (key, ", ".join(
[i['title'] if isinstance(i, dict) else i for i in item[key]])))
if json_output:
return click.echo(
dump_json_to_unicode(json_result[storage_dirs[0]]
if len(storage_dirs) == 1 else json_result))
if "authors" in item or "authornames" in item:
click.echo("Authors: %s" % ", ".join(
item.get("authornames",
[a.get("name", "") for a in item.get("authors", [])])))
return True
if "__src_url" in item:
click.secho("Source: %s" % item['__src_url'])
click.echo()
@cli.command("list", short_help="List installed libraries")
@click.option("--json-output", is_flag=True)
@click.pass_context
def lib_list(ctx, json_output):
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
json_result = {}
for storage_dir in storage_dirs:
if not json_output:
print_storage_header(storage_dirs, storage_dir)
lm = LibraryManager(storage_dir)
items = lm.get_installed()
if json_output:
json_result[storage_dir] = items
elif items:
for item in sorted(items, key=lambda i: i['name']):
print_lib_item(item)
else:
click.echo("No items found")
if json_output:
return click.echo(
dump_json_to_unicode(json_result[storage_dirs[0]]
if len(storage_dirs) == 1 else json_result))
return True
@cli.command("search", short_help="Search for a library")
@click.argument("query", required=False, nargs=-1)
@click.option("--json-output", is_flag=True)
@click.option("--page", type=click.INT, default=1)
@click.option("--id", multiple=True)
@click.option("-n", "--name", multiple=True)
@click.option("-a", "--author", multiple=True)
@click.option("-k", "--keyword", multiple=True)
@click.option("-f", "--framework", multiple=True)
@click.option("-p", "--platform", multiple=True)
@click.option("-i", "--header", multiple=True)
@click.option(
"--noninteractive",
is_flag=True,
help="Do not prompt, automatically paginate with delay")
@click.option("--noninteractive",
is_flag=True,
help="Do not prompt, automatically paginate with delay")
def lib_search(query, json_output, page, noninteractive, **filters):
if not query:
query = []
if not isinstance(query, list):
query = list(query)
for key, values in filters.iteritems():
for key, values in filters.items():
for value in values:
query.append('%s:"%s"' % (key, value))
result = get_api_result(
"/v2/lib/search",
dict(query=" ".join(query), page=page),
cache_valid="3d")
result = util.get_api_result("/v2/lib/search",
dict(query=" ".join(query), page=page),
cache_valid="1d")
if json_output:
click.echo(json.dumps(result))
click.echo(dump_json_to_unicode(result))
return
if result['total'] == 0:
@@ -219,72 +331,35 @@ def lib_search(query, json_output, page, noninteractive, **filters):
click.echo("For more examples and advanced search syntax, "
"please use documentation:")
click.secho(
"http://docs.platformio.org/page/userguide/lib/cmd_search.html\n",
"https://docs.platformio.org/page/userguide/lib/cmd_search.html\n",
fg="cyan")
return
click.secho(
"Found %d libraries:\n" % result['total'],
fg="green" if result['total'] else "yellow")
click.secho("Found %d libraries:\n" % result['total'],
fg="green" if result['total'] else "yellow")
while True:
for item in result['items']:
print_lib_item(item)
if (int(result['page']) * int(result['perpage']) >=
int(result['total'])):
if (int(result['page']) * int(result['perpage']) >= int(
result['total'])):
break
if noninteractive:
click.echo()
click.secho(
"Loading next %d libraries... Press Ctrl+C to stop!" %
result['perpage'],
fg="yellow")
click.secho("Loading next %d libraries... Press Ctrl+C to stop!" %
result['perpage'],
fg="yellow")
click.echo()
sleep(5)
time.sleep(5)
elif not click.confirm("Show next libraries?"):
break
result = get_api_result(
"/v2/lib/search",
{"query": " ".join(query),
"page": int(result['page']) + 1},
cache_valid="3d")
@cli.command("list", short_help="List installed libraries")
@click.option("--json-output", is_flag=True)
@click.pass_obj
def lib_list(lm, json_output):
items = lm.get_installed()
if json_output:
return click.echo(json.dumps(items))
if not items:
return
for item in sorted(items, key=lambda i: i['name']):
print_lib_item(item)
@util.memoized
def get_builtin_libs(storage_names=None):
items = []
storage_names = storage_names or []
pm = PlatformManager()
for manifest in pm.get_installed():
p = PlatformFactory.newPlatform(manifest['__pkg_dir'])
for storage in p.get_lib_storages():
if storage_names and storage['name'] not in storage_names:
continue
lm = LibraryManager(storage['path'])
items.append({
"name": storage['name'],
"path": storage['path'],
"items": lm.get_installed()
})
return items
result = util.get_api_result("/v2/lib/search", {
"query": " ".join(query),
"page": int(result['page']) + 1
},
cache_valid="1d")
@cli.command("builtin", short_help="List built-in libraries")
@@ -293,7 +368,7 @@ def get_builtin_libs(storage_names=None):
def lib_builtin(storage, json_output):
items = get_builtin_libs(storage)
if json_output:
return click.echo(json.dumps(items))
return click.echo(dump_json_to_unicode(items))
for storage_ in items:
if not storage_['items']:
@@ -305,18 +380,24 @@ def lib_builtin(storage, json_output):
for item in sorted(storage_['items'], key=lambda i: i['name']):
print_lib_item(item)
return True
@cli.command("show", short_help="Show detailed info about a library")
@click.argument("library", metavar="[LIBRARY]")
@click.option("--json-output", is_flag=True)
def lib_show(library, json_output):
lm = LibraryManager()
name, requirements, _ = lm.parse_pkg_input(library)
lib_id = lm.get_pkg_id_by_name(
name, requirements, silent=json_output, interactive=not json_output)
lib = get_api_result("/lib/info/%d" % lib_id, cache_valid="1d")
name, requirements, _ = lm.parse_pkg_uri(library)
lib_id = lm.search_lib_id({
"name": name,
"requirements": requirements
},
silent=json_output,
interactive=not json_output)
lib = util.get_api_result("/lib/info/%d" % lib_id, cache_valid="1d")
if json_output:
return click.echo(json.dumps(lib))
return click.echo(dump_json_to_unicode(lib))
click.secho(lib['name'], fg="cyan")
click.echo("=" * len(lib['name']))
@@ -324,9 +405,10 @@ def lib_show(library, json_output):
click.echo(lib['description'])
click.echo()
click.echo("Version: %s, released %s" %
(lib['version']['name'],
arrow.get(lib['version']['released']).humanize()))
click.echo(
"Version: %s, released %s" %
(lib['version']['name'],
time.strftime("%c", util.parse_date(lib['version']['released']))))
click.echo("Manifest: %s" % lib['confurl'])
for key in ("homepage", "repository", "license"):
if key not in lib or not lib[key]:
@@ -362,7 +444,8 @@ def lib_show(library, json_output):
blocks.append(("Headers", lib['headers']))
blocks.append(("Examples", lib['examples']))
blocks.append(("Versions", [
"%s, released %s" % (v['name'], arrow.get(v['released']).humanize())
"%s, released %s" %
(v['name'], time.strftime("%c", util.parse_date(v['released'])))
for v in lib['versions']
]))
blocks.append(("Unique Downloads", [
@@ -378,90 +461,115 @@ def lib_show(library, json_output):
for row in rows:
click.echo(row)
return True
@cli.command("register", short_help="Register a new library")
@click.argument("config_url")
def lib_register(config_url):
if (not config_url.startswith("http://") and
not config_url.startswith("https://")):
if (not config_url.startswith("http://")
and not config_url.startswith("https://")):
raise exception.InvalidLibConfURL(config_url)
result = get_api_result("/lib/register", data=dict(config_url=config_url))
result = util.get_api_result("/lib/register",
data=dict(config_url=config_url))
if "message" in result and result['message']:
click.secho(
result['message'],
fg="green"
if "successed" in result and result['successed'] else "red")
click.secho(result['message'],
fg="green" if "successed" in result and result['successed']
else "red")
@cli.command("stats", short_help="Library Registry Statistics")
@click.option("--json-output", is_flag=True)
def lib_stats(json_output):
result = get_api_result("/lib/stats", cache_valid="1h")
result = util.get_api_result("/lib/stats", cache_valid="1h")
if json_output:
return click.echo(json.dumps(result))
printitem_tpl = "{name:<33} {url}"
printitemdate_tpl = "{name:<33} {date:23} {url}"
def _print_title(title):
click.secho(title.upper(), bold=True)
click.echo("*" * len(title))
def _print_header(with_date=False):
click.echo((printitemdate_tpl if with_date else printitem_tpl).format(
name=click.style("Name", fg="cyan"),
date="Date",
url=click.style("Url", fg="blue")))
terminal_width, _ = click.get_terminal_size()
click.echo("-" * terminal_width)
def _print_lib_item(item):
click.echo((printitemdate_tpl
if "date" in item else printitem_tpl).format(
name=click.style(item['name'], fg="cyan"),
date=str(
arrow.get(item['date']).humanize()
if "date" in item else ""),
url=click.style(
"http://platformio.org/lib/show/%s/%s" %
(item['id'], quote(item['name'])),
fg="blue")))
def _print_tag_item(name):
click.echo(
printitem_tpl.format(
name=click.style(name, fg="cyan"),
url=click.style(
"http://platformio.org/lib/search?query=" + quote(
"keyword:%s" % name),
fg="blue")))
return click.echo(dump_json_to_unicode(result))
for key in ("updated", "added"):
_print_title("Recently " + key)
_print_header(with_date=True)
for item in result.get(key, []):
_print_lib_item(item)
tabular_data = [(click.style(item['name'], fg="cyan"),
time.strftime("%c", util.parse_date(item['date'])),
"https://platformio.org/lib/show/%s/%s" %
(item['id'], quote(item['name'])))
for item in result.get(key, [])]
table = tabulate(tabular_data,
headers=[
click.style("RECENTLY " + key.upper(), bold=True),
"Date", "URL"
])
click.echo(table)
click.echo()
_print_title("Recent keywords")
_print_header(with_date=False)
for item in result.get("lastkeywords"):
_print_tag_item(item)
click.echo()
_print_title("Popular keywords")
_print_header(with_date=False)
for item in result.get("topkeywords"):
_print_tag_item(item)
click.echo()
for key in ("lastkeywords", "topkeywords"):
tabular_data = [(click.style(name, fg="cyan"),
"https://platformio.org/lib/search?query=" +
quote("keyword:%s" % name))
for name in result.get(key, [])]
table = tabulate(
tabular_data,
headers=[
click.style(
("RECENT" if key == "lastkeywords" else "POPULAR") +
" KEYWORDS",
bold=True), "URL"
])
click.echo(table)
click.echo()
for key, title in (("dlday", "Today"), ("dlweek", "Week"), ("dlmonth",
"Month")):
_print_title("Featured: " + title)
_print_header(with_date=False)
for item in result.get(key, []):
_print_lib_item(item)
tabular_data = [(click.style(item['name'], fg="cyan"),
"https://platformio.org/lib/show/%s/%s" %
(item['id'], quote(item['name'])))
for item in result.get(key, [])]
table = tabulate(tabular_data,
headers=[
click.style("FEATURED: " + title.upper(),
bold=True), "URL"
])
click.echo(table)
click.echo()
return True
def print_storage_header(storage_dirs, storage_dir):
if storage_dirs and storage_dirs[0] != storage_dir:
click.echo("")
click.echo(
click.style("Library Storage: ", bold=True) +
click.style(storage_dir, fg="blue"))
def print_lib_item(item):
click.secho(item['name'], fg="cyan")
click.echo("=" * len(item['name']))
if "id" in item:
click.secho("#ID: %d" % item['id'], bold=True)
if "description" in item or "url" in item:
click.echo(item.get("description", item.get("url", "")))
click.echo()
for key in ("version", "homepage", "license", "keywords"):
if key not in item or not item[key]:
continue
if isinstance(item[key], list):
click.echo("%s: %s" % (key.title(), ", ".join(item[key])))
else:
click.echo("%s: %s" % (key.title(), item[key]))
for key in ("frameworks", "platforms"):
if key not in item:
continue
click.echo("Compatible %s: %s" % (key, ", ".join(
[i['title'] if isinstance(i, dict) else i for i in item[key]])))
if "authors" in item or "authornames" in item:
click.echo("Authors: %s" % ", ".join(
item.get("authornames",
[a.get("name", "") for a in item.get("authors", [])])))
if "__src_url" in item:
click.secho("Source: %s" % item['__src_url'])
click.echo()

View File

@@ -12,13 +12,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import json
from os.path import dirname, isdir
import click
from platformio import app, exception, util
from platformio.commands.boards import print_boards
from platformio.compat import dump_json_to_unicode
from platformio.managers.platform import PlatformFactory, PlatformManager
@@ -29,9 +29,9 @@ def cli():
def _print_platforms(platforms):
for platform in platforms:
click.echo("{name} ~ {title}".format(
name=click.style(platform['name'], fg="cyan"),
title=platform['title']))
click.echo("{name} ~ {title}".format(name=click.style(platform['name'],
fg="cyan"),
title=platform['title']))
click.echo("=" * (3 + len(platform['name'] + platform['title'])))
click.echo(platform['description'])
click.echo()
@@ -42,30 +42,22 @@ def _print_platforms(platforms):
if "packages" in platform:
click.echo("Packages: %s" % ", ".join(platform['packages']))
if "version" in platform:
click.echo("Version: " + platform['version'])
if "__src_url" in platform:
click.echo("Version: #%s (%s)" %
(platform['version'], platform['__src_url']))
else:
click.echo("Version: " + platform['version'])
click.echo()
def _get_registry_platforms():
platforms = util.get_api_result("/platforms", cache_valid="30d")
platforms = util.get_api_result("/platforms", cache_valid="7d")
pm = PlatformManager()
for platform in platforms or []:
platform['versions'] = pm.get_all_repo_versions(platform['name'])
return platforms
def _original_version(version):
if version.count(".") != 2:
return None
_, y = version.split(".")[:2]
if int(y) < 100:
return None
if len(y) % 2 != 0:
y = "0" + y
parts = [str(int(y[i * 2:i * 2 + 2])) for i in range(len(y) / 2)]
return ".".join(parts)
def _get_platform_data(*args, **kwargs):
try:
return _get_installed_platform_data(*args, **kwargs)
@@ -77,18 +69,18 @@ def _get_installed_platform_data(platform,
with_boards=True,
expose_packages=True):
p = PlatformFactory.newPlatform(platform)
data = dict(
name=p.name,
title=p.title,
description=p.description,
version=p.version,
homepage=p.homepage,
repository=p.repository_url,
url=p.vendor_url,
license=p.license,
forDesktop=not p.is_embedded(),
frameworks=sorted(p.frameworks.keys() if p.frameworks else []),
packages=p.packages.keys() if p.packages else [])
data = dict(name=p.name,
title=p.title,
description=p.description,
version=p.version,
homepage=p.homepage,
repository=p.repository_url,
url=p.vendor_url,
docs=p.docs_url,
license=p.license,
forDesktop=not p.is_embedded(),
frameworks=sorted(list(p.frameworks) if p.frameworks else []),
packages=list(p.packages) if p.packages else [])
# if dump to API
# del data['version']
@@ -110,18 +102,17 @@ def _get_installed_platform_data(platform,
data['packages'] = []
installed_pkgs = p.get_installed_packages()
for name, opts in p.packages.items():
item = dict(
name=name,
type=p.get_package_type(name),
requirements=opts.get("version"),
optional=opts.get("optional") is True)
item = dict(name=name,
type=p.get_package_type(name),
requirements=opts.get("version"),
optional=opts.get("optional") is True)
if name in installed_pkgs:
for key, value in installed_pkgs[name].items():
if key not in ("url", "version", "description"):
continue
item[key] = value
if key == "version":
item["originalVersion"] = _original_version(value)
item["originalVersion"] = util.get_original_version(value)
data['packages'].append(item)
return data
@@ -140,18 +131,17 @@ def _get_registry_platform_data( # pylint: disable=unused-argument
if not _data:
return None
data = dict(
name=_data['name'],
title=_data['title'],
description=_data['description'],
homepage=_data['homepage'],
repository=_data['repository'],
url=_data['url'],
license=_data['license'],
forDesktop=_data['forDesktop'],
frameworks=_data['frameworks'],
packages=_data['packages'],
versions=_data['versions'])
data = dict(name=_data['name'],
title=_data['title'],
description=_data['description'],
homepage=_data['homepage'],
repository=_data['repository'],
url=_data['url'],
license=_data['license'],
forDesktop=_data['forDesktop'],
frameworks=_data['frameworks'],
packages=_data['packages'],
versions=_data['versions'])
if with_boards:
data['boards'] = [
@@ -170,15 +160,16 @@ def platform_search(query, json_output):
for platform in _get_registry_platforms():
if query == "all":
query = ""
search_data = json.dumps(platform)
search_data = dump_json_to_unicode(platform)
if query and query.lower() not in search_data.lower():
continue
platforms.append(
_get_registry_platform_data(
platform['name'], with_boards=False, expose_packages=False))
_get_registry_platform_data(platform['name'],
with_boards=False,
expose_packages=False))
if json_output:
click.echo(json.dumps(platforms))
click.echo(dump_json_to_unicode(platforms))
else:
_print_platforms(platforms)
@@ -188,14 +179,14 @@ def platform_search(query, json_output):
@click.option("--json-output", is_flag=True)
def platform_frameworks(query, json_output):
frameworks = []
for framework in util.get_api_result("/frameworks", cache_valid="30d"):
for framework in util.get_api_result("/frameworks", cache_valid="7d"):
if query == "all":
query = ""
search_data = json.dumps(framework)
search_data = dump_json_to_unicode(framework)
if query and query.lower() not in search_data.lower():
continue
framework['homepage'] = (
"http://platformio.org/frameworks/" + framework['name'])
framework['homepage'] = ("https://platformio.org/frameworks/" +
framework['name'])
framework['platforms'] = [
platform['name'] for platform in _get_registry_platforms()
if framework['name'] in platform['frameworks']
@@ -204,7 +195,7 @@ def platform_frameworks(query, json_output):
frameworks = sorted(frameworks, key=lambda manifest: manifest['name'])
if json_output:
click.echo(json.dumps(frameworks))
click.echo(dump_json_to_unicode(frameworks))
else:
_print_platforms(frameworks)
@@ -216,14 +207,13 @@ def platform_list(json_output):
pm = PlatformManager()
for manifest in pm.get_installed():
platforms.append(
_get_installed_platform_data(
manifest['__pkg_dir'],
with_boards=False,
expose_packages=False))
_get_installed_platform_data(manifest['__pkg_dir'],
with_boards=False,
expose_packages=False))
platforms = sorted(platforms, key=lambda manifest: manifest['name'])
if json_output:
click.echo(json.dumps(platforms))
click.echo(dump_json_to_unicode(platforms))
else:
_print_platforms(platforms)
@@ -236,10 +226,11 @@ def platform_show(platform, json_output): # pylint: disable=too-many-branches
if not data:
raise exception.UnknownPlatform(platform)
if json_output:
return click.echo(json.dumps(data))
return click.echo(dump_json_to_unicode(data))
click.echo("{name} ~ {title}".format(
name=click.style(data['name'], fg="cyan"), title=data['title']))
click.echo("{name} ~ {title}".format(name=click.style(data['name'],
fg="cyan"),
title=data['title']))
click.echo("=" * (3 + len(data['name'] + data['title'])))
click.echo(data['description'])
click.echo()
@@ -257,7 +248,7 @@ def platform_show(platform, json_output): # pylint: disable=too-many-branches
click.echo("Frameworks: %s" % ", ".join(data['frameworks']))
if not data['packages']:
return
return None
if not isinstance(data['packages'][0], dict):
click.echo("Packages: %s" % ", ".join(data['packages']))
@@ -287,26 +278,32 @@ def platform_show(platform, json_output): # pylint: disable=too-many-branches
click.echo("------")
print_boards(data['boards'])
return True
@cli.command("install", short_help="Install new development platform")
@click.argument("platforms", nargs=-1, required=True, metavar="[PLATFORM...]")
@click.option("--with-package", multiple=True)
@click.option("--without-package", multiple=True)
@click.option("--skip-default-package", is_flag=True)
@click.option(
"-f",
"--force",
is_flag=True,
help="Reinstall/redownload dev/platform and its packages if exist")
def platform_install(platforms, with_package, without_package,
skip_default_package):
skip_default_package, force):
pm = PlatformManager()
for platform in platforms:
if pm.install(
name=platform,
with_packages=with_package,
without_packages=without_package,
skip_default_package=skip_default_package):
click.secho(
"The platform '%s' has been successfully installed!\n"
"The rest of packages will be installed automatically "
"depending on your build environment." % platform,
fg="green")
if pm.install(name=platform,
with_packages=with_package,
without_packages=without_package,
skip_default_package=skip_default_package,
force=force):
click.secho("The platform '%s' has been successfully installed!\n"
"The rest of packages will be installed automatically "
"depending on your build environment." % platform,
fg="green")
@cli.command("uninstall", short_help="Uninstall development platform")
@@ -315,26 +312,27 @@ def platform_uninstall(platforms):
pm = PlatformManager()
for platform in platforms:
if pm.uninstall(platform):
click.secho(
"The platform '%s' has been successfully "
"uninstalled!" % platform,
fg="green")
click.secho("The platform '%s' has been successfully "
"uninstalled!" % platform,
fg="green")
@cli.command("update", short_help="Update installed development platforms")
@click.argument("platforms", nargs=-1, required=False, metavar="[PLATFORM...]")
@click.option(
"-p",
"--only-packages",
is_flag=True,
help="Update only the platform packages")
@click.option(
"-c",
"--only-check",
is_flag=True,
help="Do not update, only check for a new version")
@click.option("-p",
"--only-packages",
is_flag=True,
help="Update only the platform packages")
@click.option("-c",
"--only-check",
is_flag=True,
help="DEPRECATED. Please use `--dry-run` instead")
@click.option("--dry-run",
is_flag=True,
help="Do not update, only check for the new versions")
@click.option("--json-output", is_flag=True)
def platform_update(platforms, only_packages, only_check, json_output):
def platform_update( # pylint: disable=too-many-locals
platforms, only_packages, only_check, dry_run, json_output):
pm = PlatformManager()
pkg_dir_to_name = {}
if not platforms:
@@ -344,6 +342,8 @@ def platform_update(platforms, only_packages, only_check, json_output):
pkg_dir_to_name[manifest['__pkg_dir']] = manifest.get(
"title", manifest['name'])
only_check = dry_run or only_check
if only_check and json_output:
result = []
for platform in platforms:
@@ -351,27 +351,30 @@ def platform_update(platforms, only_packages, only_check, json_output):
requirements = None
url = None
if not pkg_dir:
name, requirements, url = pm.parse_pkg_input(platform)
name, requirements, url = pm.parse_pkg_uri(platform)
pkg_dir = pm.get_package_dir(name, requirements, url)
if not pkg_dir:
continue
latest = pm.outdated(pkg_dir, requirements)
if (not latest and not PlatformFactory.newPlatform(pkg_dir)
.are_outdated_packages()):
if (not latest and not PlatformFactory.newPlatform(
pkg_dir).are_outdated_packages()):
continue
data = _get_installed_platform_data(
pkg_dir, with_boards=False, expose_packages=False)
data = _get_installed_platform_data(pkg_dir,
with_boards=False,
expose_packages=False)
if latest:
data['versionLatest'] = latest
result.append(data)
return click.echo(json.dumps(result))
else:
# cleanup cached board and platform lists
app.clean_cache()
for platform in platforms:
click.echo("Platform %s" % click.style(
pkg_dir_to_name.get(platform, platform), fg="cyan"))
click.echo("--------")
pm.update(
platform, only_packages=only_packages, only_check=only_check)
click.echo()
return click.echo(dump_json_to_unicode(result))
# cleanup cached board and platform lists
app.clean_cache()
for platform in platforms:
click.echo(
"Platform %s" %
click.style(pkg_dir_to_name.get(platform, platform), fg="cyan"))
click.echo("--------")
pm.update(platform, only_packages=only_packages, only_check=only_check)
click.echo()
return True

View File

@@ -21,8 +21,9 @@ from time import sleep
import click
from platformio import exception, util
from platformio import exception, fs
from platformio.commands.device import device_monitor as cmd_device_monitor
from platformio.compat import get_file_contents
from platformio.managers.core import pioplus_call
# pylint: disable=unused-argument
@@ -42,12 +43,13 @@ def remote_agent():
@remote_agent.command("start", short_help="Start agent")
@click.option("-n", "--name")
@click.option("-s", "--share", multiple=True, metavar="E-MAIL")
@click.option(
"-d",
"--working-dir",
envvar="PLATFORMIO_REMOTE_AGENT_DIR",
type=click.Path(
file_okay=False, dir_okay=True, writable=True, resolve_path=True))
@click.option("-d",
"--working-dir",
envvar="PLATFORMIO_REMOTE_AGENT_DIR",
type=click.Path(file_okay=False,
dir_okay=True,
writable=True,
resolve_path=True))
def remote_agent_start(**kwargs):
pioplus_call(sys.argv[1:])
@@ -62,14 +64,16 @@ def remote_agent_list():
pioplus_call(sys.argv[1:])
@cli.command(
"update", short_help="Update installed Platforms, Packages and Libraries")
@click.option(
"-c",
"--only-check",
is_flag=True,
help="Do not update, only check for new version")
def remote_update(only_check):
@cli.command("update",
short_help="Update installed Platforms, Packages and Libraries")
@click.option("-c",
"--only-check",
is_flag=True,
help="DEPRECATED. Please use `--dry-run` instead")
@click.option("--dry-run",
is_flag=True,
help="Do not update, only check for the new versions")
def remote_update(only_check, dry_run):
pioplus_call(sys.argv[1:])
@@ -77,16 +81,14 @@ def remote_update(only_check):
@click.option("-e", "--environment", multiple=True)
@click.option("-t", "--target", multiple=True)
@click.option("--upload-port")
@click.option(
"-d",
"--project-dir",
default=getcwd,
type=click.Path(
exists=True,
file_okay=True,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option("-d",
"--project-dir",
default=getcwd,
type=click.Path(exists=True,
file_okay=True,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option("--disable-auto-clean", is_flag=True)
@click.option("-r", "--force-remote", is_flag=True)
@click.option("-s", "--silent", is_flag=True)
@@ -100,16 +102,14 @@ def remote_run(**kwargs):
@click.option("--ignore", "-i", multiple=True, metavar="<pattern>")
@click.option("--upload-port")
@click.option("--test-port")
@click.option(
"-d",
"--project-dir",
default=getcwd,
type=click.Path(
exists=True,
file_okay=False,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option("-d",
"--project-dir",
default=getcwd,
type=click.Path(exists=True,
file_okay=False,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option("-r", "--force-remote", is_flag=True)
@click.option("--without-building", is_flag=True)
@click.option("--without-uploading", is_flag=True)
@@ -131,59 +131,55 @@ def device_list(json_output):
@remote_device.command("monitor", short_help="Monitor remote device")
@click.option("--port", "-p", help="Port, a number or a device name")
@click.option(
"--baud", "-b", type=int, default=9600, help="Set baud rate, default=9600")
@click.option(
"--parity",
default="N",
type=click.Choice(["N", "E", "O", "S", "M"]),
help="Set parity, default=N")
@click.option(
"--rtscts", is_flag=True, help="Enable RTS/CTS flow control, default=Off")
@click.option(
"--xonxoff",
is_flag=True,
help="Enable software flow control, default=Off")
@click.option(
"--rts",
default=None,
type=click.IntRange(0, 1),
help="Set initial RTS line state")
@click.option(
"--dtr",
default=None,
type=click.IntRange(0, 1),
help="Set initial DTR line state")
@click.option("--baud",
"-b",
type=int,
default=9600,
help="Set baud rate, default=9600")
@click.option("--parity",
default="N",
type=click.Choice(["N", "E", "O", "S", "M"]),
help="Set parity, default=N")
@click.option("--rtscts",
is_flag=True,
help="Enable RTS/CTS flow control, default=Off")
@click.option("--xonxoff",
is_flag=True,
help="Enable software flow control, default=Off")
@click.option("--rts",
default=None,
type=click.IntRange(0, 1),
help="Set initial RTS line state")
@click.option("--dtr",
default=None,
type=click.IntRange(0, 1),
help="Set initial DTR line state")
@click.option("--echo", is_flag=True, help="Enable local echo, default=Off")
@click.option(
"--encoding",
default="UTF-8",
help="Set the encoding for the serial port (e.g. hexlify, "
"Latin1, UTF-8), default: UTF-8")
@click.option("--encoding",
default="UTF-8",
help="Set the encoding for the serial port (e.g. hexlify, "
"Latin1, UTF-8), default: UTF-8")
@click.option("--filter", "-f", multiple=True, help="Add text transformation")
@click.option(
"--eol",
default="CRLF",
type=click.Choice(["CR", "LF", "CRLF"]),
help="End of line mode, default=CRLF")
@click.option(
"--raw", is_flag=True, help="Do not apply any encodings/transformations")
@click.option(
"--exit-char",
type=int,
default=3,
help="ASCII code of special character that is used to exit "
"the application, default=3 (Ctrl+C)")
@click.option(
"--menu-char",
type=int,
default=20,
help="ASCII code of special character that is used to "
"control miniterm (menu), default=20 (DEC)")
@click.option(
"--quiet",
is_flag=True,
help="Diagnostics: suppress non-error messages, default=Off")
@click.option("--eol",
default="CRLF",
type=click.Choice(["CR", "LF", "CRLF"]),
help="End of line mode, default=CRLF")
@click.option("--raw",
is_flag=True,
help="Do not apply any encodings/transformations")
@click.option("--exit-char",
type=int,
default=3,
help="ASCII code of special character that is used to exit "
"the application, default=3 (Ctrl+C)")
@click.option("--menu-char",
type=int,
default=20,
help="ASCII code of special character that is used to "
"control miniterm (menu), default=20 (DEC)")
@click.option("--quiet",
is_flag=True,
help="Diagnostics: suppress non-error messages, default=Off")
@click.pass_context
def device_monitor(ctx, **kwargs):
@@ -202,8 +198,8 @@ def device_monitor(ctx, **kwargs):
sleep(0.1)
if not t.is_alive():
return
kwargs['port'] = open(sock_file).read()
kwargs['port'] = get_file_contents(sock_file)
ctx.invoke(cmd_device_monitor, **kwargs)
t.join(2)
finally:
util.rmtree_(sock_dir)
fs.rmtree(sock_dir)

View File

@@ -1,415 +0,0 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from datetime import datetime
from hashlib import sha1
from os import getcwd, makedirs, walk
from os.path import getmtime, isdir, isfile, join
from time import time
import click
from platformio import __version__, exception, telemetry, util
from platformio.commands.device import device_monitor as cmd_device_monitor
from platformio.commands.lib import lib_install as cmd_lib_install
from platformio.commands.lib import get_builtin_libs
from platformio.commands.platform import \
platform_install as cmd_platform_install
from platformio.managers.lib import LibraryManager
from platformio.managers.platform import PlatformFactory
# pylint: disable=too-many-arguments,too-many-locals,too-many-branches
@click.command("run", short_help="Process project environments")
@click.option("-e", "--environment", multiple=True)
@click.option("-t", "--target", multiple=True)
@click.option("--upload-port")
@click.option(
"-d",
"--project-dir",
default=getcwd,
type=click.Path(
exists=True,
file_okay=True,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option("-s", "--silent", is_flag=True)
@click.option("-v", "--verbose", is_flag=True)
@click.option("--disable-auto-clean", is_flag=True)
@click.pass_context
def cli(ctx, environment, target, upload_port, project_dir, silent, verbose,
disable_auto_clean):
# find project directory on upper level
if isfile(project_dir):
project_dir = util.find_project_dir_above(project_dir)
if not util.is_platformio_project(project_dir):
raise exception.NotPlatformIOProject(project_dir)
with util.cd(project_dir):
# clean obsolete .pioenvs dir
if not disable_auto_clean:
try:
_clean_pioenvs_dir(util.get_projectpioenvs_dir())
except: # pylint: disable=bare-except
click.secho(
"Can not remove temporary directory `%s`. Please remove "
"`.pioenvs` directory from the project manually to avoid "
"build issues" % util.get_projectpioenvs_dir(force=True),
fg="yellow")
config = util.load_project_config()
check_project_defopts(config)
assert check_project_envs(config, environment)
env_default = None
if config.has_option("platformio", "env_default"):
env_default = [
e.strip()
for e in config.get("platformio", "env_default").split(", ")
]
results = []
start_time = time()
for section in config.sections():
if not section.startswith("env:"):
continue
envname = section[4:]
skipenv = any([
environment and envname not in environment, not environment and
env_default and envname not in env_default
])
if skipenv:
results.append((envname, None))
continue
if not silent and results:
click.echo()
options = {}
for k, v in config.items(section):
options[k] = v
if "piotest" not in options and "piotest" in ctx.meta:
options['piotest'] = ctx.meta['piotest']
ep = EnvironmentProcessor(ctx, envname, options, target,
upload_port, silent, verbose)
result = (envname, ep.process())
results.append(result)
if result[1] and "monitor" in ep.get_build_targets() and \
"nobuild" not in ep.get_build_targets():
ctx.invoke(cmd_device_monitor)
found_error = any([status is False for (_, status) in results])
if (found_error or not silent) and len(results) > 1:
click.echo()
print_summary(results, start_time)
if found_error:
raise exception.ReturnErrorCode(1)
return True
class EnvironmentProcessor(object):
KNOWN_OPTIONS = ("platform", "framework", "board", "board_mcu",
"board_f_cpu", "board_f_flash", "board_flash_mode",
"build_flags", "src_build_flags", "build_unflags",
"src_filter", "extra_script", "targets", "upload_port",
"upload_protocol", "upload_speed", "upload_flags",
"upload_resetmethod", "lib_deps", "lib_ignore",
"lib_extra_dirs", "lib_ldf_mode", "lib_compat_mode",
"piotest", "test_transport", "test_ignore", "test_port",
"debug_tool", "debug_port", "debug_init_cmds",
"debug_extra_cmds", "debug_server", "debug_init_break",
"debug_load_cmd")
IGNORE_BUILD_OPTIONS = ("test_transport", "test_filter", "test_ignore",
"test_port", "debug_tool", "debug_port",
"debug_init_cmds", "debug_extra_cmds",
"debug_server", "debug_init_break",
"debug_load_cmd")
REMAPED_OPTIONS = {"framework": "pioframework", "platform": "pioplatform"}
RENAMED_OPTIONS = {"lib_use": "lib_deps", "lib_force": "lib_deps"}
RENAMED_PLATFORMS = {"espressif": "espressif8266"}
def __init__(
self, # pylint: disable=R0913
cmd_ctx,
name,
options,
targets,
upload_port,
silent,
verbose):
self.cmd_ctx = cmd_ctx
self.name = name
self.options = options
self.targets = targets
self.upload_port = upload_port
self.silent = silent
self.verbose = verbose
def process(self):
terminal_width, _ = click.get_terminal_size()
start_time = time()
for k, v in self.options.items():
self.options[k] = self.options[k].strip()
if not self.silent:
click.echo("[%s] Processing %s (%s)" %
(datetime.now().strftime("%c"),
click.style(self.name, fg="cyan", bold=True),
"; ".join([
"%s: %s" % (k, v.replace("\n", ", "))
for k, v in self.options.items()
])))
click.secho("-" * terminal_width, bold=True)
self.options = self._validate_options(self.options)
result = self._run()
is_error = result['returncode'] != 0
if self.silent and not is_error:
return True
if is_error or "piotest_processor" not in self.cmd_ctx.meta:
print_header(
"[%s] Took %.2f seconds" %
((click.style("ERROR", fg="red", bold=True)
if is_error else click.style(
"SUCCESS", fg="green", bold=True)), time() - start_time),
is_error=is_error)
return not is_error
def _validate_options(self, options):
result = {}
for k, v in options.items():
# process obsolete options
if k in self.RENAMED_OPTIONS:
click.secho(
"Warning! `%s` option is deprecated and will be "
"removed in the next release! Please use "
"`%s` instead." % (k, self.RENAMED_OPTIONS[k]),
fg="yellow")
k = self.RENAMED_OPTIONS[k]
# process renamed platforms
if k == "platform" and v in self.RENAMED_PLATFORMS:
click.secho(
"Warning! Platform `%s` is deprecated and will be "
"removed in the next release! Please use "
"`%s` instead." % (v, self.RENAMED_PLATFORMS[v]),
fg="yellow")
v = self.RENAMED_PLATFORMS[v]
# warn about unknown options
if k not in self.KNOWN_OPTIONS:
click.secho(
"Detected non-PlatformIO `%s` option in `[env:%s]` section"
% (k, self.name),
fg="yellow")
result[k] = v
return result
def get_build_variables(self):
variables = {"pioenv": self.name}
if self.upload_port:
variables['upload_port'] = self.upload_port
for k, v in self.options.items():
if k in self.REMAPED_OPTIONS:
k = self.REMAPED_OPTIONS[k]
if k in self.IGNORE_BUILD_OPTIONS:
continue
if k == "targets" or (k == "upload_port" and self.upload_port):
continue
variables[k] = v
return variables
def get_build_targets(self):
targets = []
if self.targets:
targets = [t for t in self.targets]
elif "targets" in self.options:
targets = self.options['targets'].split(", ")
return targets
def _run(self):
if "platform" not in self.options:
raise exception.UndefinedEnvPlatform(self.name)
build_vars = self.get_build_variables()
build_targets = self.get_build_targets()
telemetry.on_run_environment(self.options, build_targets)
# skip monitor target, we call it above
if "monitor" in build_targets:
build_targets.remove("monitor")
if "nobuild" not in build_targets:
# install dependent libraries
if "lib_install" in self.options:
_autoinstall_libdeps(self.cmd_ctx, [
int(d.strip())
for d in self.options['lib_install'].split(",")
if d.strip()
], self.verbose)
if "lib_deps" in self.options:
_autoinstall_libdeps(self.cmd_ctx, [
d.strip()
for d in self.options['lib_deps'].split(
"\n" if "\n" in self.options['lib_deps'] else ", ")
if d.strip()
], self.verbose)
try:
p = PlatformFactory.newPlatform(self.options['platform'])
except exception.UnknownPlatform:
self.cmd_ctx.invoke(
cmd_platform_install,
platforms=[self.options['platform']],
skip_default_package=True)
p = PlatformFactory.newPlatform(self.options['platform'])
return p.run(build_vars, build_targets, self.silent, self.verbose)
def _autoinstall_libdeps(ctx, libraries, verbose=False):
storage_dir = util.get_projectlibdeps_dir()
ctx.obj = LibraryManager(storage_dir)
if verbose:
click.echo("Library Storage: " + storage_dir)
for lib in libraries:
try:
ctx.invoke(cmd_lib_install, libraries=[lib], silent=not verbose)
except exception.LibNotFound as e:
if not _is_builtin_lib(lib):
click.secho("Warning! %s" % e, fg="yellow")
def _is_builtin_lib(lib_name):
for storage in get_builtin_libs():
if any([l.get("name") == lib_name for l in storage['items']]):
return True
return False
def _clean_pioenvs_dir(pioenvs_dir):
structhash_file = join(pioenvs_dir, "structure.hash")
proj_hash = calculate_project_hash()
# if project's config is modified
if (isdir(pioenvs_dir) and
getmtime(join(util.get_project_dir(), "platformio.ini")) >
getmtime(pioenvs_dir)):
util.rmtree_(pioenvs_dir)
# check project structure
if isdir(pioenvs_dir) and isfile(structhash_file):
with open(structhash_file) as f:
if f.read() == proj_hash:
return
util.rmtree_(pioenvs_dir)
if not isdir(pioenvs_dir):
makedirs(pioenvs_dir)
with open(structhash_file, "w") as f:
f.write(proj_hash)
def print_header(label, is_error=False):
terminal_width, _ = click.get_terminal_size()
width = len(click.unstyle(label))
half_line = "=" * ((terminal_width - width - 2) / 2)
click.echo("%s %s %s" % (half_line, label, half_line), err=is_error)
def print_summary(results, start_time):
print_header("[%s]" % click.style("SUMMARY"))
envname_max_len = 0
for (envname, _) in results:
if len(envname) > envname_max_len:
envname_max_len = len(envname)
successed = True
for (envname, status) in results:
status_str = click.style("SUCCESS", fg="green")
if status is False:
successed = False
status_str = click.style("ERROR", fg="red")
elif status is None:
status_str = click.style("SKIP", fg="yellow")
format_str = (
"Environment {0:<" + str(envname_max_len + 9) + "}\t[{1}]")
click.echo(
format_str.format(click.style(envname, fg="cyan"), status_str),
err=status is False)
print_header(
"[%s] Took %.2f seconds" %
((click.style("SUCCESS", fg="green", bold=True)
if successed else click.style("ERROR", fg="red", bold=True)),
time() - start_time),
is_error=not successed)
def check_project_defopts(config):
if not config.has_section("platformio"):
return True
known = ("env_default", "home_dir", "lib_dir", "libdeps_dir", "src_dir",
"envs_dir", "data_dir", "test_dir", "boards_dir",
"lib_extra_dirs")
unknown = set([k for k, _ in config.items("platformio")]) - set(known)
if not unknown:
return True
click.secho(
"Warning! Ignore unknown `%s` option from `[platformio]` section" %
", ".join(unknown),
fg="yellow")
return False
def check_project_envs(config, environments):
if not config.sections():
raise exception.ProjectEnvsNotAvailable()
known = set([s[4:] for s in config.sections() if s.startswith("env:")])
unknown = set(environments) - known
if unknown:
raise exception.UnknownEnvNames(", ".join(unknown), ", ".join(known))
return True
def calculate_project_hash():
structure = [__version__]
for d in (util.get_projectsrc_dir(), util.get_projectlib_dir()):
if not isdir(d):
continue
for root, _, files in walk(d):
for f in files:
path = join(root, f)
if not any([s in path for s in (".git", ".svn", ".pioenvs")]):
structure.append(path)
return sha1(",".join(sorted(structure))).hexdigest() if structure else ""

View File

@@ -0,0 +1,15 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from platformio.commands.run.command import cli

View File

@@ -0,0 +1,205 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from multiprocessing import cpu_count
from os import getcwd
from os.path import isfile, join
from time import time
import click
from tabulate import tabulate
from platformio import exception, fs, util
from platformio.commands.device import device_monitor as cmd_device_monitor
from platformio.commands.run.helpers import (clean_build_dir,
handle_legacy_libdeps)
from platformio.commands.run.processor import EnvironmentProcessor
from platformio.commands.test.processor import CTX_META_TEST_IS_RUNNING
from platformio.project.config import ProjectConfig
from platformio.project.helpers import (find_project_dir_above,
get_project_build_dir)
# pylint: disable=too-many-arguments,too-many-locals,too-many-branches
try:
DEFAULT_JOB_NUMS = cpu_count()
except NotImplementedError:
DEFAULT_JOB_NUMS = 1
@click.command("run", short_help="Process project environments")
@click.option("-e", "--environment", multiple=True)
@click.option("-t", "--target", multiple=True)
@click.option("--upload-port")
@click.option("-d",
"--project-dir",
default=getcwd,
type=click.Path(exists=True,
file_okay=True,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option("-c",
"--project-conf",
type=click.Path(exists=True,
file_okay=True,
dir_okay=False,
readable=True,
resolve_path=True))
@click.option("-j",
"--jobs",
type=int,
default=DEFAULT_JOB_NUMS,
help=("Allow N jobs at once. "
"Default is a number of CPUs in a system (N=%d)" %
DEFAULT_JOB_NUMS))
@click.option("-s", "--silent", is_flag=True)
@click.option("-v", "--verbose", is_flag=True)
@click.option("--disable-auto-clean", is_flag=True)
@click.pass_context
def cli(ctx, environment, target, upload_port, project_dir, project_conf, jobs,
silent, verbose, disable_auto_clean):
# find project directory on upper level
if isfile(project_dir):
project_dir = find_project_dir_above(project_dir)
is_test_running = CTX_META_TEST_IS_RUNNING in ctx.meta
with fs.cd(project_dir):
config = ProjectConfig.get_instance(
project_conf or join(project_dir, "platformio.ini"))
config.validate(environment)
# clean obsolete build dir
if not disable_auto_clean:
try:
clean_build_dir(get_project_build_dir(), config)
except: # pylint: disable=bare-except
click.secho(
"Can not remove temporary directory `%s`. Please remove "
"it manually to avoid build issues" %
get_project_build_dir(force=True),
fg="yellow")
handle_legacy_libdeps(project_dir, config)
default_envs = config.default_envs()
results = []
for env in config.envs():
skipenv = any([
environment and env not in environment, not environment
and default_envs and env not in default_envs
])
if skipenv:
results.append({"env": env})
continue
# print empty line between multi environment project
if not silent and any(
r.get("succeeded") is not None for r in results):
click.echo()
results.append(
process_env(ctx, env, config, environment, target, upload_port,
silent, verbose, jobs, is_test_running))
command_failed = any(r.get("succeeded") is False for r in results)
if (not is_test_running and (command_failed or not silent)
and len(results) > 1):
print_processing_summary(results)
if command_failed:
raise exception.ReturnErrorCode(1)
return True
def process_env(ctx, name, config, environments, targets, upload_port, silent,
verbose, jobs, is_test_running):
if not is_test_running and not silent:
print_processing_header(name, config, verbose)
ep = EnvironmentProcessor(ctx, name, config, targets, upload_port, silent,
verbose, jobs)
result = {"env": name, "duration": time(), "succeeded": ep.process()}
result['duration'] = time() - result['duration']
# print footer on error or when is not unit testing
if not is_test_running and (not silent or not result['succeeded']):
print_processing_footer(result)
if (result['succeeded'] and "monitor" in ep.get_build_targets()
and "nobuild" not in ep.get_build_targets()):
ctx.invoke(cmd_device_monitor,
environment=environments[0] if environments else None)
return result
def print_processing_header(env, config, verbose=False):
env_dump = []
for k, v in config.items(env=env):
if verbose or k in ("platform", "framework", "board"):
env_dump.append("%s: %s" %
(k, ", ".join(v) if isinstance(v, list) else v))
click.echo("Processing %s (%s)" %
(click.style(env, fg="cyan", bold=True), "; ".join(env_dump)))
terminal_width, _ = click.get_terminal_size()
click.secho("-" * terminal_width, bold=True)
def print_processing_footer(result):
is_failed = not result.get("succeeded")
util.print_labeled_bar(
"[%s] Took %.2f seconds" %
((click.style("FAILED", fg="red", bold=True) if is_failed else
click.style("SUCCESS", fg="green", bold=True)), result['duration']),
is_error=is_failed)
def print_processing_summary(results):
tabular_data = []
succeeded_nums = 0
failed_nums = 0
duration = 0
for result in results:
duration += result.get("duration", 0)
if result.get("succeeded") is False:
failed_nums += 1
status_str = click.style("FAILED", fg="red")
elif result.get("succeeded") is None:
status_str = "IGNORED"
else:
succeeded_nums += 1
status_str = click.style("SUCCESS", fg="green")
tabular_data.append(
(click.style(result['env'], fg="cyan"), status_str,
util.humanize_duration_time(result.get("duration"))))
click.echo()
click.echo(tabulate(tabular_data,
headers=[
click.style(s, bold=True)
for s in ("Environment", "Status", "Duration")
]),
err=failed_nums)
util.print_labeled_bar(
"%s%d succeeded in %s" %
("%d failed, " % failed_nums if failed_nums else "", succeeded_nums,
util.humanize_duration_time(duration)),
is_error=failed_nums,
fg="red" if failed_nums else "green")

View File

@@ -0,0 +1,64 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from os import makedirs
from os.path import isdir, isfile, join
import click
from platformio import fs
from platformio.project.helpers import (compute_project_checksum,
get_project_dir,
get_project_libdeps_dir)
def handle_legacy_libdeps(project_dir, config):
legacy_libdeps_dir = join(project_dir, ".piolibdeps")
if (not isdir(legacy_libdeps_dir)
or legacy_libdeps_dir == get_project_libdeps_dir()):
return
if not config.has_section("env"):
config.add_section("env")
lib_extra_dirs = config.get("env", "lib_extra_dirs", [])
lib_extra_dirs.append(legacy_libdeps_dir)
config.set("env", "lib_extra_dirs", lib_extra_dirs)
click.secho(
"DEPRECATED! A legacy library storage `{0}` has been found in a "
"project. \nPlease declare project dependencies in `platformio.ini`"
" file using `lib_deps` option and remove `{0}` folder."
"\nMore details -> http://docs.platformio.org/page/projectconf/"
"section_env_library.html#lib-deps".format(legacy_libdeps_dir),
fg="yellow")
def clean_build_dir(build_dir, config):
# remove legacy ".pioenvs" folder
legacy_build_dir = join(get_project_dir(), ".pioenvs")
if isdir(legacy_build_dir) and legacy_build_dir != build_dir:
fs.rmtree(legacy_build_dir)
checksum_file = join(build_dir, "project.checksum")
checksum = compute_project_checksum(config)
if isdir(build_dir):
# check project structure
if isfile(checksum_file):
with open(checksum_file) as f:
if f.read() == checksum:
return
fs.rmtree(build_dir)
makedirs(build_dir)
with open(checksum_file, "w") as f:
f.write(checksum)

View File

@@ -0,0 +1,79 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from platformio import exception, telemetry
from platformio.commands.platform import \
platform_install as cmd_platform_install
from platformio.commands.test.processor import CTX_META_TEST_RUNNING_NAME
from platformio.managers.platform import PlatformFactory
# pylint: disable=too-many-instance-attributes
class EnvironmentProcessor(object):
def __init__( # pylint: disable=too-many-arguments
self, cmd_ctx, name, config, targets, upload_port, silent, verbose,
jobs):
self.cmd_ctx = cmd_ctx
self.name = name
self.config = config
self.targets = [str(t) for t in targets]
self.upload_port = upload_port
self.silent = silent
self.verbose = verbose
self.jobs = jobs
self.options = config.items(env=name, as_dict=True)
def get_build_variables(self):
variables = {"pioenv": self.name, "project_config": self.config.path}
if CTX_META_TEST_RUNNING_NAME in self.cmd_ctx.meta:
variables['piotest_running_name'] = self.cmd_ctx.meta[
CTX_META_TEST_RUNNING_NAME]
if self.upload_port:
# override upload port with a custom from CLI
variables['upload_port'] = self.upload_port
return variables
def get_build_targets(self):
if self.targets:
return [t for t in self.targets]
return self.config.get("env:" + self.name, "targets", [])
def process(self):
if "platform" not in self.options:
raise exception.UndefinedEnvPlatform(self.name)
build_vars = self.get_build_variables()
build_targets = self.get_build_targets()
telemetry.on_run_environment(self.options, build_targets)
# skip monitor target, we call it above
if "monitor" in build_targets:
build_targets.remove("monitor")
try:
p = PlatformFactory.newPlatform(self.options['platform'])
except exception.UnknownPlatform:
self.cmd_ctx.invoke(cmd_platform_install,
platforms=[self.options['platform']],
skip_default_package=True)
p = PlatformFactory.newPlatform(self.options['platform'])
result = p.run(build_vars, build_targets, self.silent, self.verbose,
self.jobs)
return result['returncode'] == 0

View File

@@ -13,8 +13,18 @@
# limitations under the License.
import click
from tabulate import tabulate
from platformio import app
from platformio.compat import string_types
def format_value(raw):
if isinstance(raw, bool):
return "Yes" if raw else "No"
if isinstance(raw, string_types):
return raw
return str(raw)
@click.group(short_help="Manage PlatformIO settings")
@@ -25,41 +35,27 @@ def cli():
@cli.command("get", short_help="Get existing setting/-s")
@click.argument("name", required=False)
def settings_get(name):
tabular_data = []
for key, options in sorted(app.DEFAULT_SETTINGS.items()):
if name and name != key:
continue
raw_value = app.get_setting(key)
formatted_value = format_value(raw_value)
list_tpl = "{name:<40} {value:<35} {description}"
terminal_width, _ = click.get_terminal_size()
if raw_value != options['value']:
default_formatted_value = format_value(options['value'])
formatted_value += "%s" % (
"\n" if len(default_formatted_value) > 10 else " ")
formatted_value += "[%s]" % click.style(default_formatted_value,
fg="yellow")
tabular_data.append(
(click.style(key,
fg="cyan"), formatted_value, options['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("-" * terminal_width)
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']))
tabulate(tabular_data,
headers=["Name", "Current value [Default]", "Description"]))
@cli.command("set", short_help="Set new value for the setting")

View File

@@ -1,67 +0,0 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
from os import getcwd
import click
from platformio.managers.core import pioplus_call
@click.command("test", short_help="Local Unit Testing")
@click.option("--environment", "-e", multiple=True, metavar="<environment>")
@click.option(
"--filter",
"-f",
multiple=True,
metavar="<pattern>",
help="Filter tests by a pattern")
@click.option(
"--ignore",
"-i",
multiple=True,
metavar="<pattern>",
help="Ignore tests by a pattern")
@click.option("--upload-port")
@click.option("--test-port")
@click.option(
"-d",
"--project-dir",
default=getcwd,
type=click.Path(
exists=True,
file_okay=False,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option("--without-building", is_flag=True)
@click.option("--without-uploading", is_flag=True)
@click.option(
"--no-reset",
is_flag=True,
help="Disable software reset via Serial.DTR/RST")
@click.option(
"--monitor-rts",
default=None,
type=click.IntRange(0, 1),
help="Set initial RTS line state for Serial Monitor")
@click.option(
"--monitor-dtr",
default=None,
type=click.IntRange(0, 1),
help="Set initial DTR line state for Serial Monitor")
@click.option("--verbose", "-v", is_flag=True)
def cli(*args, **kwargs): # pylint: disable=unused-argument
pioplus_call(sys.argv[1:])

View File

@@ -0,0 +1,15 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from platformio.commands.test.command import cli

View File

@@ -0,0 +1,222 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# pylint: disable=too-many-arguments, too-many-locals, too-many-branches
from fnmatch import fnmatch
from os import getcwd, listdir
from os.path import isdir, join
from time import time
import click
from tabulate import tabulate
from platformio import exception, fs, util
from platformio.commands.test.embedded import EmbeddedTestProcessor
from platformio.commands.test.native import NativeTestProcessor
from platformio.project.config import ProjectConfig
from platformio.project.helpers import get_project_test_dir
@click.command("test", short_help="Unit Testing")
@click.option("--environment", "-e", multiple=True, metavar="<environment>")
@click.option("--filter",
"-f",
multiple=True,
metavar="<pattern>",
help="Filter tests by a pattern")
@click.option("--ignore",
"-i",
multiple=True,
metavar="<pattern>",
help="Ignore tests by a pattern")
@click.option("--upload-port")
@click.option("--test-port")
@click.option("-d",
"--project-dir",
default=getcwd,
type=click.Path(exists=True,
file_okay=False,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option("-c",
"--project-conf",
type=click.Path(exists=True,
file_okay=True,
dir_okay=False,
readable=True,
resolve_path=True))
@click.option("--without-building", is_flag=True)
@click.option("--without-uploading", is_flag=True)
@click.option("--without-testing", is_flag=True)
@click.option("--no-reset", is_flag=True)
@click.option("--monitor-rts",
default=None,
type=click.IntRange(0, 1),
help="Set initial RTS line state for Serial Monitor")
@click.option("--monitor-dtr",
default=None,
type=click.IntRange(0, 1),
help="Set initial DTR line state for Serial Monitor")
@click.option("--verbose", "-v", is_flag=True)
@click.pass_context
def cli( # pylint: disable=redefined-builtin
ctx, environment, ignore, filter, upload_port, test_port, project_dir,
project_conf, without_building, without_uploading, without_testing,
no_reset, monitor_rts, monitor_dtr, verbose):
with fs.cd(project_dir):
test_dir = get_project_test_dir()
if not isdir(test_dir):
raise exception.TestDirNotExists(test_dir)
test_names = get_test_names(test_dir)
config = ProjectConfig.get_instance(
project_conf or join(project_dir, "platformio.ini"))
config.validate(envs=environment)
click.echo("Verbose mode can be enabled via `-v, --verbose` option")
click.secho("Collected %d items" % len(test_names), bold=True)
results = []
default_envs = config.default_envs()
for testname in test_names:
for envname in config.envs():
section = "env:%s" % envname
# filter and ignore patterns
patterns = dict(filter=list(filter), ignore=list(ignore))
for key in patterns:
patterns[key].extend(
config.get(section, "test_%s" % key, []))
skip_conditions = [
environment and envname not in environment,
not environment and default_envs
and envname not in default_envs,
testname != "*" and patterns['filter'] and
not any([fnmatch(testname, p)
for p in patterns['filter']]),
testname != "*"
and any([fnmatch(testname, p)
for p in patterns['ignore']]),
]
if any(skip_conditions):
results.append({"env": envname, "test": testname})
continue
click.echo()
print_processing_header(testname, envname)
cls = (NativeTestProcessor
if config.get(section, "platform") == "native" else
EmbeddedTestProcessor)
tp = cls(
ctx, testname, envname,
dict(project_config=config,
project_dir=project_dir,
upload_port=upload_port,
test_port=test_port,
without_building=without_building,
without_uploading=without_uploading,
without_testing=without_testing,
no_reset=no_reset,
monitor_rts=monitor_rts,
monitor_dtr=monitor_dtr,
verbose=verbose))
result = {
"env": envname,
"test": testname,
"duration": time(),
"succeeded": tp.process()
}
result['duration'] = time() - result['duration']
results.append(result)
print_processing_footer(result)
if without_testing:
return
print_testing_summary(results)
command_failed = any(r.get("succeeded") is False for r in results)
if command_failed:
raise exception.ReturnErrorCode(1)
def get_test_names(test_dir):
names = []
for item in sorted(listdir(test_dir)):
if isdir(join(test_dir, item)):
names.append(item)
if not names:
names = ["*"]
return names
def print_processing_header(test, env):
click.echo("Processing %s in %s environment" % (click.style(
test, fg="yellow", bold=True), click.style(env, fg="cyan", bold=True)))
terminal_width, _ = click.get_terminal_size()
click.secho("-" * terminal_width, bold=True)
def print_processing_footer(result):
is_failed = not result.get("succeeded")
util.print_labeled_bar(
"[%s] Took %.2f seconds" %
((click.style("FAILED", fg="red", bold=True) if is_failed else
click.style("PASSED", fg="green", bold=True)), result['duration']),
is_error=is_failed)
def print_testing_summary(results):
click.echo()
tabular_data = []
succeeded_nums = 0
failed_nums = 0
duration = 0
for result in results:
duration += result.get("duration", 0)
if result.get("succeeded") is False:
failed_nums += 1
status_str = click.style("FAILED", fg="red")
elif result.get("succeeded") is None:
status_str = "IGNORED"
else:
succeeded_nums += 1
status_str = click.style("PASSED", fg="green")
tabular_data.append(
(result['test'], click.style(result['env'], fg="cyan"), status_str,
util.humanize_duration_time(result.get("duration"))))
click.echo(tabulate(tabular_data,
headers=[
click.style(s, bold=True)
for s in ("Test", "Environment", "Status",
"Duration")
]),
err=failed_nums)
util.print_labeled_bar(
"%s%d succeeded in %s" %
("%d failed, " % failed_nums if failed_nums else "", succeeded_nums,
util.humanize_duration_time(duration)),
is_error=failed_nums,
fg="red" if failed_nums else "green")

View File

@@ -0,0 +1,135 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from time import sleep
import click
import serial
from platformio import exception, util
from platformio.commands.test.processor import TestProcessorBase
from platformio.managers.platform import PlatformFactory
class EmbeddedTestProcessor(TestProcessorBase):
SERIAL_TIMEOUT = 600
def process(self):
if not self.options['without_building']:
self.print_progress("Building...")
target = ["__test"]
if self.options['without_uploading']:
target.append("checkprogsize")
if not self.build_or_upload(target):
return False
if not self.options['without_uploading']:
self.print_progress("Uploading...")
target = ["upload"]
if self.options['without_building']:
target.append("nobuild")
else:
target.append("__test")
if not self.build_or_upload(target):
return False
if self.options['without_testing']:
return None
self.print_progress("Testing...")
return self.run()
def run(self):
click.echo("If you don't see any output for the first 10 secs, "
"please reset board (press reset button)")
click.echo()
try:
ser = serial.Serial(baudrate=self.get_baudrate(),
timeout=self.SERIAL_TIMEOUT)
ser.port = self.get_test_port()
ser.rts = self.options['monitor_rts']
ser.dtr = self.options['monitor_dtr']
ser.open()
except serial.SerialException as e:
click.secho(str(e), fg="red", err=True)
return False
if not self.options['no_reset']:
ser.flushInput()
ser.setDTR(False)
ser.setRTS(False)
sleep(0.1)
ser.setDTR(True)
ser.setRTS(True)
sleep(0.1)
while True:
line = ser.readline().strip()
# fix non-ascii output from device
for i, c in enumerate(line[::-1]):
if not isinstance(c, int):
c = ord(c)
if c > 127:
line = line[-i:]
break
if not line:
continue
if isinstance(line, bytes):
line = line.decode("utf8")
self.on_run_out(line)
if all([l in line for l in ("Tests", "Failures", "Ignored")]):
break
ser.close()
return not self._run_failed
def get_test_port(self):
# if test port is specified manually or in config
if self.options.get("test_port"):
return self.options.get("test_port")
if self.env_options.get("test_port"):
return self.env_options.get("test_port")
assert set(["platform", "board"]) & set(self.env_options.keys())
p = PlatformFactory.newPlatform(self.env_options['platform'])
board_hwids = p.board_config(self.env_options['board']).get(
"build.hwids", [])
port = None
elapsed = 0
while elapsed < 5 and not port:
for item in util.get_serialports():
port = item['port']
for hwid in board_hwids:
hwid_str = ("%s:%s" % (hwid[0], hwid[1])).replace("0x", "")
if hwid_str in item['hwid']:
return port
# check if port is already configured
try:
serial.Serial(port, timeout=self.SERIAL_TIMEOUT).close()
except serial.SerialException:
port = None
if not port:
sleep(0.25)
elapsed += 0.25
if not port:
raise exception.PlatformioException(
"Please specify `test_port` for environment or use "
"global `--test-port` option.")
return port

View File

@@ -0,0 +1,43 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from os.path import join
from platformio import fs, proc
from platformio.commands.test.processor import TestProcessorBase
from platformio.proc import LineBufferedAsyncPipe
from platformio.project.helpers import get_project_build_dir
class NativeTestProcessor(TestProcessorBase):
def process(self):
if not self.options['without_building']:
self.print_progress("Building...")
if not self.build_or_upload(["__test"]):
return False
if self.options['without_testing']:
return None
self.print_progress("Testing...")
return self.run()
def run(self):
with fs.cd(self.options['project_dir']):
build_dir = get_project_build_dir()
result = proc.exec_command(
[join(build_dir, self.env_name, "program")],
stdout=LineBufferedAsyncPipe(self.on_run_out),
stderr=LineBufferedAsyncPipe(self.on_run_out))
assert "returncode" in result
return result['returncode'] == 0 and not self._run_failed

View File

@@ -0,0 +1,194 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import atexit
from os import remove
from os.path import isdir, isfile, join
from string import Template
import click
from platformio import exception
from platformio.project.helpers import get_project_test_dir
TRANSPORT_OPTIONS = {
"arduino": {
"include": "#include <Arduino.h>",
"object": "",
"putchar": "Serial.write(c)",
"flush": "Serial.flush()",
"begin": "Serial.begin($baudrate)",
"end": "Serial.end()"
},
"mbed": {
"include": "#include <mbed.h>",
"object": "Serial pc(USBTX, USBRX);",
"putchar": "pc.putc(c)",
"flush": "",
"begin": "pc.baud($baudrate)",
"end": ""
},
"espidf": {
"include": "#include <stdio.h>",
"object": "",
"putchar": "putchar(c)",
"flush": "fflush(stdout)",
"begin": "",
"end": ""
},
"native": {
"include": "#include <stdio.h>",
"object": "",
"putchar": "putchar(c)",
"flush": "fflush(stdout)",
"begin": "",
"end": ""
},
"custom": {
"include": '#include "unittest_transport.h"',
"object": "",
"putchar": "unittest_uart_putchar(c)",
"flush": "unittest_uart_flush()",
"begin": "unittest_uart_begin()",
"end": "unittest_uart_end()"
}
}
CTX_META_TEST_IS_RUNNING = __name__ + ".test_running"
CTX_META_TEST_RUNNING_NAME = __name__ + ".test_running_name"
class TestProcessorBase(object):
DEFAULT_BAUDRATE = 115200
def __init__(self, cmd_ctx, testname, envname, options):
self.cmd_ctx = cmd_ctx
self.cmd_ctx.meta[CTX_META_TEST_IS_RUNNING] = True
self.test_name = testname
self.options = options
self.env_name = envname
self.env_options = options['project_config'].items(env=envname,
as_dict=True)
self._run_failed = False
self._outputcpp_generated = False
def get_transport(self):
if self.env_options.get("platform") == "native":
transport = "native"
elif "framework" in self.env_options:
transport = self.env_options.get("framework")[0]
if "test_transport" in self.env_options:
transport = self.env_options['test_transport']
if transport not in TRANSPORT_OPTIONS:
raise exception.PlatformioException(
"Unknown Unit Test transport `%s`" % transport)
return transport.lower()
def get_baudrate(self):
return int(self.env_options.get("test_speed", self.DEFAULT_BAUDRATE))
def print_progress(self, text):
click.secho(text, bold=self.options.get("verbose"))
def build_or_upload(self, target):
if not self._outputcpp_generated:
self.generate_outputcpp(get_project_test_dir())
self._outputcpp_generated = True
if self.test_name != "*":
self.cmd_ctx.meta[CTX_META_TEST_RUNNING_NAME] = self.test_name
try:
from platformio.commands.run import cli as cmd_run
return self.cmd_ctx.invoke(cmd_run,
project_dir=self.options['project_dir'],
upload_port=self.options['upload_port'],
silent=not self.options['verbose'],
environment=[self.env_name],
disable_auto_clean="nobuild" in target,
target=target)
except exception.ReturnErrorCode:
return False
def process(self):
raise NotImplementedError
def run(self):
raise NotImplementedError
def on_run_out(self, line):
line = line.strip()
if line.endswith(":PASS"):
click.echo("%s\t[%s]" %
(line[:-5], click.style("PASSED", fg="green")))
elif ":FAIL" in line:
self._run_failed = True
click.echo("%s\t[%s]" % (line, click.style("FAILED", fg="red")))
else:
click.echo(line)
def generate_outputcpp(self, test_dir):
assert isdir(test_dir)
cpp_tpl = "\n".join([
"$include",
"#include <output_export.h>",
"",
"$object",
"",
"#ifdef __GNUC__",
"void output_start(unsigned int baudrate __attribute__((unused)))",
"#else",
"void output_start(unsigned int baudrate)",
"#endif",
"{",
" $begin;",
"}",
"",
"void output_char(int c)",
"{",
" $putchar;",
"}",
"",
"void output_flush(void)",
"{",
" $flush;",
"}",
"",
"void output_complete(void)",
"{",
" $end;",
"}"
]) # yapf: disable
def delete_tmptest_file(file_):
try:
remove(file_)
except: # pylint: disable=bare-except
if isfile(file_):
click.secho(
"Warning: Could not remove temporary file '%s'. "
"Please remove it manually." % file_,
fg="yellow")
tpl = Template(cpp_tpl).substitute(
TRANSPORT_OPTIONS[self.get_transport()])
data = Template(tpl).substitute(baudrate=self.get_baudrate())
tmp_file = join(test_dir, "output_export.cpp")
with open(tmp_file, "w") as f:
f.write(data)
atexit.register(delete_tmptest_file, tmp_file)

View File

@@ -15,31 +15,37 @@
import click
from platformio import app
from platformio.commands.lib import CTX_META_STORAGE_DIRS_KEY
from platformio.commands.lib import lib_update as cmd_lib_update
from platformio.commands.platform import platform_update as cmd_platform_update
from platformio.managers.core import update_core_packages
from platformio.managers.lib import LibraryManager
@click.command(
"update", short_help="Update installed platforms, packages and libraries")
@click.option(
"--core-packages", is_flag=True, help="Update only the core packages")
@click.option(
"-c",
"--only-check",
is_flag=True,
help="Do not update, only check for new version")
@click.command("update",
short_help="Update installed platforms, packages and libraries")
@click.option("--core-packages",
is_flag=True,
help="Update only the core packages")
@click.option("-c",
"--only-check",
is_flag=True,
help="DEPRECATED. Please use `--dry-run` instead")
@click.option("--dry-run",
is_flag=True,
help="Do not update, only check for the new versions")
@click.pass_context
def cli(ctx, core_packages, only_check):
def cli(ctx, core_packages, only_check, dry_run):
# cleanup lib search results, cached board and platform lists
app.clean_cache()
only_check = dry_run or only_check
update_core_packages(only_check)
if core_packages:
return
# cleanup lib search results, cached board and platform lists
app.clean_cache()
click.echo()
click.echo("Platform Manager")
click.echo("================")
@@ -48,5 +54,5 @@ def cli(ctx, core_packages, only_check):
click.echo()
click.echo("Library Manager")
click.echo("===============")
ctx.obj = LibraryManager()
ctx.meta[CTX_META_STORAGE_DIRS_KEY] = [LibraryManager().package_dir]
ctx.invoke(cmd_lib_update, only_check=only_check)

View File

@@ -12,64 +12,63 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import re
from zipfile import ZipFile
import click
import requests
from platformio import VERSION, __version__, exception, util
from platformio.compat import WINDOWS
from platformio.proc import exec_command, get_pythonexe_path
from platformio.project.helpers import get_project_cache_dir
@click.command(
"upgrade", short_help="Upgrade PlatformIO to the latest version")
def cli():
latest = get_latest_version()
if __version__ == latest:
@click.command("upgrade",
short_help="Upgrade PlatformIO to the latest version")
@click.option("--dev", is_flag=True, help="Use development branch")
def cli(dev):
if not dev and __version__ == get_latest_version():
return click.secho(
"You're up-to-date!\nPlatformIO %s is currently the "
"newest version available." % __version__,
fg="green")
else:
click.secho("Please wait while upgrading PlatformIO ...", fg="yellow")
to_develop = not all([c.isdigit() for c in latest if c != "."])
cmds = ([
"pip", "install", "--upgrade",
"https://github.com/platformio/platformio-core/archive/develop.zip"
if to_develop else "platformio"
], ["platformio", "--version"])
click.secho("Please wait while upgrading PlatformIO ...", fg="yellow")
cmd = None
r = None
try:
for cmd in cmds:
cmd = [util.get_pythonexe_path(), "-m"] + cmd
r = None
r = util.exec_command(cmd)
to_develop = dev or not all(c.isdigit() for c in __version__ if c != ".")
cmds = (["pip", "install", "--upgrade",
get_pip_package(to_develop)], ["platformio", "--version"])
# try pip with disabled cache
if r['returncode'] != 0 and cmd[2] == "pip":
cmd.insert(3, "--no-cache-dir")
r = util.exec_command(cmd)
cmd = None
r = {}
try:
for cmd in cmds:
cmd = [get_pythonexe_path(), "-m"] + cmd
r = exec_command(cmd)
assert r['returncode'] == 0
assert "version" in r['out']
actual_version = r['out'].strip().split("version", 1)[1].strip()
click.secho(
"PlatformIO has been successfully upgraded to %s" %
actual_version,
fg="green")
click.echo("Release notes: ", nl=False)
click.secho(
"http://docs.platformio.org/en/latest/history.html", fg="cyan")
except Exception as e: # pylint: disable=W0703
if not r:
raise exception.UpgradeError("\n".join([str(cmd), str(e)]))
permission_errors = ("permission denied", "not permitted")
if (any([m in r['err'].lower() for m in permission_errors]) and
"windows" not in util.get_systype()):
click.secho(
"""
# try pip with disabled cache
if r['returncode'] != 0 and cmd[2] == "pip":
cmd.insert(3, "--no-cache-dir")
r = exec_command(cmd)
assert r['returncode'] == 0
assert "version" in r['out']
actual_version = r['out'].strip().split("version", 1)[1].strip()
click.secho("PlatformIO has been successfully upgraded to %s" %
actual_version,
fg="green")
click.echo("Release notes: ", nl=False)
click.secho("https://docs.platformio.org/en/latest/history.html",
fg="cyan")
except Exception as e: # pylint: disable=broad-except
if not r:
raise exception.UpgradeError("\n".join([str(cmd), str(e)]))
permission_errors = ("permission denied", "not permitted")
if (any(m in r['err'].lower() for m in permission_errors)
and not WINDOWS):
click.secho("""
-----------------
Permission denied
-----------------
@@ -79,12 +78,36 @@ You need the `sudo` permission to install Python packages. Try
WARNING! Don't use `sudo` for the rest PlatformIO commands.
""",
fg="yellow",
err=True)
raise exception.ReturnErrorCode(1)
else:
raise exception.UpgradeError(
"\n".join([str(cmd), r['out'], r['err']]))
fg="yellow",
err=True)
raise exception.ReturnErrorCode(1)
raise exception.UpgradeError("\n".join([str(cmd), r['out'], r['err']]))
return True
def get_pip_package(to_develop):
if not to_develop:
return "platformio"
dl_url = ("https://github.com/platformio/"
"platformio-core/archive/develop.zip")
cache_dir = get_project_cache_dir()
if not os.path.isdir(cache_dir):
os.makedirs(cache_dir)
pkg_name = os.path.join(cache_dir, "piocoredevelop.zip")
try:
with open(pkg_name, "w") as fp:
r = exec_command(["curl", "-fsSL", dl_url],
stdout=fp,
universal_newlines=True)
assert r['returncode'] == 0
# check ZIP structure
with ZipFile(pkg_name) as zp:
assert zp.testzip() is None
return pkg_name
except: # pylint: disable=bare-except
pass
return dl_url
def get_latest_version():
@@ -122,8 +145,7 @@ def get_develop_latest_version():
def get_pypi_latest_version():
r = requests.get(
"https://pypi.python.org/pypi/platformio/json",
headers=util.get_request_defheaders())
r = requests.get("https://pypi.org/pypi/platformio/json",
headers=util.get_request_defheaders())
r.raise_for_status()
return r.json()['info']['version']

108
platformio/compat.py Normal file
View File

@@ -0,0 +1,108 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# pylint: disable=unused-import
import json
import os
import re
import sys
PY2 = sys.version_info[0] == 2
CYGWIN = sys.platform.startswith('cygwin')
WINDOWS = sys.platform.startswith('win')
def get_filesystem_encoding():
return sys.getfilesystemencoding() or sys.getdefaultencoding()
if PY2:
# pylint: disable=undefined-variable
string_types = (str, unicode)
def is_bytes(x):
return isinstance(x, (buffer, bytearray))
def path_to_unicode(path):
if isinstance(path, unicode):
return path
return path.decode(get_filesystem_encoding()).encode("utf-8")
def get_file_contents(path):
with open(path) as f:
return f.read()
def hashlib_encode_data(data):
if is_bytes(data):
return data
if isinstance(data, unicode):
data = data.encode(get_filesystem_encoding())
elif not isinstance(data, string_types):
data = str(data)
return data
def dump_json_to_unicode(obj):
if isinstance(obj, unicode):
return obj
return json.dumps(obj,
encoding=get_filesystem_encoding(),
ensure_ascii=False,
sort_keys=True).encode("utf8")
_magic_check = re.compile('([*?[])')
_magic_check_bytes = re.compile(b'([*?[])')
def glob_escape(pathname):
"""Escape all special characters."""
# https://github.com/python/cpython/blob/master/Lib/glob.py#L161
# Escaping is done by wrapping any of "*?[" between square brackets.
# Metacharacters do not work in the drive part and shouldn't be
# escaped.
drive, pathname = os.path.splitdrive(pathname)
if isinstance(pathname, bytes):
pathname = _magic_check_bytes.sub(br'[\1]', pathname)
else:
pathname = _magic_check.sub(r'[\1]', pathname)
return drive + pathname
else:
from glob import escape as glob_escape # pylint: disable=no-name-in-module
string_types = (str, )
def is_bytes(x):
return isinstance(x, (bytes, memoryview, bytearray))
def path_to_unicode(path):
return path
def get_file_contents(path):
try:
with open(path) as f:
return f.read()
except UnicodeDecodeError:
with open(path, encoding="latin-1") as f:
return f.read()
def hashlib_encode_data(data):
if is_bytes(data):
return data
if not isinstance(data, string_types):
data = str(data)
return data.encode()
def dump_json_to_unicode(obj):
if isinstance(obj, string_types):
return obj
return json.dumps(obj, ensure_ascii=False, sort_keys=True)

View File

@@ -15,14 +15,16 @@
from email.utils import parsedate_tz
from math import ceil
from os.path import getsize, join
from sys import version_info
from time import mktime
import click
import requests
from platformio import app, util
from platformio import util
from platformio.exception import (FDSHASumMismatch, FDSizeMismatch,
FDUnrecognizedStatusCode)
from platformio.proc import exec_command
class FileDownloader(object):
@@ -30,22 +32,22 @@ class FileDownloader(object):
CHUNK_SIZE = 1024
def __init__(self, url, dest_dir=None):
self._request = None
# make connection
self._request = requests.get(
url, stream=True, headers=util.get_request_defheaders())
self._request = requests.get(url,
stream=True,
headers=util.get_request_defheaders(),
verify=version_info >= (2, 7, 9))
if self._request.status_code != 200:
raise FDUnrecognizedStatusCode(self._request.status_code, url)
disposition = self._request.headers.get("content-disposition")
if disposition and "filename=" in disposition:
self._fname = disposition[
disposition.index("filename=") + 9:].replace('"', "").replace(
"'", "")
self._fname = self._fname.encode("utf8")
self._fname = disposition[disposition.index("filename=") +
9:].replace('"', "").replace("'", "")
else:
self._fname = url.split("/")[-1]
self._progressbar = None
self._fname = [p for p in url.split("/") if p][-1]
self._fname = str(self._fname)
self._destination = self._fname
if dest_dir:
self.set_destination(join(dest_dir, self._fname))
@@ -64,50 +66,54 @@ class FileDownloader(object):
return -1
return int(self._request.headers['content-length'])
def start(self):
def start(self, with_progress=True):
label = "Downloading"
itercontent = self._request.iter_content(chunk_size=self.CHUNK_SIZE)
f = open(self._destination, "wb")
if app.is_disabled_progressbar() or self.get_size() == -1:
click.echo("Downloading...")
for chunk in itercontent:
if chunk:
f.write(chunk)
else:
chunks = int(ceil(self.get_size() / float(self.CHUNK_SIZE)))
with click.progressbar(length=chunks, label="Downloading") as pb:
for _ in pb:
f.write(next(itercontent))
f.close()
self._request.close()
try:
if not with_progress or self.get_size() == -1:
click.echo("%s..." % label)
for chunk in itercontent:
if chunk:
f.write(chunk)
else:
chunks = int(ceil(self.get_size() / float(self.CHUNK_SIZE)))
with click.progressbar(length=chunks, label=label) as pb:
for _ in pb:
f.write(next(itercontent))
finally:
f.close()
self._request.close()
if self.get_lmtime():
self._preserve_filemtime(self.get_lmtime())
return True
def verify(self, sha1=None):
_dlsize = getsize(self._destination)
if self.get_size() != -1 and _dlsize != self.get_size():
raise FDSizeMismatch(_dlsize, self._fname, self.get_size())
if not sha1:
return
return None
dlsha1 = None
try:
result = util.exec_command(["sha1sum", self._destination])
result = exec_command(["sha1sum", self._destination])
dlsha1 = result['out']
except (OSError, ValueError):
try:
result = util.exec_command(
["shasum", "-a", "1", self._destination])
result = exec_command(["shasum", "-a", "1", self._destination])
dlsha1 = result['out']
except (OSError, ValueError):
pass
if dlsha1:
dlsha1 = dlsha1[1:41] if dlsha1.startswith("\\") else dlsha1[:40]
if sha1 != dlsha1:
raise FDSHASumMismatch(dlsha1, self._fname, sha1)
if not dlsha1:
return None
dlsha1 = dlsha1[1:41] if dlsha1.startswith("\\") else dlsha1[:40]
if sha1.lower() != dlsha1.lower():
raise FDSHASumMismatch(dlsha1, self._fname, sha1)
return True
def _preserve_filemtime(self, lmdate):
timedata = parsedate_tz(lmdate)

View File

@@ -19,8 +19,10 @@ class PlatformioException(Exception):
def __str__(self): # pragma: no cover
if self.MESSAGE:
# pylint: disable=not-an-iterable
return self.MESSAGE.format(*self.args)
return Exception.__str__(self)
return super(PlatformioException, self).__str__()
class ReturnErrorCode(PlatformioException):
@@ -28,15 +30,28 @@ class ReturnErrorCode(PlatformioException):
MESSAGE = "{0}"
class LockFileTimeoutError(PlatformioException):
pass
class MinitermException(PlatformioException):
pass
class AbortedByUser(PlatformioException):
class UserSideException(PlatformioException):
pass
class AbortedByUser(UserSideException):
MESSAGE = "Aborted by user"
#
# Development Platform
#
class UnknownPlatform(PlatformioException):
MESSAGE = "Unknown development platform '{0}'"
@@ -49,15 +64,8 @@ class IncompatiblePlatform(PlatformioException):
class PlatformNotInstalledYet(PlatformioException):
MESSAGE = "The platform '{0}' has not been installed yet. "\
"Use `platformio platform install {0}` command"
class BoardNotDefined(PlatformioException):
MESSAGE = "You need to specify board ID using `-b` or `--board` "\
"option. Supported boards list is available via "\
"`platformio boards` command"
MESSAGE = ("The platform '{0}' has not been installed yet. "
"Use `platformio platform install {0}` command")
class UnknownBoard(PlatformioException):
@@ -75,74 +83,163 @@ class UnknownFramework(PlatformioException):
MESSAGE = "Unknown framework '{0}'"
class UnknownPackage(PlatformioException):
# Package Manager
class PlatformIOPackageException(PlatformioException):
pass
class UnknownPackage(PlatformIOPackageException):
MESSAGE = "Detected unknown package '{0}'"
class MissingPackageManifest(PlatformioException):
class MissingPackageManifest(PlatformIOPackageException):
MESSAGE = "Could not find one of '{0}' manifest files in the package"
class UndefinedPackageVersion(PlatformioException):
class UndefinedPackageVersion(PlatformIOPackageException):
MESSAGE = "Could not find a version that satisfies the requirement '{0}'"\
" for your system '{1}'"
MESSAGE = ("Could not find a version that satisfies the requirement '{0}'"
" for your system '{1}'")
class PackageInstallError(PlatformioException):
class PackageInstallError(PlatformIOPackageException):
MESSAGE = "Could not install '{0}' with version requirements '{1}' "\
"for your system '{2}'.\n"\
"If you use Antivirus, it can block PlatformIO Package "\
"Manager. Try to disable it for a while."
MESSAGE = ("Could not install '{0}' with version requirements '{1}' "
"for your system '{2}'.\n\n"
"Please try this solution -> http://bit.ly/faq-package-manager")
class FDUnrecognizedStatusCode(PlatformioException):
class ExtractArchiveItemError(PlatformIOPackageException):
MESSAGE = "Got an unrecognized status code '{0}' when downloaded {1}"
MESSAGE = (
"Could not extract `{0}` to `{1}`. Try to disable antivirus "
"tool or check this solution -> http://bit.ly/faq-package-manager")
class FDSizeMismatch(PlatformioException):
MESSAGE = "The size ({0:d} bytes) of downloaded file '{1}' "\
"is not equal to remote size ({2:d} bytes)"
class FDSHASumMismatch(PlatformioException):
MESSAGE = "The 'sha1' sum '{0}' of downloaded file '{1}' "\
"is not equal to remote '{2}'"
class NotPlatformIOProject(PlatformioException):
MESSAGE = "Not a PlatformIO project. `platformio.ini` file has not been "\
"found in current working directory ({0}). To initialize new project "\
"please use `platformio init` command"
class UndefinedEnvPlatform(PlatformioException):
MESSAGE = "Please specify platform for '{0}' environment"
class UnsupportedArchiveType(PlatformioException):
class UnsupportedArchiveType(PlatformIOPackageException):
MESSAGE = "Can not unpack file '{0}'"
class ProjectEnvsNotAvailable(PlatformioException):
class FDUnrecognizedStatusCode(PlatformIOPackageException):
MESSAGE = "Got an unrecognized status code '{0}' when downloaded {1}"
class FDSizeMismatch(PlatformIOPackageException):
MESSAGE = ("The size ({0:d} bytes) of downloaded file '{1}' "
"is not equal to remote size ({2:d} bytes)")
class FDSHASumMismatch(PlatformIOPackageException):
MESSAGE = ("The 'sha1' sum '{0}' of downloaded file '{1}' "
"is not equal to remote '{2}'")
#
# Project
#
class PlatformIOProjectException(PlatformioException):
pass
class NotPlatformIOProject(PlatformIOProjectException):
MESSAGE = (
"Not a PlatformIO project. `platformio.ini` file has not been "
"found in current working directory ({0}). To initialize new project "
"please use `platformio init` command")
class InvalidProjectConf(PlatformIOProjectException):
MESSAGE = ("Invalid '{0}' (project configuration file): '{1}'")
class UndefinedEnvPlatform(PlatformIOProjectException):
MESSAGE = "Please specify platform for '{0}' environment"
class ProjectEnvsNotAvailable(PlatformIOProjectException):
MESSAGE = "Please setup environments in `platformio.ini` file"
class UnknownEnvNames(PlatformioException):
class UnknownEnvNames(PlatformIOProjectException):
MESSAGE = "Unknown environment names '{0}'. Valid names are '{1}'"
class ProjectOptionValueError(PlatformIOProjectException):
MESSAGE = "{0} for option `{1}` in section [{2}]"
#
# Library
#
class LibNotFound(PlatformioException):
MESSAGE = ("Library `{0}` has not been found in PlatformIO Registry.\n"
"You can ignore this message, if `{0}` is a built-in library "
"(included in framework, SDK). E.g., SPI, Wire, etc.")
class NotGlobalLibDir(UserSideException):
MESSAGE = (
"The `{0}` is not a PlatformIO project.\n\n"
"To manage libraries in global storage `{1}`,\n"
"please use `platformio lib --global {2}` or specify custom storage "
"`platformio lib --storage-dir /path/to/storage/ {2}`.\n"
"Check `platformio lib --help` for details.")
class InvalidLibConfURL(PlatformioException):
MESSAGE = "Invalid library config URL '{0}'"
#
# UDEV Rules
#
class InvalidUdevRules(PlatformioException):
pass
class MissedUdevRules(InvalidUdevRules):
MESSAGE = (
"Warning! Please install `99-platformio-udev.rules`. \nMode details: "
"https://docs.platformio.org/en/latest/faq.html#platformio-udev-rules")
class OutdatedUdevRules(InvalidUdevRules):
MESSAGE = (
"Warning! Your `{0}` are outdated. Please update or reinstall them."
"\n Mode details: https://docs.platformio.org"
"/en/latest/faq.html#platformio-udev-rules")
#
# Misc
#
class GetSerialPortsError(PlatformioException):
MESSAGE = "No implementation for your platform ('{0}') available"
@@ -158,31 +255,12 @@ class APIRequestError(PlatformioException):
MESSAGE = "[API] {0}"
class InternetIsOffline(PlatformioException):
class InternetIsOffline(UserSideException):
MESSAGE = "You are not connected to the Internet"
class LibNotFound(PlatformioException):
MESSAGE = "Library `{0}` has not been found in PlatformIO Registry.\n"\
"You can ignore this message, if `{0}` is a built-in library "\
"(included in framework, SDK). E.g., SPI, Wire, etc."
class NotGlobalLibDir(PlatformioException):
MESSAGE = "The `{0}` is not a PlatformIO project.\n\n"\
"To manage libraries "\
"in global storage `{1}`,\n"\
"please use `platformio lib --global {2}` or specify custom "\
"storage `platformio lib --storage-dir /path/to/storage/ {2}`."\
"\nCheck `platformio lib --help` for details."
class InvalidLibConfURL(PlatformioException):
MESSAGE = "Invalid library config URL '{0}'"
MESSAGE = (
"You are not connected to the Internet.\n"
"If you build a project first time, we need Internet connection "
"to install all dependencies and toolchains.")
class BuildScriptNotFound(PlatformioException):
@@ -200,11 +278,16 @@ class InvalidSettingValue(PlatformioException):
MESSAGE = "Invalid value '{0}' for the setting '{1}'"
class InvalidJSONFile(PlatformioException):
MESSAGE = "Could not load broken JSON: {0}"
class CIBuildEnvsEmpty(PlatformioException):
MESSAGE = "Can't find PlatformIO build environments.\n"\
"Please specify `--board` or path to `platformio.ini` with "\
"predefined environments using `--project-conf` option"
MESSAGE = ("Can't find PlatformIO build environments.\n"
"Please specify `--board` or path to `platformio.ini` with "
"predefined environments using `--project-conf` option")
class UpgradeError(PlatformioException):
@@ -213,11 +296,43 @@ class UpgradeError(PlatformioException):
* Upgrade using `pip install -U platformio`
* Try different installation/upgrading steps:
http://docs.platformio.org/page/installation.html
https://docs.platformio.org/page/installation.html
"""
class HomeDirPermissionsError(PlatformioException):
MESSAGE = (
"The directory `{0}` or its parent directory is not owned by the "
"current user and PlatformIO can not store configuration data.\n"
"Please check the permissions and owner of that directory.\n"
"Otherwise, please remove manually `{0}` directory and PlatformIO "
"will create new from the current user.")
class CygwinEnvDetected(PlatformioException):
MESSAGE = "PlatformIO does not work within Cygwin environment. "\
"Use native Terminal instead."
MESSAGE = ("PlatformIO does not work within Cygwin environment. "
"Use native Terminal instead.")
class DebugSupportError(PlatformioException):
MESSAGE = (
"Currently, PlatformIO does not support debugging for `{0}`.\n"
"Please request support at https://github.com/platformio/"
"platformio-core/issues \nor visit -> https://docs.platformio.org"
"/page/plus/debugging.html")
class DebugInvalidOptions(PlatformioException):
pass
class TestDirNotExists(PlatformioException):
MESSAGE = "A test folder '{0}' does not exist.\nPlease create 'test' "\
"directory in project's root and put a test set.\n"\
"More details about Unit "\
"Testing: http://docs.platformio.org/page/plus/"\
"unit-testing.html"

163
platformio/fs.py Normal file
View File

@@ -0,0 +1,163 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import os
import re
import shutil
import stat
import sys
from glob import glob
import click
from platformio import exception
from platformio.compat import get_file_contents, glob_escape
class cd(object):
def __init__(self, new_path):
self.new_path = new_path
self.prev_path = os.getcwd()
def __enter__(self):
os.chdir(self.new_path)
def __exit__(self, etype, value, traceback):
os.chdir(self.prev_path)
def get_source_dir():
curpath = os.path.abspath(__file__)
if not os.path.isfile(curpath):
for p in sys.path:
if os.path.isfile(os.path.join(p, __file__)):
curpath = os.path.join(p, __file__)
break
return os.path.dirname(curpath)
def load_json(file_path):
try:
with open(file_path, "r") as f:
return json.load(f)
except ValueError:
raise exception.InvalidJSONFile(file_path)
def format_filesize(filesize):
base = 1024
unit = 0
suffix = "B"
filesize = float(filesize)
if filesize < base:
return "%d%s" % (filesize, suffix)
for i, suffix in enumerate("KMGTPEZY"):
unit = base**(i + 2)
if filesize >= unit:
continue
if filesize % (base**(i + 1)):
return "%.2f%sB" % ((base * filesize / unit), suffix)
break
return "%d%sB" % ((base * filesize / unit), suffix)
def ensure_udev_rules():
from platformio.util import get_systype
def _rules_to_set(rules_path):
return set(l.strip() for l in get_file_contents(rules_path).split("\n")
if l.strip() and not l.startswith("#"))
if "linux" not in get_systype():
return None
installed_rules = [
"/etc/udev/rules.d/99-platformio-udev.rules",
"/lib/udev/rules.d/99-platformio-udev.rules"
]
if not any(os.path.isfile(p) for p in installed_rules):
raise exception.MissedUdevRules
origin_path = os.path.abspath(
os.path.join(get_source_dir(), "..", "scripts",
"99-platformio-udev.rules"))
if not os.path.isfile(origin_path):
return None
origin_rules = _rules_to_set(origin_path)
for rules_path in installed_rules:
if not os.path.isfile(rules_path):
continue
current_rules = _rules_to_set(rules_path)
if not origin_rules <= current_rules:
raise exception.OutdatedUdevRules(rules_path)
return True
def path_endswith_ext(path, extensions):
if not isinstance(extensions, (list, tuple)):
extensions = [extensions]
for ext in extensions:
if path.endswith("." + ext):
return True
return False
def match_src_files(src_dir, src_filter=None, src_exts=None):
def _append_build_item(items, item, src_dir):
if not src_exts or path_endswith_ext(item, src_exts):
items.add(item.replace(src_dir + os.sep, ""))
src_filter = src_filter or ""
if isinstance(src_filter, (list, tuple)):
src_filter = " ".join(src_filter)
matches = set()
# correct fs directory separator
src_filter = src_filter.replace("/", os.sep).replace("\\", os.sep)
for (action, pattern) in re.findall(r"(\+|\-)<([^>]+)>", src_filter):
items = set()
for item in glob(os.path.join(glob_escape(src_dir), pattern)):
if os.path.isdir(item):
for root, _, files in os.walk(item, followlinks=True):
for f in files:
_append_build_item(items, os.path.join(root, f),
src_dir)
else:
_append_build_item(items, item, src_dir)
if action == "+":
matches |= items
else:
matches -= items
return sorted(list(matches))
def rmtree(path):
def _onerror(func, path, __):
try:
st_mode = os.stat(path).st_mode
if st_mode & stat.S_IREAD:
os.chmod(path, st_mode | stat.S_IWRITE)
func(path)
except Exception as e: # pylint: disable=broad-except
click.secho("%s \nPlease manually remove the file `%s`" %
(str(e), path),
fg="red",
err=True)
return shutil.rmtree(path, onerror=_onerror)

View File

@@ -12,91 +12,118 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import codecs
import os
import re
from cStringIO import StringIO
import sys
from os.path import abspath, basename, expanduser, isdir, isfile, join, relpath
import bottle
import click
from platformio import exception, util
from platformio.commands.run import cli as cmd_run
from platformio import fs, util
from platformio.compat import WINDOWS, get_file_contents
from platformio.proc import where_is_program
from platformio.project.config import ProjectConfig
from platformio.project.helpers import (get_project_lib_dir,
get_project_libdeps_dir,
get_project_src_dir,
load_project_ide_data)
class ProjectGenerator(object):
def __init__(self, project_dir, ide, env_name):
def __init__(self, project_dir, ide, boards):
self.config = ProjectConfig.get_instance(
join(project_dir, "platformio.ini"))
self.config.validate()
self.project_dir = project_dir
self.ide = ide
self.env_name = env_name
self._tplvars = {}
with util.cd(self.project_dir):
self.project_src_dir = util.get_projectsrc_dir()
self._gather_tplvars()
self.ide = str(ide)
self.env_name = str(self.get_best_envname(boards))
@staticmethod
def get_supported_ides():
tpls_dir = join(util.get_source_dir(), "ide", "tpls")
tpls_dir = join(fs.get_source_dir(), "ide", "tpls")
return sorted(
[d for d in os.listdir(tpls_dir) if isdir(join(tpls_dir, d))])
@util.memoized
def get_project_env(self):
data = None
config = util.load_project_config(self.project_dir)
for section in config.sections():
if not section.startswith("env:"):
def get_best_envname(self, boards=None):
envname = None
default_envs = self.config.default_envs()
if default_envs:
envname = default_envs[0]
if not boards:
return envname
for env in self.config.envs():
if not boards:
return env
if not envname:
envname = env
items = self.config.items(env=env, as_dict=True)
if "board" in items and items.get("board") in boards:
return env
return envname
def _load_tplvars(self):
tpl_vars = {
"config": self.config,
"systype": util.get_systype(),
"project_name": basename(self.project_dir),
"project_dir": self.project_dir,
"env_name": self.env_name,
"user_home_dir": abspath(expanduser("~")),
"platformio_path":
sys.argv[0] if isfile(sys.argv[0])
else where_is_program("platformio"),
"env_path": os.getenv("PATH"),
"env_pathsep": os.pathsep
} # yapf: disable
# default env configuration
tpl_vars.update(self.config.items(env=self.env_name, as_dict=True))
# build data
tpl_vars.update(
load_project_ide_data(self.project_dir, self.env_name) or {})
with fs.cd(self.project_dir):
tpl_vars.update({
"src_files": self.get_src_files(),
"project_src_dir": get_project_src_dir(),
"project_lib_dir": get_project_lib_dir(),
"project_libdeps_dir": join(
get_project_libdeps_dir(), self.env_name)
}) # yapf: disable
for key, value in tpl_vars.items():
if key.endswith(("_path", "_dir")):
tpl_vars[key] = self.to_unix_path(value)
for key in ("includes", "src_files", "libsource_dirs"):
if key not in tpl_vars:
continue
if self.env_name != section[4:]:
continue
data = {"env_name": section[4:]}
for k, v in config.items(section):
data[k] = v
return data
tpl_vars[key] = [self.to_unix_path(inc) for inc in tpl_vars[key]]
@util.memoized
def get_project_build_data(self):
data = {"defines": [], "includes": [], "cxx_path": None}
envdata = self.get_project_env()
if not envdata:
return data
tpl_vars['to_unix_path'] = self.to_unix_path
return tpl_vars
out = StringIO()
with util.capture_stdout(out):
click.get_current_context().invoke(
cmd_run,
project_dir=self.project_dir,
environment=[envdata['env_name']],
target=["idedata"])
result = out.getvalue()
if '"includes":' not in result:
raise exception.PlatformioException(result)
for line in result.split("\n"):
line = line.strip()
if line.startswith('{"') and line.endswith("}"):
data = json.loads(line)
return data
def get_project_name(self):
return basename(self.project_dir)
@staticmethod
def to_unix_path(path):
if not WINDOWS or not path:
return path
return re.sub(r"[\\]+", "/", path)
def get_src_files(self):
result = []
with util.cd(self.project_dir):
for root, _, files in os.walk(self.project_src_dir):
with fs.cd(self.project_dir):
for root, _, files in os.walk(get_project_src_dir()):
for f in files:
result.append(relpath(join(root, f)))
return result
def get_tpls(self):
tpls = []
tpls_dir = join(util.get_source_dir(), "ide", "tpls", self.ide)
tpls_dir = join(fs.get_source_dir(), "ide", "tpls", self.ide)
for root, _, files in os.walk(tpls_dir):
for f in files:
if not f.endswith(".tpl"):
@@ -108,6 +135,7 @@ class ProjectGenerator(object):
return tpls
def generate(self):
tpl_vars = self._load_tplvars()
for tpl_relpath, tpl_path in self.get_tpls():
dst_dir = self.project_dir
if tpl_relpath:
@@ -116,62 +144,16 @@ class ProjectGenerator(object):
os.makedirs(dst_dir)
file_name = basename(tpl_path)[:-4]
self._merge_contents(
join(dst_dir, file_name),
self._render_tpl(tpl_path).encode("utf8"))
contents = self._render_tpl(tpl_path, tpl_vars)
self._merge_contents(join(dst_dir, file_name), contents)
def _render_tpl(self, tpl_path):
content = ""
with open(tpl_path) as f:
content = f.read()
return bottle.template(content, **self._tplvars)
@staticmethod
def _render_tpl(tpl_path, tpl_vars):
return bottle.template(get_file_contents(tpl_path), **tpl_vars)
@staticmethod
def _merge_contents(dst_path, contents):
file_name = basename(dst_path)
# merge .gitignore
if file_name == ".gitignore" and isfile(dst_path):
modified = False
default = [l.strip() for l in contents.split("\n")]
with open(dst_path) as fp:
current = [l.strip() for l in fp.readlines()]
for d in default:
if d and d not in current:
modified = True
current.append(d)
if not modified:
return
contents = "\n".join(current) + "\n"
with open(dst_path, "w") as f:
f.write(contents)
def _gather_tplvars(self):
self._tplvars.update(self.get_project_env())
self._tplvars.update(self.get_project_build_data())
self._tplvars.update({
"project_name":
self.get_project_name(),
"src_files":
self.get_src_files(),
"user_home_dir":
abspath(expanduser("~")),
"project_dir":
self.project_dir,
"project_src_dir":
self.project_src_dir,
"systype":
util.get_systype(),
"platformio_path":
self._fix_os_path(util.where_is_program("platformio")),
"env_pathsep":
os.pathsep,
"env_path":
self._fix_os_path(os.getenv("PATH"))
})
@staticmethod
def _fix_os_path(path):
return (re.sub(r"[\\]+", '\\' * 4, path)
if "windows" in util.get_systype() else path)
if basename(dst_path) == ".gitignore" and isfile(dst_path):
return
with codecs.open(dst_path, "w", encoding="utf8") as fp:
fp.write(contents)

View File

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

View File

@@ -1,8 +1,9 @@
% _defines = " ".join(["-D%s" % d for d in defines])
{
"execPath": "{{ cxx_path.replace("\\", "/") }}",
"gccDefaultCFlags": "-fsyntax-only {{! cc_flags.replace(' -MMD ', ' ').replace('"', '\\"') }}",
"gccDefaultCppFlags": "-fsyntax-only {{! cxx_flags.replace(' -MMD ', ' ').replace('"', '\\"') }}",
"execPath": "{{ cxx_path }}",
"gccDefaultCFlags": "-fsyntax-only {{! cc_flags.replace(' -MMD ', ' ').replace('"', '\\"') }} {{ !_defines.replace('"', '\\"') }}",
"gccDefaultCppFlags": "-fsyntax-only {{! cxx_flags.replace(' -MMD ', ' ').replace('"', '\\"') }} {{ !_defines.replace('"', '\\"') }}",
"gccErrorLimit": 15,
"gccIncludePaths": "{{ ','.join(includes).replace("\\", "/") }}",
"gccIncludePaths": "{{ ','.join(includes) }}",
"gccSuppressWarnings": false
}

View File

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

View File

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

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
<component name="CidrRootsConfiguration">
<sourceRoots>
<file path="$PROJECT_DIR$/src" />
</sourceRoots>
<libraryRoots>
<file path="$PROJECT_DIR$/lib" />
<file path="$PROJECT_DIR$/.pio/libdeps" />
</libraryRoots>
<excludeRoots>
<file path="$PROJECT_DIR$/.pio" />
</excludeRoots>
</component>
</project>

View File

@@ -15,7 +15,7 @@
<FilterInfo>
<option name="description" value="" />
<option name="name" value="PIO Conf" />
<option name="regExp" value="$FILE_PATH$:^platofrmio" />
<option name="regExp" value="$FILE_PATH$:^platformio" />
</FilterInfo>
</array>
</option>

View File

@@ -1,14 +1,31 @@
# !!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE
# https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags
#
# If you need to override existing CMake configuration or add extra,
# please create `CMakeListsUser.txt` in the root of project.
# The `CMakeListsUser.txt` will not be overwritten by PlatformIO.
cmake_minimum_required(VERSION 3.2)
project({{project_name}})
include(CMakeListsPrivate.txt)
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/CMakeListsUser.txt)
include(CMakeListsUser.txt)
endif()
add_custom_target(
PLATFORMIO_BUILD ALL
COMMAND ${PLATFORMIO_CMD} -f -c clion run
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(
PLATFORMIO_BUILD_VERBOSE ALL
COMMAND ${PLATFORMIO_CMD} -f -c clion run --verbose
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(
PLATFORMIO_UPLOAD ALL
COMMAND ${PLATFORMIO_CMD} -f -c clion run --target upload
@@ -21,6 +38,12 @@ add_custom_target(
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(
PLATFORMIO_MONITOR ALL
COMMAND ${PLATFORMIO_CMD} -f -c clion device monitor
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(
PLATFORMIO_TEST ALL
COMMAND ${PLATFORMIO_CMD} -f -c clion test

View File

@@ -1,26 +1,48 @@
set(ENV{PATH} "{{env_path}}")
set(PLATFORMIO_CMD "{{platformio_path}}")
# !!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE
# https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags
#
# If you need to override existing CMake configuration or add extra,
# please create `CMakeListsUser.txt` in the root of project.
# The `CMakeListsUser.txt` will not be overwritten by PlatformIO.
SET(CMAKE_C_COMPILER "{{cc_path.replace("\\", "/")}}")
SET(CMAKE_CXX_COMPILER "{{cxx_path.replace("\\", "/")}}")
% import re
%
% def _normalize_path(path):
% if project_dir in path:
% path = path.replace(project_dir, "${CMAKE_CURRENT_LIST_DIR}")
% elif user_home_dir in path:
% if "windows" in systype:
% path = path.replace(user_home_dir, "$ENV{HOMEDRIVE}$ENV{HOMEPATH}")
% else:
% path = path.replace(user_home_dir, "$ENV{HOME}")
% end
% end
% return path
% end
set(PLATFORMIO_CMD "{{ _normalize_path(platformio_path) }}")
SET(CMAKE_C_COMPILER "{{ _normalize_path(cc_path) }}")
SET(CMAKE_CXX_COMPILER "{{ _normalize_path(cxx_path) }}")
SET(CMAKE_CXX_FLAGS_DISTRIBUTION "{{cxx_flags}}")
SET(CMAKE_C_FLAGS_DISTRIBUTION "{{cc_flags}}")
set(CMAKE_CXX_STANDARD 11)
% STD_RE = re.compile(r"\-std=[a-z\+]+(\d+)")
% cc_stds = STD_RE.findall(cc_flags)
% cxx_stds = STD_RE.findall(cxx_flags)
% if cc_stds:
SET(CMAKE_C_STANDARD {{ cc_stds[-1] }})
% end
% if cxx_stds:
set(CMAKE_CXX_STANDARD {{ cxx_stds[-1] }})
% end
% for define in defines:
add_definitions(-D{{!define}})
add_definitions(-D'{{!re.sub(r"([\"\(\)#])", r"\\\1", define)}}')
% end
% for include in includes:
% if include.startswith(user_home_dir):
% if "windows" in systype:
include_directories("$ENV{HOMEDRIVE}$ENV{HOMEPATH}{{include.replace(user_home_dir, '').replace("\\", "/")}}")
% else:
include_directories("$ENV{HOME}{{include.replace(user_home_dir, '').replace("\\", "/")}}")
% end
% else:
include_directories("{{include.replace("\\", "/")}}")
% end
include_directories("{{ _normalize_path(include) }}")
% end
FILE(GLOB_RECURSE SRC_LIST "{{project_src_dir.replace("\\", "/")}}/*.*")
FILE(GLOB_RECURSE SRC_LIST "{{ _normalize_path(project_src_dir) }}/*.*" "{{ _normalize_path(project_lib_dir) }}/*.*" "{{ _normalize_path(project_libdeps_dir) }}/*.*")

View File

@@ -53,12 +53,12 @@
<Add option="-D{{define}}"/>
% end
% for include in includes:
<Add directory="{{include.replace("\\", "/")}}"/>
% end
<Add directory="{{include}}"/>
% end
</Compiler>
<Unit filename="platformio.ini" />
% for file in src_files:
<Unit filename="{{file.replace("\\", "/")}}"></Unit>
<Unit filename="{{file}}"></Unit>
% end
</Project>
</CodeBlocks_project_file>

View File

@@ -5,13 +5,13 @@
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="0.910961921" moduleId="org.eclipse.cdt.core.settings" name="Default">
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
@@ -99,6 +99,104 @@
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
<cconfiguration id="0.910961921.1363900502">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="0.910961921.1363900502" moduleId="org.eclipse.cdt.core.settings" name="Debug">
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration artifactName="mbed" buildProperties="" description="" id="0.910961921.1363900502" name="Debug" parent="org.eclipse.cdt.build.core.prefbase.cfg">
<folderInfo id="0.910961921.1363900502." name="/" resourcePath="">
<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.2116690625" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">
<targetPlatform binaryParser="org.eclipse.cdt.core.ELF" id="org.eclipse.cdt.build.core.prefbase.toolchain.2116690625.848954921" name=""/>
<builder arguments="-f -c eclipse debug" cleanBuildTarget="run --target clean" command="platformio" enableCleanBuild="false" id="org.eclipse.cdt.build.core.settings.default.builder.985867833" incrementalBuildTarget="" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.libs.1855678035" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.30528994" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">
<option id="org.eclipse.cdt.build.core.settings.holder.incpaths.794801023" name="Include Paths" superClass="org.eclipse.cdt.build.core.settings.holder.incpaths" valueType="includePath">
% for include in includes:
% if "toolchain" in include:
% continue
% end
% if include.startswith(user_home_dir):
% if "windows" in systype:
<listOptionValue builtIn="false" value="${USERPROFILE}{{include.replace(user_home_dir, '')}}"/>
% else:
<listOptionValue builtIn="false" value="${HOME}{{include.replace(user_home_dir, '')}}"/>
% end
% else:
<listOptionValue builtIn="false" value="{{include}}"/>
% end
% end
</option>
<option id="org.eclipse.cdt.build.core.settings.holder.symbols.1743427839" name="Symbols" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" valueType="definedSymbols">
% for define in defines:
<listOptionValue builtIn="false" value="{{define}}"/>
% end
</option>
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.919136836" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.1146422798" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder">
<option id="org.eclipse.cdt.build.core.settings.holder.incpaths.650084869" name="Include Paths" superClass="org.eclipse.cdt.build.core.settings.holder.incpaths" useByScannerDiscovery="false" valueType="includePath">
% for include in includes:
% if "toolchain" in include:
% continue
% end
% if include.startswith(user_home_dir):
% if "windows" in systype:
<listOptionValue builtIn="false" value="${USERPROFILE}{{include.replace(user_home_dir, '')}}"/>
% else:
<listOptionValue builtIn="false" value="${HOME}{{include.replace(user_home_dir, '')}}"/>
% end
% else:
<listOptionValue builtIn="false" value="{{include}}"/>
% end
% end
</option>
<option id="org.eclipse.cdt.build.core.settings.holder.symbols.2055633423" name="Symbols" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" useByScannerDiscovery="false" valueType="definedSymbols">
% for define in defines:
<listOptionValue builtIn="false" value="{{define}}"/>
% end
</option>
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.445650141" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.1637357529" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">
<option id="org.eclipse.cdt.build.core.settings.holder.incpaths.1246337321" name="Include Paths" superClass="org.eclipse.cdt.build.core.settings.holder.incpaths" useByScannerDiscovery="false" valueType="includePath">
% for include in includes:
% if "toolchain" in include:
% continue
% end
% if include.startswith(user_home_dir):
% if "windows" in systype:
<listOptionValue builtIn="false" value="${USERPROFILE}{{include.replace(user_home_dir, '')}}"/>
% else:
<listOptionValue builtIn="false" value="${HOME}{{include.replace(user_home_dir, '')}}"/>
% end
% else:
<listOptionValue builtIn="false" value="{{include}}"/>
% end
% end
</option>
<option id="org.eclipse.cdt.build.core.settings.holder.symbols.2122043341" name="Symbols" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" useByScannerDiscovery="false" valueType="definedSymbols">
% for define in defines:
<listOptionValue builtIn="false" value="{{define}}"/>
% end
</option>
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.207004812" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
</toolChain>
</folderInfo>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="{{project_name}}.null.189551033" name="{{project_name}}"/>
@@ -121,17 +219,17 @@
<target name="PlatformIO: Upload using Programmer" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>platformio</buildCommand>
<buildArguments>-f -c eclipse</buildArguments>
<buildTarget>run -t program</buildTarget>
<buildTarget>run --target program</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>false</runAllBuilders>
</target>
<target name="PlatformIO: Upload SPIFFS image" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>platformio</buildCommand>
<buildArguments>-f -c eclipse</buildArguments>
<buildTarget>run -t uploadfs</buildTarget>
<buildTarget>run --target uploadfs</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>false</runAllBuilders>
</target>
<target name="PlatformIO: Build" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
@@ -139,23 +237,39 @@
<buildArguments>-f -c eclipse</buildArguments>
<buildTarget>run</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>false</runAllBuilders>
</target>
<target name="PlatformIO: Verbose Build" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>platformio</buildCommand>
<buildArguments>-f -c eclipse</buildArguments>
<buildTarget>run --verbose</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>false</runAllBuilders>
</target>
<target name="PlatformIO: Upload" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>platformio</buildCommand>
<buildArguments>-f -c eclipse</buildArguments>
<buildTarget>run -t upload</buildTarget>
<buildTarget>run --target upload</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>false</runAllBuilders>
</target>
<target name="PlatformIO: Verbose Upload" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>platformio</buildCommand>
<buildArguments>-f -c eclipse</buildArguments>
<buildTarget>run --target upload --verbose</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>false</runAllBuilders>
</target>
<target name="PlatformIO: Clean" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>platformio</buildCommand>
<buildArguments>-f -c eclipse</buildArguments>
<buildTarget>run -t clean</buildTarget>
<buildTarget>run --target clean</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>false</runAllBuilders>
</target>
<target name="PlatformIO: Test" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
@@ -163,15 +277,15 @@
<buildArguments>-f -c eclipse</buildArguments>
<buildTarget>test</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>false</runAllBuilders>
</target>
<target name="PlatformIO: Update platforms and libraries" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<target name="PlatformIO: Remote" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>platformio</buildCommand>
<buildArguments>-f -c eclipse</buildArguments>
<buildTarget>update</buildTarget>
<buildTarget>remote run --target upload</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>false</runAllBuilders>
</target>
<target name="PlatformIO: Rebuild C/C++ Project Index" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
@@ -179,7 +293,39 @@
<buildArguments>-f -c eclipse</buildArguments>
<buildTarget>init --ide eclipse</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>false</runAllBuilders>
</target>
<target name="PlatformIO: List Devices" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>platformio</buildCommand>
<buildArguments>-f -c eclipse</buildArguments>
<buildTarget>device list</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>false</runAllBuilders>
</target>
<target name="PlatformIO: Update Project Libraries" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>platformio</buildCommand>
<buildArguments>-f -c eclipse</buildArguments>
<buildTarget>lib update</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>false</runAllBuilders>
</target>
<target name="PlatformIO: Update All" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>platformio</buildCommand>
<buildArguments>-f -c eclipse</buildArguments>
<buildTarget>update</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>false</runAllBuilders>
</target>
<target name="PlatformIO: Upgrade Core" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>platformio</buildCommand>
<buildArguments>-f -c eclipse</buildArguments>
<buildTarget>upgrade</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>false</runAllBuilders>
</target>
</buildTargets>

View File

@@ -2,7 +2,7 @@
<launchConfiguration type="org.eclipse.cdt.launch.applicationLaunchType">
<booleanAttribute key="org.eclipse.cdt.dsf.gdb.AUTO_SOLIB" value="true"/>
<listAttribute key="org.eclipse.cdt.dsf.gdb.AUTO_SOLIB_LIST"/>
<stringAttribute key="org.eclipse.cdt.dsf.gdb.DEBUG_NAME" value="platformio -c eclipse debug -d ${project_loc} --interface=gdb"/>
<stringAttribute key="org.eclipse.cdt.dsf.gdb.DEBUG_NAME" value="piodebuggdb"/>
<booleanAttribute key="org.eclipse.cdt.dsf.gdb.DEBUG_ON_FORK" value="false"/>
<stringAttribute key="org.eclipse.cdt.dsf.gdb.GDB_INIT" value=".pioinit"/>
<booleanAttribute key="org.eclipse.cdt.dsf.gdb.NON_STOP" value="false"/>
@@ -12,17 +12,17 @@
<stringAttribute key="org.eclipse.cdt.dsf.gdb.TRACEPOINT_MODE" value="TP_NORMAL_ONLY"/>
<booleanAttribute key="org.eclipse.cdt.dsf.gdb.UPDATE_THREADLIST_ON_SUSPEND" value="false"/>
<booleanAttribute key="org.eclipse.cdt.dsf.gdb.internal.ui.launching.LocalApplicationCDebuggerTab.DEFAULTS_SET" value="true"/>
<intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="0"/>
<intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="1"/>
<stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/>
<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_ID" value="gdb"/>
<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_REGISTER_GROUPS" value=""/>
<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_START_MODE" value="run"/>
<booleanAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN" value="true"/>
<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN_SYMBOL" value="main"/>
<stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value=".pioenvs/{{env_name}}/firmware.elf"/>
<booleanAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN" value="false"/>
<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN_SYMBOL" value=""/>
<stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="{{prog_path}}"/>
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="{{project_name}}"/>
<booleanAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_AUTO_ATTR" value="false"/>
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value=""/>
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value="0.910961921.1363900502"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/{{project_name}}"/>
</listAttribute>

View File

@@ -1,3 +1,16 @@
% import re
% STD_RE = re.compile(r"(\-std=[a-z\+]+\d+)")
% cxx_stds = STD_RE.findall(cxx_flags)
% cxx_std = cxx_stds[-1] if cxx_stds else ""
%
% if cxx_path.startswith(user_home_dir):
% if "windows" in systype:
% cxx_path = "${USERPROFILE}" + cxx_path.replace(user_home_dir, "")
% else:
% cxx_path = "${HOME}" + cxx_path.replace(user_home_dir, "")
% end
% end
%
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project>
<configuration id="0.910961921" name="Default">
@@ -5,11 +18,18 @@
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
% if "windows" in systype:
<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="1291887707783033084" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${USERPROFILE}{{cxx_path.replace(user_home_dir, '')}} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
% else:
<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-869785120007741010" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${HOME}{{cxx_path.replace(user_home_dir, '')}} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
% end
<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="1291887707783033084" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="{{ cxx_path }} ${FLAGS} {{ cxx_std }} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
</extension>
</configuration>
<configuration id="0.910961921.1363900502" name="Debug">
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="1291887707783033084" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="{{ cxx_path }} ${FLAGS} {{ cxx_std }} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>

View File

@@ -1,6 +1,11 @@
eclipse.preferences.version=1
environment/project/0.910961921/PATH/delimiter={{env_pathsep.replace(":", "\\:")}}
environment/project/0.910961921/PATH/operation=replace
environment/project/0.910961921/PATH/value={{env_path.replace(":", "\\:")}}
environment/project/0.910961921/PATH/value={{env_path.replace(":", "\\:")}}${PathDelimiter}${PATH}
environment/project/0.910961921/append=true
environment/project/0.910961921/appendContributed=true
environment/project/0.910961921/appendContributed=true
environment/project/0.910961921.1363900502/PATH/delimiter={{env_pathsep.replace(":", "\\:")}}
environment/project/0.910961921.1363900502/PATH/operation=replace
environment/project/0.910961921.1363900502/PATH/value={{env_path.replace(":", "\\:")}}${PathDelimiter}${PATH}
environment/project/0.910961921.1363900502/append=true
environment/project/0.910961921.1363900502/appendContributed=true

View File

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

View File

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

View File

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

View File

@@ -14,7 +14,8 @@ INCLUDEPATH += "{{include}}"
% end
% for define in defines:
DEFINES += "{{define}}"
% tokens = define.split("##", 1)
DEFINES += "{{tokens[0].strip()}}"
% end
OTHER_FILES += platformio.ini

View File

@@ -4,7 +4,7 @@
{
"cmd":
[
"platformio",
"{{ platformio_path }}",
"-f", "-c", "sublimetext",
"run"
],
@@ -14,7 +14,7 @@
{
"cmd":
[
"platformio",
"{{ platformio_path }}",
"-f", "-c", "sublimetext",
"run"
],
@@ -23,27 +23,7 @@
{
"cmd":
[
"platformio",
"-f", "-c", "sublimetext",
"run",
"--target",
"clean"
],
"name": "Clean"
},
{
"cmd":
[
"platformio",
"-f", "-c", "sublimetext",
"test"
],
"name": "Test"
},
{
"cmd":
[
"platformio",
"{{ platformio_path }}",
"-f", "-c", "sublimetext",
"run",
"--target",
@@ -54,7 +34,27 @@
{
"cmd":
[
"platformio",
"{{ platformio_path }}",
"-f", "-c", "sublimetext",
"run",
"--target",
"clean"
],
"name": "Clean"
},
{
"cmd":
[
"{{ platformio_path }}",
"-f", "-c", "sublimetext",
"test"
],
"name": "Test"
},
{
"cmd":
[
"{{ platformio_path }}",
"-f", "-c", "sublimetext",
"run",
"--target",
@@ -65,7 +65,7 @@
{
"cmd":
[
"platformio",
"{{ platformio_path }}",
"-f", "-c", "sublimetext",
"run",
"--target",
@@ -76,16 +76,24 @@
{
"cmd":
[
"platformio",
"{{ platformio_path }}",
"-f", "-c", "sublimetext",
"update"
],
"name": "Update platforms and libraries"
},
{
"cmd":
[
"{{ platformio_path }}",
"-f", "-c", "sublimetext",
"upgrade"
],
"name": "Upgrade PlatformIO Core"
}
],
"working_dir": "${project_path:${folder}}",
"selector": "source.c, source.c++",
"path": "{{env_path}}"
"selector": "source.c, source.c++"
}
],
"folders":
@@ -97,8 +105,8 @@
"settings":
{
"sublimegdb_workingdir": "{{project_dir}}",
"sublimegdb_exec_cmd": "-exec-continue",
"sublimegdb_commandline": "{{platformio_path}} -f -c sublimetext debug --interface=gdb --interpreter=mi -x .pioinit"
"sublimegdb_exec_cmd": "",
"sublimegdb_commandline": "{{ platformio_path }} -f -c sublimetext debug --interface=gdb --interpreter=mi -x .pioinit"
}
}

View File

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

View File

@@ -1,8 +1,9 @@
% _defines = " ".join(["-D%s" % d for d in defines])
{
"execPath": "{{ cxx_path.replace("\\", "/") }}",
"gccDefaultCFlags": "-fsyntax-only {{! cc_flags.replace(' -MMD ', ' ').replace('"', '\\"') }}",
"gccDefaultCppFlags": "-fsyntax-only {{! cxx_flags.replace(' -MMD ', ' ').replace('"', '\\"') }}",
"execPath": "{{ cxx_path }}",
"gccDefaultCFlags": "-fsyntax-only {{! cc_flags.replace(' -MMD ', ' ').replace('"', '\\"') }} {{ !_defines.replace('"', '\\"') }}",
"gccDefaultCppFlags": "-fsyntax-only {{! cxx_flags.replace(' -MMD ', ' ').replace('"', '\\"') }} {{ !_defines.replace('"', '\\"') }}",
"gccErrorLimit": 15,
"gccIncludePaths": "{{ ','.join(includes).replace("\\", "/") }}",
"gccIncludePaths": "{{! ','.join("'{}'".format(inc) for inc in includes)}}",
"gccSuppressWarnings": false
}

View File

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

View File

@@ -15,7 +15,7 @@
</ItemGroup>
% for file in src_files:
<ItemGroup>
% if any([file.endswith(".%s" % e) for e in ("h", "hh", "hpp", "inc")]):
% if any(file.endswith(".%s" % e) for e in ("h", "hh", "hpp", "inc")):
<ClInclude Include="{{file}}">
<Filter>Header Files</Filter>
</ClInclude>

View File

@@ -60,7 +60,7 @@
</ItemGroup>
% for file in src_files:
<ItemGroup>
% if any([file.endswith(".%s" % e) for e in ("h", "hh", "hpp", "inc")]):
% if any(file.endswith(".%s" % e) for e in ("h", "hh", "hpp", "inc")):
<ClInclude Include="{{file}}">
<Filter>Header Files</Filter>
</ClInclude>

View File

@@ -1,3 +1,5 @@
.pioenvs
.piolibdeps
.vscode
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

View File

@@ -1,37 +1,71 @@
{
"configurations": [
{
"name": "!!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags"
},
{
% import platform
% from os.path import commonprefix, dirname, isdir
%
% systype = platform.system().lower()
%
% def _escape(text):
% return to_unix_path(text).replace('"', '\\"')
% end
%
% cleaned_includes = []
% for include in includes:
% if "toolchain-" not in dirname(commonprefix([include, cc_path])) and isdir(include):
% cleaned_includes.append(include)
% end
% end
%
% if systype == "windows":
"name": "Win32",
% elif systype == "darwin":
"name": "Mac",
"macFrameworkPath": [],
% else:
"name": "Linux",
% end
"includePath": [
% for include in includes:
"{{include.replace('\\\\', '/').replace('\\', '/').replace('"', '\\"')}}",
% for include in cleaned_includes:
"{{ include }}",
% end
""
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": "",
"path": [
% for include in includes:
"{{include.replace('\\\\', '/').replace('\\', '/').replace('"', '\\"')}}",
% for include in cleaned_includes:
"{{ include }}",
% end
""
]
},
"defines": [
% for define in defines:
"{{!define.replace('"', '\\"')}}",
"{{! _escape(define) }}",
% end
""
]
],
"intelliSenseMode": "clang-x64",
% import re
% STD_RE = re.compile(r"\-std=[a-z\+]+(\d+)")
% cc_stds = STD_RE.findall(cc_flags)
% cxx_stds = STD_RE.findall(cxx_flags)
%
% # pass only architecture specific flags
% cc_m_flags = " ".join([f.strip() for f in cc_flags.split(" ") if f.strip().startswith("-m")])
%
% if cc_stds:
"cStandard": "c{{ cc_stds[-1] }}",
% end
% if cxx_stds:
"cppStandard": "c++{{ cxx_stds[-1] }}",
% end
"compilerPath": "\"{{cc_path}}\" {{! _escape(cc_m_flags) }}"
}
]
],
"version": 4
}

View File

@@ -0,0 +1,7 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}

View File

@@ -1,15 +1,44 @@
// AUTOMATICALLY GENERATED FILE. PLEASE DO NOT MODIFY IT MANUALLY
// PIO Unified Debugger
//
// Documentation: https://docs.platformio.org/page/plus/debugging.html
// Configuration: https://docs.platformio.org/page/projectconf/section_env_debug.html
% from os.path import dirname, join
%
% def _escape_path(path):
% return path.replace('\\\\', '/').replace('\\', '/').replace('"', '\\"')
% end
%
{
"version": "0.2.0",
"configurations": [
{
"type": "gdb",
"type": "platformio-debug",
"request": "launch",
"cwd": "${workspaceRoot}",
"name": "PlatformIO Debugger",
"target": "{{prog_path.replace('\\\\', '/').replace('\\', '/').replace('"', '\\"')}}",
"gdbpath": "{{join(dirname(platformio_path), "piodebuggdb").replace('\\\\', '/').replace('\\', '/').replace('"', '\\"')}}",
"autorun": [ "source .pioinit" ]
"name": "PIO Debug",
"executable": "{{ _escape_path(prog_path) }}",
"toolchainBinDir": "{{ _escape_path(dirname(gdb_path)) }}",
% if svd_path:
"svdPath": "{{ _escape_path(svd_path) }}",
% end
"preLaunchTask": {
"type": "PlatformIO",
"task": "Pre-Debug"
},
"internalConsoleOptions": "openOnSessionStart"
},
{
"type": "platformio-debug",
"request": "launch",
"name": "PIO Debug (skip Pre-Debug)",
"executable": "{{ _escape_path(prog_path) }}",
"toolchainBinDir": "{{ _escape_path(dirname(gdb_path)) }}",
% if svd_path:
"svdPath": "{{ _escape_path(svd_path) }}",
% end
"internalConsoleOptions": "openOnSessionStart"
}
]
}

Some files were not shown because too many files have changed in this diff Show More