From 349b159a7b23b2c2d2ec54b719f501d831d2b043 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 23 May 2016 22:28:48 +0300 Subject: [PATCH 001/284] Move boards and platforms to separate repos // Issue #479 --- platformio/boards/adafruit.json | 252 ----- platformio/boards/arduino.json | 927 ------------------ platformio/boards/atmelsam.json | 50 - platformio/boards/digistump.json | 107 -- platformio/boards/engduino.json | 86 -- platformio/boards/espressif.json | 476 --------- platformio/boards/freescalekinetis.json | 114 --- platformio/boards/intel.json | 30 - platformio/boards/lattice.json | 45 - platformio/boards/microchippic32.json | 577 ----------- platformio/boards/microduino.json | 197 ---- platformio/boards/mightycore.json | 155 --- platformio/boards/misc.json | 742 -------------- platformio/boards/nordicnrf51.json | 182 ---- platformio/boards/nxplpc.json | 210 ---- platformio/boards/punchthrough.json | 22 - platformio/boards/raspberrypi.json | 52 - platformio/boards/siliconlabsefm32.json | 103 -- platformio/boards/sparkfun.json | 242 ----- platformio/boards/ststm32.json | 625 ------------ platformio/boards/teensy.json | 95 -- platformio/boards/timsp430.json | 164 ---- platformio/boards/titiva.json | 59 -- platformio/builder/scripts/__init__.py | 13 - platformio/builder/scripts/atmelavr.py | 168 ---- platformio/builder/scripts/atmelsam.py | 189 ---- platformio/builder/scripts/basearm.py | 97 -- platformio/builder/scripts/baseavr.py | 98 -- platformio/builder/scripts/espressif.py | 357 ------- .../builder/scripts/frameworks/__init__.py | 13 - .../builder/scripts/frameworks/arduino.py | 339 ------- .../builder/scripts/frameworks/cmsis.py | 93 -- .../builder/scripts/frameworks/energia.py | 74 -- .../builder/scripts/frameworks/libopencm3.py | 191 ---- platformio/builder/scripts/frameworks/mbed.py | 289 ------ .../builder/scripts/frameworks/simba.py | 35 - platformio/builder/scripts/frameworks/spl.py | 119 --- .../builder/scripts/frameworks/wiringpi.py | 65 -- .../builder/scripts/freescalekinetis.py | 61 -- platformio/builder/scripts/intel_arc32.py | 200 ---- platformio/builder/scripts/lattice_ice40.py | 149 --- platformio/builder/scripts/linux_arm.py | 60 -- platformio/builder/scripts/linux_i686.py | 60 -- platformio/builder/scripts/linux_x86_64.py | 60 -- platformio/builder/scripts/microchippic32.py | 190 ---- platformio/builder/scripts/native.py | 44 - platformio/builder/scripts/nordicnrf51.py | 77 -- platformio/builder/scripts/nxplpc.py | 70 -- .../builder/scripts/siliconlabsefm32.py | 61 -- platformio/builder/scripts/ststm32.py | 113 --- platformio/builder/scripts/teensy.py | 115 --- platformio/builder/scripts/timsp430.py | 127 --- platformio/builder/scripts/titiva.py | 74 -- platformio/builder/scripts/windows_x86.py | 65 -- .../commands/{platforms.py => platform.py} | 0 .../{pkgmanager.py => managers/package.py} | 0 .../base.py => managers/platform.py} | 0 platformio/platforms/__init__.py | 13 - platformio/platforms/atmelavr.py | 74 -- platformio/platforms/atmelsam.py | 61 -- platformio/platforms/espressif.py | 68 -- platformio/platforms/freescalekinetis.py | 42 - platformio/platforms/intel_arc32.py | 45 - platformio/platforms/lattice_ice40.py | 43 - platformio/platforms/linux_arm.py | 59 -- platformio/platforms/linux_i686.py | 43 - platformio/platforms/linux_x86_64.py | 43 - platformio/platforms/microchippic32.py | 46 - platformio/platforms/native.py | 29 - platformio/platforms/nordicnrf51.py | 58 -- platformio/platforms/nxplpc.py | 44 - platformio/platforms/siliconlabsefm32.py | 47 - platformio/platforms/ststm32.py | 71 -- platformio/platforms/teensy.py | 69 -- platformio/platforms/timsp430.py | 50 - platformio/platforms/titiva.py | 54 - platformio/platforms/windows_x86.py | 35 - 77 files changed, 10172 deletions(-) delete mode 100644 platformio/boards/adafruit.json delete mode 100644 platformio/boards/arduino.json delete mode 100644 platformio/boards/atmelsam.json delete mode 100644 platformio/boards/digistump.json delete mode 100644 platformio/boards/engduino.json delete mode 100644 platformio/boards/espressif.json delete mode 100644 platformio/boards/freescalekinetis.json delete mode 100644 platformio/boards/intel.json delete mode 100755 platformio/boards/lattice.json delete mode 100644 platformio/boards/microchippic32.json delete mode 100644 platformio/boards/microduino.json delete mode 100644 platformio/boards/mightycore.json delete mode 100644 platformio/boards/misc.json delete mode 100644 platformio/boards/nordicnrf51.json delete mode 100644 platformio/boards/nxplpc.json delete mode 100644 platformio/boards/punchthrough.json delete mode 100644 platformio/boards/raspberrypi.json delete mode 100644 platformio/boards/siliconlabsefm32.json delete mode 100644 platformio/boards/sparkfun.json delete mode 100644 platformio/boards/ststm32.json delete mode 100644 platformio/boards/teensy.json delete mode 100644 platformio/boards/timsp430.json delete mode 100644 platformio/boards/titiva.json delete mode 100644 platformio/builder/scripts/__init__.py delete mode 100644 platformio/builder/scripts/atmelavr.py delete mode 100644 platformio/builder/scripts/atmelsam.py delete mode 100644 platformio/builder/scripts/basearm.py delete mode 100644 platformio/builder/scripts/baseavr.py delete mode 100644 platformio/builder/scripts/espressif.py delete mode 100644 platformio/builder/scripts/frameworks/__init__.py delete mode 100644 platformio/builder/scripts/frameworks/arduino.py delete mode 100644 platformio/builder/scripts/frameworks/cmsis.py delete mode 100644 platformio/builder/scripts/frameworks/energia.py delete mode 100644 platformio/builder/scripts/frameworks/libopencm3.py delete mode 100644 platformio/builder/scripts/frameworks/mbed.py delete mode 100755 platformio/builder/scripts/frameworks/simba.py delete mode 100644 platformio/builder/scripts/frameworks/spl.py delete mode 100644 platformio/builder/scripts/frameworks/wiringpi.py delete mode 100644 platformio/builder/scripts/freescalekinetis.py delete mode 100644 platformio/builder/scripts/intel_arc32.py delete mode 100755 platformio/builder/scripts/lattice_ice40.py delete mode 100644 platformio/builder/scripts/linux_arm.py delete mode 100644 platformio/builder/scripts/linux_i686.py delete mode 100644 platformio/builder/scripts/linux_x86_64.py delete mode 100644 platformio/builder/scripts/microchippic32.py delete mode 100644 platformio/builder/scripts/native.py delete mode 100644 platformio/builder/scripts/nordicnrf51.py delete mode 100644 platformio/builder/scripts/nxplpc.py delete mode 100644 platformio/builder/scripts/siliconlabsefm32.py delete mode 100644 platformio/builder/scripts/ststm32.py delete mode 100644 platformio/builder/scripts/teensy.py delete mode 100644 platformio/builder/scripts/timsp430.py delete mode 100644 platformio/builder/scripts/titiva.py delete mode 100644 platformio/builder/scripts/windows_x86.py rename platformio/commands/{platforms.py => platform.py} (100%) rename platformio/{pkgmanager.py => managers/package.py} (100%) rename platformio/{platforms/base.py => managers/platform.py} (100%) delete mode 100644 platformio/platforms/__init__.py delete mode 100644 platformio/platforms/atmelavr.py delete mode 100644 platformio/platforms/atmelsam.py delete mode 100644 platformio/platforms/espressif.py delete mode 100644 platformio/platforms/freescalekinetis.py delete mode 100644 platformio/platforms/intel_arc32.py delete mode 100755 platformio/platforms/lattice_ice40.py delete mode 100644 platformio/platforms/linux_arm.py delete mode 100644 platformio/platforms/linux_i686.py delete mode 100644 platformio/platforms/linux_x86_64.py delete mode 100644 platformio/platforms/microchippic32.py delete mode 100644 platformio/platforms/native.py delete mode 100644 platformio/platforms/nordicnrf51.py delete mode 100644 platformio/platforms/nxplpc.py delete mode 100644 platformio/platforms/siliconlabsefm32.py delete mode 100644 platformio/platforms/ststm32.py delete mode 100644 platformio/platforms/teensy.py delete mode 100644 platformio/platforms/timsp430.py delete mode 100644 platformio/platforms/titiva.py delete mode 100644 platformio/platforms/windows_x86.py diff --git a/platformio/boards/adafruit.json b/platformio/boards/adafruit.json deleted file mode 100644 index 9fb2dda4..00000000 --- a/platformio/boards/adafruit.json +++ /dev/null @@ -1,252 +0,0 @@ -{ - "flora8": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_FLORA8", - "f_cpu": "8000000L", - "mcu": "atmega32u4", - "usb_product": "Adafruit Flora", - "variant": "flora", - "hwid": [ - ["0x239A", "0x8004"] - ] - }, - "frameworks": ["arduino"], - "name": "Adafruit Flora", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://www.adafruit.com/product/659", - "vendor": "Adafruit" - }, - - "bluefruitmicro": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_BLUEFRUITMICRO", - "f_cpu": "8000000L", - "mcu": "atmega32u4", - "usb_product": "Bluefruit Micro", - "variant": "bluefruitmicro", - "hwid": [ - ["0x239A", "0x800A"] - ] - }, - "frameworks": ["arduino"], - "name": "Adafruit Bluefruit Micro", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "https://www.adafruit.com/products/2661", - "vendor": "Adafruit" - }, - - "gemma": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_GEMMA", - "f_cpu": "8000000L", - "mcu": "attiny85", - "variant": "tiny8" - }, - "frameworks": ["arduino"], - "name": "Adafruit Gemma", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 512, - "maximum_size": 8192, - "protocol": "usbtiny" - }, - "url": "http://www.adafruit.com/products/1222", - "vendor": "Adafruit" - }, - - "feather32u4": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_FEATHER32U4", - "f_cpu": "8000000L", - "mcu": "atmega32u4", - "usb_product": "Feather 32u4", - "variant": "feather32u4", - "hwid": [ - ["0x239A", "0x800C"] - ] - }, - "frameworks": ["arduino"], - "name": "Adafruit Feather", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "https://learn.adafruit.com/adafruit-feather-32u4-bluefruit-le/", - "vendor": "Adafruit" - }, - - "trinket3": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_TRINKET3", - "f_cpu": "8000000L", - "mcu": "attiny85", - "variant": "tiny8" - }, - "frameworks": ["arduino"], - "name": "Adafruit Trinket 3V/8MHz", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 512, - "maximum_size": 8192, - "protocol": "usbtiny" - }, - "url": "http://www.adafruit.com/products/1500", - "vendor": "Adafruit" - }, - - "trinket5": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_TRINKET5", - "f_cpu": "16000000L", - "mcu": "attiny85", - "variant": "tiny8" - }, - "frameworks": ["arduino"], - "name": "Adafruit Trinket 5V/16MHz", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 512, - "maximum_size": 8192, - "protocol": "usbtiny" - }, - "url": "http://www.adafruit.com/products/1501", - "vendor": "Adafruit" - }, - - "metro": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_METRO", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "Adafruit Metro", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 32256, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.adafruit.com/products/2466", - "vendor": "Adafruit" - }, - - "protrinket3": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_PROTRINKET3", - "f_cpu": "12000000L", - "mcu": "atmega328p", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "Adafruit Pro Trinket 3V/12MHz (USB)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 28672, - "protocol": "usbtiny" - }, - "url": "http://www.adafruit.com/products/2010", - "vendor": "Adafruit" - }, - - "protrinket5": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_PROTRINKET5", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "Adafruit Pro Trinket 5V/16MHz (USB)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 28672, - "protocol": "usbtiny" - }, - "url": "http://www.adafruit.com/products/2000", - "vendor": "Adafruit" - }, - "protrinket3ftdi": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_PROTRINKET3FTDI", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "Adafruit Pro Trinket 3V/12MHz (FTDI)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 28672, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.adafruit.com/products/2010", - "vendor": "Adafruit" - }, - "protrinket5ftdi": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_PROTRINKET5FTDI", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "Adafruit Pro Trinket 5V/16MHz (USB)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 28672, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.adafruit.com/products/2000", - "vendor": "Adafruit" - } -} diff --git a/platformio/boards/arduino.json b/platformio/boards/arduino.json deleted file mode 100644 index 602c066e..00000000 --- a/platformio/boards/arduino.json +++ /dev/null @@ -1,927 +0,0 @@ -{ - "LilyPadUSB": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_LILYPAD_USB", - "f_cpu": "8000000L", - "mcu": "atmega32u4", - "usb_product": "LilyPad USB", - "variant": "leonardo", - "hwid": [ - ["0x1B4F", "0x9207"], - ["0x1B4F", "0x9208"] - ] - }, - "frameworks": ["arduino"], - "name": "Arduino LilyPad USB", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://arduino.cc/en/Main/ArduinoBoardLilyPadUSB", - "vendor": "Arduino" - }, - "atmegangatmega168": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_NG", - "f_cpu": "16000000L", - "mcu": "atmega168", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "Arduino NG or older ATmega168", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 14336, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 19200 - }, - "url": "http://arduino.cc/en/main/boards", - "vendor": "Arduino" - }, - "atmegangatmega8": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_NG", - "f_cpu": "16000000L", - "mcu": "atmega8", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "Arduino NG or older ATmega8", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 7168, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 19200 - }, - "url": "http://arduino.cc/en/main/boards", - "vendor": "Arduino" - }, - "btatmega168": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_BT", - "f_cpu": "16000000L", - "mcu": "atmega168", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "Arduino BT ATmega168", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 1024, - "maximum_size": 14336, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 19200 - }, - "url": "http://arduino.cc/en/main/boards", - "vendor": "Arduino" - }, - "btatmega328": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_BT", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "Arduino BT ATmega328", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2048, - "maximum_size": 28672, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 19200 - }, - "url": "http://arduino.cc/en/main/boards", - "vendor": "Arduino" - }, - "diecimilaatmega168": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_DUEMILANOVE", - "f_cpu": "16000000L", - "mcu": "atmega168", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "Arduino Duemilanove or Diecimila ATmega168", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 14336, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 19200 - }, - "url": "http://arduino.cc/en/Main/ArduinoBoardDiecimila", - "vendor": "Arduino" - }, - "diecimilaatmega328": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_DUEMILANOVE", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "Arduino Duemilanove or Diecimila ATmega328", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 30720, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "http://arduino.cc/en/Main/ArduinoBoardDiecimila", - "vendor": "Arduino" - }, - "esplora": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ESPLORA", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "usb_product": "Arduino Esplora", - "variant": "leonardo", - "hwid": [ - ["0x2341", "0x003C"], - ["0x2341", "0x803C"], - ["0x2A03", "0x003C"], - ["0x2A03", "0x803C"] - ] - }, - "frameworks": ["arduino"], - "name": "Arduino Esplora", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-esplora", - "vendor": "Arduino" - }, - "ethernet": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ETHERNET", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "ethernet" - }, - "frameworks": ["arduino"], - "name": "Arduino Ethernet", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 32256, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-ethernet", - "vendor": "Arduino" - }, - "fio": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_FIO", - "f_cpu": "8000000L", - "mcu": "atmega328p", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "Arduino Fio", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 30720, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "http://arduino.cc/en/Main/ArduinoBoardFio", - "vendor": "Arduino" - }, - "leonardo": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_LEONARDO", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "usb_product": "Arduino Leonardo", - "variant": "leonardo", - "hwid": [ - ["0x2341", "0x0036"], - ["0x2341", "0x8036"], - ["0x2A03", "0x0036"], - ["0x2A03", "0x8036"] - ] - }, - "frameworks": ["arduino"], - "name": "Arduino Leonardo", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-leonardo", - "vendor": "Arduino" - }, - "leonardoeth": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_LEONARDO", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "usb_product": "Arduino Leonardo ETH", - "variant": "leonardo", - "hwid": [ - ["0x2A03", "0x8040"], - ["0x2A03", "0x0040"] - ] - }, - "frameworks": ["arduino"], - "name": "Arduino Leonardo ETH", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-leonardo-eth", - "vendor": "Arduino" - }, - "lilypadatmega168": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_LILYPAD", - "f_cpu": "8000000L", - "mcu": "atmega168", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "Arduino LilyPad ATmega168", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 14336, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 19200 - }, - "url": "http://arduino.cc/en/Main/ArduinoBoardLilyPad", - "vendor": "Arduino" - }, - "lilypadatmega328": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_LILYPAD", - "f_cpu": "8000000L", - "mcu": "atmega328p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "Arduino LilyPad ATmega328", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 30720, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "http://arduino.cc/en/Main/ArduinoBoardLilyPad", - "vendor": "Arduino" - }, - "megaADK": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ADK", - "f_cpu": "16000000L", - "mcu": "atmega2560", - "variant": "mega" - }, - "frameworks": ["arduino"], - "name": "Arduino Mega ADK", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 253952, - "protocol": "wiring", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-mega-adk", - "vendor": "Arduino" - }, - "megaatmega1280": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_MEGA", - "f_cpu": "16000000L", - "mcu": "atmega1280", - "variant": "mega" - }, - "frameworks": ["arduino"], - "name": "Arduino Mega or Mega 2560 ATmega1280", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 126976, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-mega-2560", - "vendor": "Arduino" - }, - "megaatmega2560": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_MEGA2560", - "f_cpu": "16000000L", - "mcu": "atmega2560", - "variant": "mega" - }, - "frameworks": ["arduino", "simba"], - "name": "Arduino Mega or Mega 2560 ATmega2560 (Mega 2560)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 253952, - "protocol": "wiring", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-mega-2560", - "vendor": "Arduino" - }, - "micro": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_MICRO", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "usb_product": "Arduino Micro", - "variant": "micro", - "hwid": [ - ["0x2341", "0x0037"], - ["0x2341", "0x8037"], - ["0x2A03", "0x0037"], - ["0x2A03", "0x8037"] - ] - }, - "frameworks": ["arduino"], - "name": "Arduino Micro", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-micro", - "vendor": "Arduino" - }, - "miniatmega168": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_MINI", - "f_cpu": "16000000L", - "mcu": "atmega168", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "Arduino Mini ATmega168", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 14336, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 19200 - }, - "url": "http://arduino.cc/en/Main/ArduinoBoardMini", - "vendor": "Arduino" - }, - "miniatmega328": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_MINI", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "Arduino Mini ATmega328", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 28672, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://arduino.cc/en/Main/ArduinoBoardMini", - "vendor": "Arduino" - }, - "nanoatmega168": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_NANO", - "f_cpu": "16000000L", - "mcu": "atmega168", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "Arduino Nano ATmega168", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 14336, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 19200 - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-nano", - "vendor": "Arduino" - }, - "nanoatmega328": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_NANO", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino", "simba"], - "name": "Arduino Nano ATmega328", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 30720, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-nano", - "vendor": "Arduino" - }, - "pro16MHzatmega168": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_PRO", - "f_cpu": "16000000L", - "mcu": "atmega168", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "Arduino Pro or Pro Mini ATmega168 (5V, 16 MHz)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 14336, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 19200 - }, - "url": "http://arduino.cc/en/Main/ArduinoBoardProMini", - "vendor": "Arduino" - }, - "pro16MHzatmega328": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_PRO", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "Arduino Pro or Pro Mini ATmega328 (5V, 16 MHz)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 30720, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "http://arduino.cc/en/Main/ArduinoBoardProMini", - "vendor": "Arduino" - }, - "pro8MHzatmega168": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_PRO", - "f_cpu": "8000000L", - "mcu": "atmega168", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "Arduino Pro or Pro Mini ATmega168 (3.3V, 8 MHz)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 14336, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 19200 - }, - "url": "http://arduino.cc/en/Main/ArduinoBoardProMini", - "vendor": "Arduino" - }, - "pro8MHzatmega328": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_PRO", - "f_cpu": "8000000L", - "mcu": "atmega328p", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "Arduino Pro or Pro Mini ATmega328 (3.3V, 8 MHz)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 30720, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "http://arduino.cc/en/Main/ArduinoBoardProMini", - "vendor": "Arduino" - }, - "robotControl": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ROBOT_CONTROL", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "usb_product": "Robot Control", - "variant": "robot_control", - "hwid": [ - ["0x2341", "0x0038"], - ["0x2341", "0x8038"], - ["0x2A03", "0x0038"], - ["0x2A03", "0x8038"] - ] - }, - "frameworks": ["arduino"], - "name": "Arduino Robot Control", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-robot", - "vendor": "Arduino" - }, - "robotMotor": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ROBOT_MOTOR", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "usb_product": "Robot Motor", - "variant": "robot_motor", - "hwid": [ - ["0x2341", "0x0039"], - ["0x2341", "0x8039"], - ["0x2A03", "0x0039"], - ["0x2A03", "0x8039"] - ] - }, - "frameworks": ["arduino"], - "name": "Arduino Robot Motor", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-robot", - "vendor": "Arduino" - }, - "uno": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_UNO", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "standard", - "hwid": [ - ["0x2341", "0x0043"], - ["0x2341", "0x0001"], - ["0x2A03", "0x0043"] - ] - }, - "frameworks": ["arduino", "simba"], - "name": "Arduino Uno", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 32256, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-uno", - "vendor": "Arduino" - }, - "yun": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_YUN", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "usb_product": "Arduino Yun", - "variant": "yun", - "hwid": [ - ["0x2341", "0x0041"], - ["0x2341", "0x8041"], - ["0x2A03", "0x0041"], - ["0x2A03", "0x8041"] - ] - }, - "frameworks": ["arduino"], - "name": "Arduino Yun", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "via_ssh": true, - "wait_for_upload_port": true - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-yun", - "vendor": "Arduino" - }, - "yunmini": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_YUN", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "usb_product": "Arduino Yun Mini", - "variant": "yun", - "hwid": [ - ["0x2A03", "0x8050"], - ["0x2A03", "0x0050"] - ] - }, - "frameworks": ["arduino"], - "name": "Arduino Yun Mini", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "via_ssh": true, - "wait_for_upload_port": true - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-yun-mini", - "vendor": "Arduino" - }, - "chiwawa": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_YUN", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "usb_product": "Arduino Industrial 101", - "variant": "yun", - "hwid": [ - ["0x2A03", "0x8056"], - ["0x2A03", "0x0056"] - ] - }, - "frameworks": ["arduino"], - "name": "Arduino Industrial 101", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "via_ssh": true, - "wait_for_upload_port": true - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-industrial-101", - "vendor": "Arduino" - }, - "one": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_YUN", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "usb_product": "Linino One", - "variant": "yun", - "hwid": [ - ["0x2A03", "0x8001"], - ["0x2A03", "0x0001"] - ] - }, - "frameworks": ["arduino"], - "name": "Linino One", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "via_ssh": true, - "wait_for_upload_port": true - }, - "url": "http://www.linino.org/portfolio/linino-one/", - "vendor": "Linino" - }, - "due": { - "build": { - "core": "arduino", - "extra_flags": "-D__SAM3X8E__ -DARDUINO_SAM_DUE -DARDUINO_ARCH_SAM", - "f_cpu": "84000000L", - "mcu": "sam3x8e", - "cpu": "cortex-m3", - "usb_product": "Arduino Due", - "variant": "arduino_due_x", - "ldscript": "sam3x8e.ld", - "hwid": [ - ["0x2341", "0x003D"], - ["0x2A03", "0x003D"] - ] - }, - "frameworks": ["arduino", "simba"], - "name": "Arduino Due (Programming Port)", - "platform": "atmelsam", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 32768, - "maximum_size": 524288, - "protocol": "sam-ba", - "require_upload_port" : true, - "use_1200bps_touch": true, - "wait_for_upload_port": false - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-due", - "vendor": "Arduino" - }, - "dueUSB": { - "build": { - "core": "arduino", - "extra_flags": "-D__SAM3X8E__ -DARDUINO_SAM_DUE -DARDUINO_ARCH_SAM", - "f_cpu": "84000000L", - "mcu": "sam3x8e", - "cpu": "cortex-m3", - "usb_product": "Arduino Due", - "variant": "arduino_due_x", - "ldscript": "sam3x8e.ld", - "hwid": [ - ["0x2341", "0x003E"], - ["0x2A03", "0x003E"] - ] - }, - "frameworks": ["arduino"], - "name": "Arduino Due (USB Native Port)", - "platform": "atmelsam", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 32768, - "maximum_size": 524288, - "protocol": "sam-ba", - "require_upload_port" : true, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://www.arduino.org/products/boards/4-arduino-boards/arduino-due", - "vendor": "Arduino" - }, - "zero": { - "build": { - "core": "arduino_zero", - "extra_flags": "-DARDUINO_SAMD_ZERO -DARDUINO_ARCH_SAMD -D__SAMD21G18A__", - "f_cpu": "48000000L", - "mcu": "samd21g18a", - "cpu": "cortex-m0plus", - "usb_product": "Arduino Zero", - "variant": "arduino_zero", - "ldscript": "flash_with_bootloader.ld", - "hwid": [ - ["0x2341", "0x804D"], - ["0x03EB", "0x2157"] - ] - }, - "frameworks": ["arduino"], - "name": "Arduino Zero (Programming Port)", - "platform": "atmelsam", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 32768, - "maximum_size": 262144, - "protocol": "sam-ba", - "require_upload_port" : false, - "use_1200bps_touch": false, - "wait_for_upload_port": false - }, - "url": "https://www.arduino.cc/en/Main/ArduinoBoardZero", - "vendor": "Arduino" - }, - "zeroUSB": { - "build": { - "core": "arduino_zero", - "extra_flags": "-DARDUINO_SAMD_ZERO -DARDUINO_ARCH_SAMD -D__SAMD21G18A__", - "f_cpu": "48000000L", - "mcu": "samd21g18a", - "cpu": "cortex-m0plus", - "usb_product": "Arduino Zero", - "variant": "arduino_zero", - "ldscript": "flash_with_bootloader.ld", - "hwid": [ - ["0x2341", "0x804D"], - ["0x2341", "0x004D"], - ["0x2341", "0x824D"] - ] - }, - "frameworks": ["arduino"], - "name": "Arduino Zero (USB Native Port)", - "platform": "atmelsam", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 32768, - "maximum_size": 262144, - "protocol": "sam-ba", - "require_upload_port" : true, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "https://www.arduino.cc/en/Main/ArduinoBoardZero", - "vendor": "Arduino" - } -} diff --git a/platformio/boards/atmelsam.json b/platformio/boards/atmelsam.json deleted file mode 100644 index bb2561ee..00000000 --- a/platformio/boards/atmelsam.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "samr21_xpro": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0plus", - "mcu": "atsamr21g18a" - }, - "frameworks": ["mbed"], - "name": "Atmel ATSAMR21-XPRO", - "platform": "atmelsam", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/SAMR21-XPRO/", - "vendor": "Atmel" - }, - "saml21_xpro_b": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0plus", - "mcu": "atsaml21j18b" - }, - "frameworks": ["mbed"], - "name": "Atmel SAML21-XPRO-B", - "platform": "atmelsam", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/SAML21-XPRO/", - "vendor": "Atmel" - }, - "samd21_xpro": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0plus", - "mcu": "atsamd21j18a" - }, - "frameworks": ["mbed"], - "name": "Atmel SAMD21-XPRO", - "platform": "atmelsam", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/SAMD21-XPRO/", - "vendor": "Atmel" - } -} diff --git a/platformio/boards/digistump.json b/platformio/boards/digistump.json deleted file mode 100644 index 24634358..00000000 --- a/platformio/boards/digistump.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "digispark-tiny": { - "build": { - "core": "digispark_tiny", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_DIGISPARK", - "f_cpu": "16000000L", - "mcu": "attiny85", - "variant": "digispark_tiny" - }, - "frameworks": ["arduino"], - "name": "Digistump Digispark (Default - 16 MHz)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 512, - "maximum_size": 6012, - "protocol": "digispark" - }, - "url": "http://digistump.com/products/1", - "vendor": "Digistump" - }, - "digispark-pro": { - "build": { - "core": "digispark_pro", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_DIGISPARKPRO", - "f_cpu": "16000000L", - "mcu": "attiny167", - "variant": "digispark_pro" - }, - "frameworks": ["arduino"], - "name": "Digistump Digispark Pro (Default 16 MHz)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 512, - "maximum_size": 14844, - "protocol": "digispark" - }, - "url": "http://digistump.com/products/109", - "vendor": "Digistump" - }, - "digispark-pro32": { - "build": { - "core": "digispark_pro", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_DIGISPARKPRO", - "f_cpu": "16000000L", - "mcu": "attiny167", - "variant": "digispark_pro32" - }, - "frameworks": ["arduino"], - "name": "Digistump Digispark Pro (16 MHz) (32 byte buffer)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 512, - "maximum_size": 14844, - "protocol": "digispark" - }, - "url": "http://digistump.com/products/109", - "vendor": "Digistump" - }, - "digispark-pro64": { - "build": { - "core": "digispark_pro", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_DIGISPARKPRO", - "f_cpu": "16000000L", - "mcu": "attiny167", - "variant": "digispark_pro64" - }, - "frameworks": ["arduino"], - "name": "Digistump Digispark Pro (16 MHz) (64 byte buffer)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 512, - "maximum_size": 14844, - "protocol": "digispark" - }, - "url": "http://digistump.com/products/109", - "vendor": "Digistump" - }, - "digix": { - "build": { - "core": "digispark_digix", - "extra_flags": "-w -D__SAM3X8E__ -DARDUINO_SAM_DIGIX -DARDUINO_ARCH_SAM", - "f_cpu": "84000000L", - "mcu": "at91sam3x8e", - "cpu": "cortex-m3", - "ldscript": "sam3x8e.ld", - "usb_product": "Digistump DigiX", - "variant": "digispark_digix", - "hwid": [ - ["0x16D0", "0x078A"] - ] - }, - "frameworks": ["arduino"], - "name": "Digistump DigiX", - "platform": "atmelsam", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 28672, - "maximum_size": 524288, - "protocol": "sam-ba", - "require_upload_port" : true, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://digistump.com/products/50", - "vendor": "Digistump" - } -} \ No newline at end of file diff --git a/platformio/boards/engduino.json b/platformio/boards/engduino.json deleted file mode 100644 index 5e7c1c48..00000000 --- a/platformio/boards/engduino.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "engduinov1": { - "build": { - "board": "AVR_ENGDUINOV1", - "core": "arduino", - "f_cpu": "8000000L", - "mcu": "atmega32u4", - "usb_product": "EngduinoV1", - "variant": "engduinov1", - "hwid": [ - ["0x1B4F", "0x9208"] - ] - }, - "frameworks": ["arduino"], - "name": "Engduino 1", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://www.engduino.org", - "vendor": "Engduino" - }, - "engduinov2": { - "build": { - "board": "AVR_ENGDUINOV2", - "core": "arduino", - "f_cpu": "8000000L", - "mcu": "atmega32u4", - "usb_product": "EngduinoV2", - "variant": "engduinov2", - "hwid": [ - ["0x1B4F", "0x9208"] - ] - }, - "frameworks": ["arduino"], - "name": "Engduino 2", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://www.engduino.org", - "vendor": "Engduino" - }, - "engduinov3": { - "build": { - "board": "AVR_ENGDUINOV3", - "core": "arduino", - "f_cpu": "8000000L", - "mcu": "atmega32u4", - "usb_product": "EngduinoV3", - "variant": "engduinov3", - "hwid": [ - ["0x1B4F", "0x9208"] - ] - }, - "frameworks": ["arduino"], - "name": "Engduino 3", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://www.engduino.org", - "vendor": "Engduino" - } -} \ No newline at end of file diff --git a/platformio/boards/espressif.json b/platformio/boards/espressif.json deleted file mode 100644 index 691b4dc6..00000000 --- a/platformio/boards/espressif.json +++ /dev/null @@ -1,476 +0,0 @@ -{ - "esp01": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "qio", - "ldscript": "esp8266.flash.512k64.ld", - "mcu": "esp8266", - "variant": "generic" - }, - "frameworks": ["arduino", "simba"], - "name": "Espressif Generic ESP8266 ESP-01 512k", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 524288, - "resetmethod": "ck", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.esp8266.com/wiki/doku.php?id=esp8266-module-family", - "vendor": "Espressif" - }, - - "esp01_1m": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "qio", - "ldscript": "esp8266.flash.1m256.ld", - "mcu": "esp8266", - "variant": "generic" - }, - "frameworks": ["arduino", "simba"], - "name": "Espressif Generic ESP8266 ESP-01 1M", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 1048576, - "resetmethod": "ck", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.esp8266.com/wiki/doku.php?id=esp8266-module-family", - "vendor": "Espressif" - }, - - "esp07": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP07", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "qio", - "ldscript": "esp8266.flash.4m1m.ld", - "mcu": "esp8266", - "variant": "nodemcu" - }, - "frameworks": ["arduino"], - "name": "Espressif Generic ESP8266 ESP-07", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 4194304, - "resetmethod": "nodemcu", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.esp8266.com/wiki/doku.php?id=esp8266-module-family#esp-07", - "vendor": "Espressif" - }, - - "esp12e": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP12", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "dio", - "ldscript": "esp8266.flash.4m1m.ld", - "mcu": "esp8266", - "variant": "nodemcu" - }, - "frameworks": ["arduino", "simba"], - "name": "Espressif ESP8266 ESP-12E", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 4194304, - "resetmethod": "nodemcu", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.esp8266.com/wiki/doku.php?id=esp8266-module-family", - "vendor": "Espressif" - }, - - "espduino": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP13", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "dio", - "ldscript": "esp8266.flash.4m1m.ld", - "mcu": "esp8266", - "variant": "ESPDuino" - }, - "frameworks": ["arduino"], - "name": "ESPDuino (ESP-13 Module)", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 4194304, - "resetmethod": "ck", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.tindie.com/products/doit/espduinowifi-uno-r3/", - "vendor": "Doit" - }, - - "nodemcu": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_NODEMCU", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "qio", - "ldscript": "esp8266.flash.4m1m.ld", - "mcu": "esp8266", - "variant": "nodemcu" - }, - "frameworks": ["arduino", "simba"], - "name": "NodeMCU 0.9 (ESP-12 Module)", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 4194304, - "resetmethod": "nodemcu", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.nodemcu.com/", - "vendor": "NodeMCU" - }, - - "nodemcuv2": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_NODEMCU", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "dio", - "ldscript": "esp8266.flash.4m1m.ld", - "mcu": "esp8266", - "variant": "nodemcu" - }, - "frameworks": ["arduino", "simba"], - "name": "NodeMCU 1.0 (ESP-12E Module)", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 4194304, - "resetmethod": "nodemcu", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.nodemcu.com/", - "vendor": "NodeMCU" - }, - - "huzzah": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP12", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "qio", - "ldscript": "esp8266.flash.4m1m.ld", - "mcu": "esp8266", - "variant": "adafruit" - }, - "frameworks": ["arduino", "simba"], - "name": "Adafruit HUZZAH ESP8266", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 4194304, - "resetmethod": "nodemcu", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.adafruit.com/products/2471", - "vendor": "Adafruit" - }, - - "espresso_lite_v1": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESPRESSO_LITE_V1", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "dio", - "ldscript": "esp8266.flash.4m1m.ld", - "mcu": "esp8266", - "variant": "espresso_lite_v1" - }, - "frameworks": ["arduino"], - "name": "ESPresso Lite 1.0", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 4194304, - "resetmethod": "nodemcu", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.espert.co", - "vendor": "ESPert" - }, - - "espresso_lite_v2": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESPRESSO_LITE_V2", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "dio", - "ldscript": "esp8266.flash.4m1m.ld", - "mcu": "esp8266", - "variant": "espresso_lite_v2" - }, - "frameworks": ["arduino"], - "name": "ESPresso Lite 2.0", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 4194304, - "resetmethod": "ck", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.espert.co", - "vendor": "ESPert" - }, - - "modwifi": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_MOD_WIFI_ESP8266", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "qio", - "ldscript": "esp8266.flash.2m.ld", - "mcu": "esp8266", - "variant": "generic" - }, - "frameworks": ["arduino"], - "name": "Olimex MOD-WIFI-ESP8266(-DEV)", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 2097152, - "resetmethod": "ck", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.olimex.com/Products/IoT/MOD-WIFI-ESP8266-DEV/open-source-hardware", - "vendor": "Olimex" - }, - - "thing": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_THING", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "qio", - "ldscript": "esp8266.flash.512k64.ld", - "mcu": "esp8266", - "variant": "thing" - }, - "frameworks": ["arduino"], - "name": "SparkFun ESP8266 Thing", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 524288, - "resetmethod": "ck", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.sparkfun.com/products/13231", - "vendor": "SparkFun" - }, - - "thingdev": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_THING", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "dio", - "ldscript": "esp8266.flash.512k64.ld", - "mcu": "esp8266", - "variant": "thing" - }, - "frameworks": ["arduino"], - "name": "SparkFun ESP8266 Thing Dev", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 524288, - "resetmethod": "nodemcu", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.sparkfun.com/products/13231", - "vendor": "SparkFun" - }, - - "esp210": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP210", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "qio", - "ldscript": "esp8266.flash.4m1m.ld", - "mcu": "esp8266", - "variant": "generic" - }, - "frameworks": ["arduino"], - "name": "SweetPea ESP-210", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 4194304, - "resetmethod": "ck", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://wiki.sweetpeas.se/index.php?title=ESP-210", - "vendor": "SweetPea" - }, - - "d1": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_NODEMCU", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "dio", - "ldscript": "esp8266.flash.4m1m.ld", - "mcu": "esp8266", - "variant": "d1" - }, - "frameworks": ["arduino"], - "name": "WeMos D1(Retired)", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 4194304, - "resetmethod": "nodemcu", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.wemos.cc/wiki/doku.php?id=en:d1", - "vendor": "WeMos" - }, - - "d1_mini": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_NODEMCU", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "dio", - "ldscript": "esp8266.flash.4m1m.ld", - "mcu": "esp8266", - "variant": "d1_mini" - }, - "frameworks": ["arduino"], - "name": "WeMos D1 R2 & mini", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 4194304, - "resetmethod": "nodemcu", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.wemos.cc/wiki/doku.php?id=en:d1_mini", - "vendor": "WeMos" - }, - - "espino": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP12", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "qio", - "ldscript": "esp8266.flash.4m1m.ld", - "mcu": "esp8266", - "variant": "espino" - }, - "frameworks": ["arduino"], - "name": "ESPino", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 4194304, - "resetmethod": "ck", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.espino.io", - "vendor": "ESPino" - }, - - "espinotee": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP13", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "qio", - "ldscript": "esp8266.flash.4m1m.ld", - "mcu": "esp8266", - "variant": "espinotee" - }, - "frameworks": ["arduino"], - "name": "ThaiEasyElec ESPino", - "platform": "espressif", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 4194304, - "resetmethod": "nodemcu", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.thaieasyelec.com/products/wireless-modules/wifi-modules/espino-wifi-development-board-detail.html", - "vendor": "ThaiEasyElec" - }, - - "esp_wroom_02": { - "build": { - "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP_WROOM_02", - "f_cpu": "80000000L", - "f_flash": "40000000L", - "flash_mode": "qio", - "ldscript": "esp8266.flash.4m1m.ld", - "mcu": "esp8266", - "variant": "nodemcu" - }, - "frameworks": ["arduino"], - "name": "ESP-WROOM-02", - "platform": "espressif", - "upload": { - "maximum_ram_size": 51200, - "maximum_size": 4194304, - "resetmethod": "nodemcu", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://www.esp8266.com/wiki/doku.php?id=esp8266-module-family", - "vendor": "Espressif" - } -} diff --git a/platformio/boards/freescalekinetis.json b/platformio/boards/freescalekinetis.json deleted file mode 100644 index 869a977a..00000000 --- a/platformio/boards/freescalekinetis.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "frdm_kl25z": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0plus", - "mcu": "mkl25z128vlk4" - }, - "frameworks": ["mbed"], - "name": "Freescale Kinetis FRDM-KL25Z", - "platform": "freescalekinetis", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 131072 - }, - "url": "https://developer.mbed.org/platforms/KL25Z/", - "vendor": "Freescale" - }, - "frdm_kl46z": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0plus", - "mcu": "mkl46z256vll4" - }, - "frameworks": ["mbed"], - "name": "Freescale Kinetis FRDM-KL46Z", - "platform": "freescalekinetis", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/FRDM-KL46Z/", - "vendor": "Freescale" - }, - "frdm_k64f": { - "build": { - "f_cpu": "120000000L", - "cpu": "cortex-m4", - "mcu": "mk64fn1m0vll12" - }, - "frameworks": ["mbed"], - "name": "Freescale Kinetis FRDM-K64F", - "platform": "freescalekinetis", - "upload": { - "maximum_ram_size": 262144, - "maximum_size": 1048576 - }, - "url": "https://developer.mbed.org/platforms/FRDM-K64F/", - "vendor": "Freescale" - }, - "frdm_kl05z": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0plus", - "mcu": "mkl05z32vfm4" - }, - "frameworks": ["mbed"], - "name": "Freescale Kinetis FRDM-KL05Z", - "platform": "freescalekinetis", - "upload": { - "maximum_ram_size": 4096, - "maximum_size": 32768 - }, - "url": "https://developer.mbed.org/platforms/FRDM-KL05Z/", - "vendor": "Freescale" - }, - "frdm_k20d50m": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m4", - "mcu": "mk20dx128vlh5" - }, - "frameworks": ["mbed"], - "name": "Freescale Kinetis FRDM-K20D50M", - "platform": "freescalekinetis", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 131072 - }, - "url": "https://developer.mbed.org/platforms/FRDM-K20D50M/", - "vendor": "Freescale" - }, - "frdm_k22f": { - "build": { - "f_cpu": "120000000L", - "cpu": "cortex-m4", - "mcu": "mk22fn512vlh12" - }, - "frameworks": ["mbed"], - "name": "Freescale Kinetis FRDM-K22F", - "platform": "freescalekinetis", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 524288 - }, - "url": "https://developer.mbed.org/platforms/FRDM-K22F/", - "vendor": "Freescale" - }, - "IBMEthernetKit": { - "build": { - "f_cpu": "120000000L", - "cpu": "cortex-m4", - "mcu": "mk64fn1m0vll12" - }, - "frameworks": ["mbed"], - "name": "Ethernet IoT Starter Kit", - "platform": "freescalekinetis", - "upload": { - "maximum_ram_size": 262144, - "maximum_size": 1048576 - }, - "url": "http://developer.mbed.org/platforms/IBMEthernetKit/", - "vendor": "Freescale" - } -} \ No newline at end of file diff --git a/platformio/boards/intel.json b/platformio/boards/intel.json deleted file mode 100644 index e74bdd39..00000000 --- a/platformio/boards/intel.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "genuino101": { - "build": { - "core": "arc32", - "extra_flags": "-DARDUINO_ARCH_ARC32 -D__ARDUINO_ARC__", - "f_cpu": "32000000L", - "ldscript": "flash.ld", - "mcu": "ARCv2EM", - "usb_product": "Genuino 101", - "variant": "arduino_101", - "hwid": [ - ["0x8087", "0x0AB6"] - ] - }, - "frameworks": ["arduino"], - "name": "Arduino/Genuino 101", - "platform": "intel_arc32", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 196608, - "use_1200bps_touch": true, - "protocol": "script", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": false - }, - "url": "https://www.arduino.cc/en/Main/ArduinoBoard101", - "vendor": "Intel" - } -} diff --git a/platformio/boards/lattice.json b/platformio/boards/lattice.json deleted file mode 100755 index ce31a2e4..00000000 --- a/platformio/boards/lattice.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "icestick": { - "build": { - "core": "icestick", - "f_cpu": "12000000L", - "cpu": "fpga", - "mcu": "ice40hx1k", - "variant": "1k", - "hwid": [ - ["0x0403", "0x6010"] - ] - }, - "frameworks": ["icestorm"], - "name": "Lattice iCEstick FPGA Evaluation Kit", - "platform": "lattice_ice40", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 32768 - }, - "url": "http://www.latticesemi.com/icestick", - "vendor": "Lattice" - }, - - "icezum": { - "build": { - "core": "icezum", - "f_cpu": "12000000L", - "cpu": "fpga", - "mcu": "ice40hx1k", - "variant": "1k", - "hwid": [ - ["0x0403", "0x6010"] - ] - }, - "frameworks": ["icestorm"], - "name": "BQ IceZUM Alhambra FPGA", - "platform": "lattice_ice40", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 32768 - }, - "url": "https://github.com/bqlabs/icezum/wiki", - "vendor": "BQ" - } -} diff --git a/platformio/boards/microchippic32.json b/platformio/boards/microchippic32.json deleted file mode 100644 index b5a949be..00000000 --- a/platformio/boards/microchippic32.json +++ /dev/null @@ -1,577 +0,0 @@ -{ - "cerebot32mx4": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_CEREBOT_32MX4_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX460F512.ld", - "mcu": "32MX460F512L", - "variant": "Cerebot_32MX4" - }, - "frameworks": ["arduino"], - "name": "Digilent Cerebot 32MX4", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 520192, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://store.digilentinc.com/cerebot-32mx4-limited-time-see-chipkit-pro-mx4/", - "vendor": "Digilent" - }, - - "cerebot32mx7": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_CEREBOT_32MX7_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX795F512.ld", - "mcu": "32MX795F512L", - "variant": "Cerebot_32MX7" - }, - "frameworks": ["arduino"], - "name": "Digilent Cerebot 32MX7", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 520192, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://www.microchip.com/Developmenttools/ProductDetails.aspx?PartNO=TDGL004", - "vendor": "Digilent" - }, - - "chipkit_mx3": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_CEREBOT_MX3CK_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX320F128.ld", - "mcu": "32MX320F128H", - "variant": "Cerebot_MX3cK" - }, - "frameworks": ["arduino"], - "name": "Digilent chipKIT MX3", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 126976, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://store.digilentinc.com/chipkit-mx3-microcontroller-board-with-pmod-headers/", - "vendor": "Digilent" - }, - - "chipkit_pro_mx4": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_CEREBOT_MX4CK_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX460F512.ld", - "mcu": "32MX460F512L", - "variant": "Cerebot_MX4cK" - }, - "frameworks": ["arduino"], - "name": "Digilent chipKIT Pro MX4", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 520192, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://store.digilentinc.com/chipkit-pro-mx4-embedded-systems-trainer-board/", - "vendor": "Digilent" - }, - - "chipkit_pro_mx7": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_CEREBOT_MX7CK_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX795F512.ld", - "mcu": "32MX795F512L", - "variant": "Cerebot_MX7cK" - }, - "frameworks": ["arduino"], - "name": "Digilent chipKIT Pro MX7", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 520192, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://store.digilentinc.com/chipkit-pro-mx7-advanced-peripherals-embedded-systems-trainer-board/", - "vendor": "Digilent" - }, - - "chipkit_pi": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_CHIPKIT_PI_", - "f_cpu": "40000000L", - "ldscript": "cchipKIT-application-32MX250F128.ld", - "mcu": "32MX250F128B", - "variant": "ChipKIT_Pi" - }, - "frameworks": ["arduino"], - "name": "Element14 chipKIT Pi", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 122880, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://www.element14.com/community/community/knode/dev_platforms_kits/element14_dev_kits/microchip-chipkit/chipkit_pi", - "vendor": "element14" - }, - - "chipkit_cmod": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_CMOD_", - "f_cpu": "40000000L", - "ldscript": "chipKIT-application-32MX150F128.ld", - "mcu": "32MX150F128D", - "variant": "Cmod" - }, - "frameworks": ["arduino"], - "name": "Digilent chipKIT Cmod", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 126976, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://store.digilentinc.com/chipkit-cmod-breadboardable-mz-microcontroller-board/", - "vendor": "Digilent" - }, - - "cui32stem": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_CUI32_ -D_USE_USB_FOR_SERIAL_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX795F512.ld", - "mcu": "32MX795F512H", - "variant": "CUI32stem" - }, - "frameworks": ["arduino"], - "name": "SeeedStudio CUI32stem", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 520192, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://www.seeedstudio.com/wiki/CUI32Stem", - "vendor": "SeeedStudio" - }, - - "ubw32_mx460": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_UBW32_MX460_ -D_USE_USB_FOR_SERIAL_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX460F512.ld", - "mcu": "32MX460F512L", - "variant": "Default_100" - }, - "frameworks": ["arduino"], - "name": "UBW32 MX460", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 520192, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://www.schmalzhaus.com/UBW32/", - "vendor": "UBW32" - }, - - "ubw32_mx795": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_UBW32_MX795_ -D_USE_USB_FOR_SERIAL_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX795F512.ld", - "mcu": "32MX795F512L", - "variant": "Default_100" - }, - "frameworks": ["arduino"], - "name": "UBW32 MX795", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 520192, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://www.schmalzhaus.com/UBW32/", - "vendor": "UBW32" - }, - - "usbono_pic32": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_PONTECH_UAV100_ -D_USE_USB_FOR_SERIAL_ -Danything=1", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX440F512.ld", - "mcu": "32MX440F512H", - "variant": "Default_64" - }, - "frameworks": ["arduino"], - "name": "PONTECH UAV100", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 520192, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://www.pontech.com/productdisplay/uav100", - "vendor": "PONTECH" - }, - - "chipkit_dp32": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_DP32_ -D_USE_USB_FOR_SERIAL_", - "f_cpu": "40000000L", - "ldscript": "chipKIT-application-32MX250F128.ld", - "mcu": "32MX250F128B", - "variant": "DP32" - }, - "frameworks": ["arduino"], - "name": "Digilent chipKIT DP32", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 122880, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://store.digilentinc.com/chipkit-dp32-dip-package-prototyping-microcontroller-board/", - "vendor": "Digilent" - }, - - "fubarino_mini": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_FUBARINO_MINI_ -D_USE_USB_FOR_SERIAL_", - "f_cpu": "48000000L", - "ldscript": "chipKIT-application-32MX250F128.ld", - "mcu": "32MX250F128D", - "variant": "Fubarino_Mini" - }, - "frameworks": ["arduino"], - "name": "Fubarino Mini", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 122880, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://fubarino.org/mini/", - "vendor": "Fubarino" - }, - - "fubarino_sd": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_FUBARINO_SD_ -D_USE_USB_FOR_SERIAL_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX795F512.ld", - "mcu": "32MX795F512H", - "variant": "Fubarino_SD" - }, - "frameworks": ["arduino"], - "name": "Fubarino SD (1.5)", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 520192, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://fubarino.org/sd/index.html", - "vendor": "Fubarino" - }, - - "mega_pic32": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_MEGA_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX795F512.ld", - "mcu": "32MX795F512L", - "variant": "Max32" - }, - "frameworks": ["arduino"], - "name": "Digilent chipKIT MAX32", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 520192, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://store.digilentinc.com/chipkit-max32-microcontroller-board-with-mega-r3-headers/", - "vendor": "Digilent" - }, - - "pinguino32": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_OLIMEX_PIC32_PINGUINO_ -D_USE_USB_FOR_SERIAL_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX440F256.ld", - "mcu": "32MX440F256H", - "variant": "Olimex_PIC32_Pinguino" - }, - "frameworks": ["arduino"], - "name": "Olimex PIC32-PINGUINO", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 258048, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "https://www.olimex.com/Products/Duino/PIC32/PIC32-PINGUINO/open-source-hardware", - "vendor": "Olimex" - }, - - "picadillo_35t": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_PICADILLO_35T_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX795F512.ld", - "mcu": "32MX795F512L", - "variant": "picadillo_35t" - }, - "frameworks": ["arduino"], - "name": "4DSystems PICadillo 35T", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 520192, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://www.4dsystems.com.au/product/Picadillo_35T/", - "vendor": "4DSystems" - }, - - "quick240_usb": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_PONTECH_QUICK240_USB_ -D_USE_USB_FOR_SERIAL_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX795F512.ld", - "mcu": "32MX795F512L", - "variant": "quicK240" - }, - "frameworks": ["arduino"], - "name": "PONTECH quicK240", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 520192, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://quick240.com/quicki/", - "vendor": "PONTECH" - }, - - "chipkit_uc32": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_UC32_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX340F512.ld", - "mcu": "32MX340F512H", - "variant": "uC32" - }, - "frameworks": ["arduino"], - "name": "Digilent chipKIT uC32", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 520192, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://store.digilentinc.com/chipkit-uc32-basic-microcontroller-board-with-uno-r3-headers/", - "vendor": "Digilent" - }, - - "uno_pic32": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_UNO_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX320F128.ld", - "mcu": "32MX320F128H", - "variant": "Uno32" - }, - "frameworks": ["arduino"], - "name": "Digilent chipKIT UNO32", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 126976, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://store.digilentinc.com/chipkit-uno32-basic-microcontroller-board-retired-see-chipkit-uc32/", - "vendor": "Digilent" - }, - - "chipkit_wf32": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_WF32_", - "f_cpu": "80000000L", - "ldscript": "chipKIT-application-32MX695F512.ld", - "mcu": "32MX695F512L", - "variant": "WF32" - }, - "frameworks": ["arduino"], - "name": "Digilent chipKIT WF32", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 520192, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://store.digilentinc.com/chipkit-wf32-wifi-enabled-microntroller-board-with-uno-r3-headers/", - "vendor": "Digilent" - }, - - "chipkit_wifire": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_WIFIRE_", - "f_cpu": "200000000L", - "ldscript": "MZ-application-32MZ2048ECX.ld", - "mcu": "32MZ2048ECG100", - "variant": "WiFire" - }, - "frameworks": ["arduino"], - "name": "Digilent chipKIT WiFire", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 524288, - "maximum_size": 2080768, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://store.digilentinc.com/chipkit-wi-fire-wifi-enabled-mz-microcontroller-board/", - "vendor": "Digilent" - }, - - "openscope": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_OPENSCOPE_", - "f_cpu": "200000000L", - "ldscript": "MZ-application-32MZ2048ECX.ld", - "mcu": "32MZ2048EFG124", - "variant": "OpenScope" - }, - "frameworks": ["arduino"], - "name": "Digilent OpenScope", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 524288, - "maximum_size": 2080768, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://store.digilentinc.com/", - "vendor": "Digilent" - }, - - "openbci": { - "build": { - "core": "pic32", - "extra_flags": "-D_BOARD_DP32_ -D_USE_USB_FOR_SERIAL_", - "f_cpu": "40000000L", - "ldscript": "chipKIT-application-32MX250F128.ld", - "mcu": "32MX250F128B", - "variant": "OpenBCI" - }, - "frameworks": ["arduino"], - "name": "OpenBCI 32bit", - "platform": "microchippic32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 122880, - "protocol": "stk500v2", - "require_upload_port" : true, - "speed": 115200, - "wait_for_upload_port": true - }, - "url": "http://shop.openbci.com/", - "vendor": "OpenBCI" - } -} diff --git a/platformio/boards/microduino.json b/platformio/boards/microduino.json deleted file mode 100644 index 64e88ec5..00000000 --- a/platformio/boards/microduino.json +++ /dev/null @@ -1,197 +0,0 @@ -{ - "1284p16m": { - "build": { - "board": "AVR_MICRODUINO_CORE_PLUS", - "core": "arduino", - "f_cpu": "16000000L", - "mcu": "atmega1284p", - "variant": "plus" - }, - "frameworks": ["arduino"], - "name": "Microduino Core+ (ATmega1284P@16M,5V)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 130048, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.microduino.cc/wiki/index.php?title=Microduino-Core%2B", - "vendor": "Microduino" - }, - "1284p8m": { - "build": { - "board": "AVR_MICRODUINO_CORE_PLUS", - "core": "arduino", - "f_cpu": "8000000L", - "mcu": "atmega1284p", - "variant": "plus" - }, - "frameworks": ["arduino"], - "name": "Microduino Core+ (ATmega1284P@8M,3.3V)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 130048, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "https://www.microduino.cc/wiki/index.php?title=Microduino-Core%2B", - "vendor": "Microduino" - }, - "168pa16m": { - "build": { - "board": "AVR_MICRODUINO_CORE", - "core": "arduino", - "f_cpu": "16000000L", - "mcu": "atmega168p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "Microduino Core (Atmega168PA@16M,5V)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 15872, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.microduino.cc/wiki/index.php?title=Microduino-Core", - "vendor": "Microduino" - }, - "168pa8m": { - "build": { - "board": "AVR_MICRODUINO_CORE", - "core": "arduino", - "f_cpu": "8000000L", - "mcu": "atmega168p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "Microduino Core (Atmega168PA@8M,3.3V)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 15872, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "https://www.microduino.cc/wiki/index.php?title=Microduino-Core", - "vendor": "Microduino" - }, - "328p16m": { - "build": { - "board": "AVR_MICRODUINO_CORE", - "core": "arduino", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "Microduino Core (Atmega328P@16M,5V)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 32256, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.microduino.cc/wiki/index.php?title=Microduino-Core", - "vendor": "Microduino" - }, - "328p8m": { - "build": { - "board": "AVR_MICRODUINO_CORE", - "core": "arduino", - "f_cpu": "8000000L", - "mcu": "atmega328p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "Microduino Core (Atmega328P@8M,3.3V)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 32256, - "require_upload_port" : true, - "protocol": "arduino", - "speed": 57600 - }, - "url": "https://www.microduino.cc/wiki/index.php?title=Microduino-Core", - "vendor": "Microduino" - }, - "32u416m": { - "build": { - "board": "AVR_MICRODUINO_CORE_USB", - "core": "arduino", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "variant": "32u4", - "hwid": [ - ["0x2341", "0x8036"] - ] - }, - "frameworks": ["arduino"], - "name": "Microduino Core USB (ATmega32U4@16M,5V)", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "https://www.microduino.cc/wiki/index.php?title=Microduino-CoreUSB", - "vendor": "Microduino" - }, - "644pa16m": { - "build": { - "board": "AVR_MICRODUINO_CORE_PLUS", - "core": "arduino", - "f_cpu": "16000000L", - "mcu": "atmega644p", - "variant": "plus" - }, - "frameworks": ["arduino"], - "name": "Microduino Core+ (Atmega644PA@16M,5V)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 4096, - "maximum_size": 64512, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.microduino.cc/wiki/index.php?title=Microduino-Core%2B", - "vendor": "Microduino" - }, - "644pa8m": { - "build": { - "board": "AVR_MICRODUINO_CORE_PLUS", - "core": "arduino", - "f_cpu": "8000000L", - "mcu": "atmega644p", - "variant": "plus" - }, - "frameworks": ["arduino"], - "name": "Microduino Core+ (Atmega644PA@8M,3.3V)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 4096, - "maximum_size": 64512, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "https://www.microduino.cc/wiki/index.php?title=Microduino-Core%2B", - "vendor": "Microduino" - } -} \ No newline at end of file diff --git a/platformio/boards/mightycore.json b/platformio/boards/mightycore.json deleted file mode 100644 index 7ee7913f..00000000 --- a/platformio/boards/mightycore.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "mightycore1284": { - "build": { - "core": "MightyCore", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATmega1284", - "f_cpu": "16000000L", - "mcu": "atmega1284p", - "variant": "mightycore" - }, - "frameworks": ["arduino"], - "name": "MightyCore ATmega1284", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 130048, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.tindie.com/products/MCUdude/dip-40-arduino-compatible-development-board", - "vendor": "Mcudude" - }, - - "mightycore644": { - "build": { - "core": "MightyCore", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATmega644", - "f_cpu": "16000000L", - "mcu": "atmega644p", - "variant": "mightycore" - }, - "frameworks": ["arduino"], - "name": "MightyCore ATmega644", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 4096, - "maximum_size": 64512, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.tindie.com/products/MCUdude/dip-40-arduino-compatible-development-board", - "vendor": "Mcudude" - }, - - "mightycore324": { - "build": { - "core": "MightyCore", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATmega324", - "f_cpu": "16000000L", - "mcu": "atmega324p", - "variant": "mightycore" - }, - "frameworks": ["arduino"], - "name": "MightyCore ATmega324", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 32256, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.tindie.com/products/MCUdude/dip-40-arduino-compatible-development-board", - "vendor": "Mcudude" - }, - - "mightycore164": { - "build": { - "core": "MightyCore", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATmega164", - "f_cpu": "16000000L", - "mcu": "atmega164p", - "variant": "mightycore" - }, - "frameworks": ["arduino"], - "name": "MightyCore ATmega164", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 15872, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.tindie.com/products/MCUdude/dip-40-arduino-compatible-development-board", - "vendor": "Mcudude" - }, - - "mightycore32": { - "build": { - "core": "MightyCore", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATmega32", - "f_cpu": "16000000L", - "mcu": "atmega32", - "variant": "mightycore" - }, - "frameworks": ["arduino"], - "name": "MightyCore ATmega32", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 32256, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.tindie.com/products/MCUdude/dip-40-arduino-compatible-development-board", - "vendor": "Mcudude" - }, - - "mightycore16": { - "build": { - "core": "MightyCore", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATmega16", - "f_cpu": "16000000L", - "mcu": "atmega16", - "variant": "mightycore" - }, - "frameworks": ["arduino"], - "name": "MightyCore ATmega16", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 15872, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.tindie.com/products/MCUdude/dip-40-arduino-compatible-development-board", - "vendor": "Mcudude" - }, - - "mightycore8535": { - "build": { - "core": "MightyCore", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATmega8535", - "f_cpu": "16000000L", - "mcu": "atmega16", - "variant": "mightycore" - }, - "frameworks": ["arduino"], - "name": "MightyCore ATmega8535", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 512, - "maximum_size": 7680, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.tindie.com/products/MCUdude/dip-40-arduino-compatible-development-board", - "vendor": "Mcudude" - } -} diff --git a/platformio/boards/misc.json b/platformio/boards/misc.json deleted file mode 100644 index bbff9241..00000000 --- a/platformio/boards/misc.json +++ /dev/null @@ -1,742 +0,0 @@ -{ - "ardhat": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_ARDHAT", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "ubIQio Ardhat", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 32256, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://ardhat.com", - "vendor": "ubIQio" - }, - - "raspduino": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_RASPDUINO", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "BitWizard Raspduino", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 30720, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "http://www.bitwizard.nl/wiki/index.php/Raspduino", - "vendor": "BitWizard" - }, - - "sainSmartDue": { - "build": { - "core": "arduino", - "extra_flags": "-D__SAM3X8E__ -DARDUINO_SAM_DUE -DARDUINO_ARCH_SAM", - "f_cpu": "84000000L", - "mcu": "at91sam3x8e", - "cpu": "cortex-m3", - "usb_product": "Arduino Due", - "variant": "arduino_due_x", - "ldscript": "sam3x8e.ld", - "hwid": [ - ["0x2341", "0x003E"] - ] - }, - "frameworks": ["arduino"], - "name": "SainSmart Due (Programming Port)", - "platform": "atmelsam", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 32768, - "maximum_size": 524288, - "protocol": "sam-ba", - "require_upload_port" : true, - "use_1200bps_touch": true, - "wait_for_upload_port": false - }, - "url": "http://www.sainsmart.com/arduino/control-boards/sainsmart-due-atmel-sam3x8e-arm-cortex-m3-board-black.html", - "vendor": "SainSmart" - }, - "sainSmartDueUSB": { - "build": { - "core": "arduino", - "extra_flags": "-D__SAM3X8E__ -DARDUINO_SAM_DUE -DARDUINO_ARCH_SAM", - "f_cpu": "84000000L", - "mcu": "at91sam3x8e", - "cpu": "cortex-m3", - "usb_product": "Arduino Due", - "variant": "arduino_due_x", - "ldscript": "sam3x8e.ld", - "hwid": [ - ["0x2341", "0x003E"] - ] - }, - "frameworks": ["arduino"], - "name": "SainSmart Due (USB Native Port)", - "platform": "atmelsam", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 32768, - "maximum_size": 524288, - "protocol": "sam-ba", - "require_upload_port" : true, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://www.sainsmart.com/arduino/control-boards/sainsmart-due-atmel-sam3x8e-arm-cortex-m3-board-black.html", - "vendor": "SainSmart" - }, - - "panStampAVR": { - "build": { - "core": "panstamp", - "extra_flags": "-DPANSTAMP_AVR", - "f_cpu": "8000000L", - "mcu": "atmega328p", - "variant": "panstamp" - }, - "frameworks": ["arduino"], - "name": "PanStamp AVR", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 32256, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "http://www.panstamp.com/product/panstamp-avr/", - "vendor": "PanStamp" - }, - - "panStampNRG": { - "build": { - "core": "panstamp", - "f_cpu": "12000000L", - "mcu": "cc430f5137", - "variant": "panstamp_nrg_1.1" - }, - "frameworks": ["arduino"], - "name": "PanStamp NRG 1.1", - "platform": "timsp430", - "upload": { - "maximum_ram_size": 4096, - "maximum_size": 32640, - "protocol": "flash-bsl" - }, - "url": "http://www.panstamp.com/product/197/", - "vendor": "PanStamp" - }, - "reprap_rambo": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_RAMBO", - "f_cpu": "16000000L", - "mcu": "atmega2560", - "variant": "rambo" - }, - "frameworks": ["arduino"], - "name": "RepRap RAMBo", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 258048, - "protocol": "wiring", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://reprap.org/wiki/Rambo", - "vendor": "RepRap" - }, - - "sanguino_atmega1284p": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_SANGUINO", - "f_cpu": "16000000L", - "mcu": "atmega1284p", - "variant": "sanguino" - }, - "frameworks": ["arduino"], - "name": "Sanguino ATmega1284p (16MHz)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 130048, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://code.google.com/p/sanguino/", - "vendor": "Sanguino" - }, - - "sanguino_atmega1284_8m": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_SANGUINO", - "f_cpu": "8000000L", - "mcu": "atmega1284p", - "variant": "sanguino" - }, - "frameworks": ["arduino"], - "name": "Sanguino ATmega1284p (8MHz)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 130048, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "https://code.google.com/p/sanguino/", - "vendor": "Sanguino" - }, - - "sanguino_atmega644": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_SANGUINO", - "f_cpu": "16000000L", - "mcu": "atmega644", - "variant": "sanguino" - }, - "frameworks": ["arduino"], - "name": "Sanguino ATmega644 or ATmega644A (16 MHz)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 4096, - "maximum_size": 64512, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://code.google.com/p/sanguino/", - "vendor": "Sanguino" - }, - - "sanguino_atmega644_8m": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_SANGUINO", - "f_cpu": "8000000L", - "mcu": "atmega644", - "variant": "sanguino" - }, - "frameworks": ["arduino"], - "name": "Sanguino ATmega644 or ATmega644A (8 MHz)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 4096, - "maximum_size": 64512, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "https://code.google.com/p/sanguino/", - "vendor": "Sanguino" - }, - - "sanguino_atmega644p": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_SANGUINO", - "f_cpu": "16000000L", - "mcu": "atmega644p", - "variant": "sanguino" - }, - "frameworks": ["arduino"], - "name": "Sanguino ATmega644P or ATmega644PA (16 MHz)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 4096, - "maximum_size": 64512, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://code.google.com/p/sanguino/", - "vendor": "Sanguino" - }, - - "sanguino_atmega644p_8m": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_SANGUINO", - "f_cpu": "8000000L", - "mcu": "atmega644p", - "variant": "sanguino" - }, - "frameworks": ["arduino"], - "name": "Sanguino ATmega644P or ATmega644PA (8 MHz)", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 4096, - "maximum_size": 64512, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "https://code.google.com/p/sanguino/", - "vendor": "Sanguino" - }, - - "tinyduino": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_LILYPAD", - "f_cpu": "8000000L", - "mcu": "atmega328p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "TinyCircuits TinyDuino Processor Board", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 30720, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "https://tiny-circuits.com/tinyduino-processor-board.html", - "vendor": "TinyCircuits" - }, - - "blend": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "usb_product": "RedBearLab Blend", - "variant": "leonardo", - "hwid": [ - ["0x2341", "0x8036"] - ] - }, - "frameworks": ["arduino"], - "name": "RedBearLab Blend", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://redbearlab.com/blend/", - "vendor": "RedBearLab" - }, - - "blendmicro8": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR", - "f_cpu": "8000000L", - "mcu": "atmega32u4", - "usb_product": "RedBearLab Blend", - "variant": "micro", - "hwid": [ - ["0x03EB", "0x2404"] - ] - }, - "frameworks": ["arduino"], - "name": "RedBearLab Blend Micro 3.3V/8MHz", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://redbearlab.com/blendmicro/", - "vendor": "RedBearLab" - }, - - "blendmicro16": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "usb_product": "RedBearLab Blend", - "variant": "micro", - "hwid": [ - ["0x03EB", "0x2404"] - ] - }, - "frameworks": ["arduino"], - "name": "RedBearLab Blend Micro 3.3V/16MHz (overclock)", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://redbearlab.com/blendmicro/", - "vendor": "RedBearLab" - }, - - "tinylily": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_LILYPAD", - "f_cpu": "8000000L", - "mcu": "atmega328p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "TinyCircuits TinyLily Mini Processor", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 30720, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 57600 - }, - "url": "https://tiny-circuits.com/tiny-lily-mini-processor.html", - "vendor": "TinyCircuits" - }, - - "lightup": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_LEONARDO", - "f_cpu": "8000000L", - "mcu": "atmega32u4", - "usb_product": "LightUp", - "variant": "leonardo", - "hwid": [ - ["0x1d50", "0x6096"] - ] - }, - "frameworks": ["arduino"], - "name": "LightUp", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "https://www.lightup.io/", - "vendor": "LightUp" - }, - - "moteino": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_MOTEINO", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "LowPowerLab Moteino", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 31744, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://lowpowerlab.com/shop/moteino-r4", - "vendor": "LowPowerLab" - }, - - "moteinomega": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_MOTEINOMEGA", - "f_cpu": "16000000L", - "mcu": "atmega1284p", - "variant": "moteinomega" - }, - "frameworks": ["arduino"], - "name": "LowPowerLab MoteinoMEGA", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 130048, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://lowpowerlab.com/blog/2014/08/09/moteinomega-available-now/", - "vendor": "LowPowerLab" - }, - - "zumbt328": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_BT", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "eightanaloginputs" - }, - "frameworks": ["arduino"], - "name": "BQ ZUM BT-328", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2048, - "maximum_size": 28672, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 19200 - }, - "url": "http://www.bq.com/gb/products/zum.html", - "vendor": "BQ" - }, - - "quirkbot": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DQUIRKBOT", - "f_cpu": "8000000L", - "mcu": "atmega32u4", - "variant" : "quirkbot", - "usb_product": "Quirkbot", - "hwid": [ - ["0x2886", "0xf004"], - ["0x2886", "0xf005"], - ["0x2886", "0xf006"], - ["0x2886", "0xf007"] - ] - }, - "frameworks": ["arduino"], - "name": "Quirkbot", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "http://quirkbot.com", - "vendor": "Quirkbot" - }, - - "wildfirev2": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_MEGA", - "f_cpu": "16000000L", - "mcu": "atmega1284p", - "variant": "wildfirev2" - }, - "frameworks": ["arduino"], - "name": "Wicked Device WildFire V2", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 122878, - "protocol": "wiring", - "require_upload_port" : true, - "speed": 38400 - }, - "url": "http://shop.wickeddevice.com/resources/wildfire/", - "vendor": "Wicked Device" - }, - - "wildfirev3": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_MEGA", - "f_cpu": "16000000L", - "mcu": "atmega1284p", - "variant": "wildfirev3" - }, - "frameworks": ["arduino"], - "name": "Wicked Device WildFire V3", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 130048, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "http://shop.wickeddevice.com/resources/wildfire/", - "vendor": "Wicked Device" - }, - - "attiny13": { - "build": { - "core": "core13", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATTINY13", - "f_cpu": "9600000L", - "mcu": "attiny13" - }, - "frameworks": ["arduino"], - "name": "Generic ATTiny13", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 64, - "maximum_size": 1024, - "protocol": "arduinoisp", - "require_upload_port" : true, - "speed": 19200 - }, - "url": "http://www.atmel.com/devices/ATTINY13.aspx", - "vendor": "Generic ATTiny" - }, - - "attiny24": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATTINY24", - "f_cpu": "8000000L", - "mcu": "attiny24", - "variant": "tiny14" - }, - "frameworks": ["arduino"], - "name": "Generic ATTiny24", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 128, - "maximum_size": 2048, - "protocol": "usbtiny" - }, - "url": "http://www.atmel.com/devices/ATTINY24.aspx", - "vendor": "Generic ATTiny" - }, - - "attiny25": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATTINY25", - "f_cpu": "8000000L", - "mcu": "attiny25", - "variant": "tiny8" - }, - "frameworks": ["arduino"], - "name": "Generic ATTiny25", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 128, - "maximum_size": 2048, - "protocol": "usbtiny" - }, - "url": "http://www.atmel.com/devices/ATTINY25.aspx", - "vendor": "Generic ATTiny" - }, - - "attiny44": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATTINY44", - "f_cpu": "8000000L", - "mcu": "attiny44", - "variant": "tiny14" - }, - "frameworks": ["arduino"], - "name": "Generic ATTiny44", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 256, - "maximum_size": 4096, - "protocol": "usbtiny" - }, - "url": "http://www.atmel.com/devices/ATTINY44.aspx", - "vendor": "Generic ATTiny" - }, - - "attiny45": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATTINY45", - "f_cpu": "8000000L", - "mcu": "attiny45", - "variant": "tiny8" - }, - "frameworks": ["arduino"], - "name": "Generic ATTiny45", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 256, - "maximum_size": 4096, - "protocol": "usbtiny" - }, - "url": "http://www.atmel.com/devices/ATTINY45.aspx", - "vendor": "Generic ATTiny" - }, - - "attiny84": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATTINY84", - "f_cpu": "8000000L", - "mcu": "attiny84", - "variant": "tiny14" - }, - "frameworks": ["arduino"], - "name": "Generic ATTiny84", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 512, - "maximum_size": 8192, - "protocol": "usbtiny" - }, - "url": "http://www.atmel.com/devices/ATTINY84.aspx", - "vendor": "Generic ATTiny" - }, - - "attiny85": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATTINY85", - "f_cpu": "8000000L", - "mcu": "attiny85", - "variant": "tiny8" - }, - "frameworks": ["arduino"], - "name": "Generic ATTiny85", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 512, - "maximum_size": 8192, - "protocol": "usbtiny" - }, - "url": "http://www.atmel.com/devices/ATTINY85.aspx", - "vendor": "Generic ATTiny" - } -} diff --git a/platformio/boards/nordicnrf51.json b/platformio/boards/nordicnrf51.json deleted file mode 100644 index 1a80b2fd..00000000 --- a/platformio/boards/nordicnrf51.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "nrf51_mkit": { - "build": { - "f_cpu": "16000000L", - "cpu": "cortex-m0", - "mcu": "nrf51822" - }, - "frameworks": ["mbed"], - "name": "Nordic nRF51822-mKIT", - "platform": "nordicnrf51", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 131072 - }, - "url": "http://developer.mbed.org/platforms/Nordic-nRF51822/", - "vendor": "Nordic" - }, - "hrm1017": { - "build": { - "f_cpu": "16000000L", - "cpu": "cortex-m0", - "mcu": "nrf51822" - }, - "frameworks": ["mbed"], - "name": "Switch Science mbed HRM1017", - "platform": "nordicnrf51", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/mbed-HRM1017/", - "vendor": "Switch Science" - }, - "redBearLab": { - "build": { - "f_cpu": "16000000L", - "cpu": "cortex-m0", - "mcu": "nrf51822" - }, - "frameworks": ["mbed"], - "name": "RedBearLab nRF51822", - "platform": "nordicnrf51", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/RedBearLab-nRF51822/", - "vendor": "RedBearLab" - }, - "nrf51_dk": { - "build": { - "f_cpu": "32000000L", - "cpu": "cortex-m0", - "mcu": "nrf51822" - }, - "frameworks": ["mbed"], - "name": "Nordic nRF51-DK", - "platform": "nordicnrf51", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/Nordic-nRF51-DK/", - "vendor": "Nordic" - }, - "redBearLabBLENano": { - "build": { - "f_cpu": "16000000L", - "cpu": "cortex-m0", - "mcu": "nrf51822" - }, - "frameworks": ["mbed"], - "name": "RedBearLab BLE Nano", - "platform": "nordicnrf51", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/RedBearLab-BLE-Nano/", - "vendor": "RedBearLab" - }, - "nrf51_dongle": { - "build": { - "f_cpu": "32000000L", - "cpu": "cortex-m0", - "mcu": "nrf51822" - }, - "frameworks": ["mbed"], - "name": "Nordic nRF51-Dongle", - "platform": "nordicnrf51", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/Nordic-nRF51-Dongle/", - "vendor": "Nordic" - }, - "wallBotBLE": { - "build": { - "f_cpu": "16000000L", - "cpu": "cortex-m0", - "mcu": "nrf51822" - }, - "frameworks": ["mbed"], - "name": "JKSoft Wallbot BLE", - "platform": "nordicnrf51", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 131072 - }, - "url": "https://developer.mbed.org/platforms/JKSoft-Wallbot-BLE/", - "vendor": "JKSoft" - }, - "seeedTinyBLE": { - "build": { - "f_cpu": "16000000L", - "cpu": "cortex-m0", - "mcu": "nrf51822" - }, - "frameworks": ["mbed"], - "name": "SeeedStudio Seeed Tiny BLE", - "platform": "nordicnrf51", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 262144 - }, - "url": "http://developer.mbed.org/platforms/Seeed-Tiny-BLE/", - "vendor": "SeeedStudio" - }, - "dfcm_nnn40": { - "build": { - "f_cpu": "32000000L", - "cpu": "cortex-m0", - "mcu": "nrf51822" - }, - "frameworks": ["mbed"], - "name": "Delta DFCM-NNN40", - "platform": "nordicnrf51", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/Delta-DFCM-NNN40/", - "vendor": "Delta" - }, - "rfduino": { - "build": { - "core": "arduino", - "extra_flags": "-D__RFduino__", - "f_cpu": "16000000L", - "ldscript": "RFduino.ld", - "cpu": "cortex-m0", - "mcu": "nrf51822", - "variant": "RFduino" - }, - "frameworks": ["arduino"], - "name": "RFduino", - "platform": "nordicnrf51", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 131072 - }, - "url": "http://www.rfduino.com/product/rfd22102-rfduino-dip/index.html", - "vendor": "RFduino" - }, - "bbcmicrobit": { - "build": { - "f_cpu": "16000000L", - "cpu": "cortex-m0", - "mcu": "nrf51822" - }, - "frameworks": ["mbed"], - "name": "BBC micro:bit", - "platform": "nordicnrf51", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/Microbit/", - "vendor": "BBC" - } -} diff --git a/platformio/boards/nxplpc.json b/platformio/boards/nxplpc.json deleted file mode 100644 index de29b022..00000000 --- a/platformio/boards/nxplpc.json +++ /dev/null @@ -1,210 +0,0 @@ -{ - "lpc1768": { - "build": { - "f_cpu": "96000000L", - "cpu": "cortex-m3", - "mcu": "lpc1768" - }, - "frameworks": ["mbed"], - "name": "NXP mbed LPC1768", - "platform": "nxplpc", - "upload": { - "maximum_ram_size": 65536, - "maximum_size": 524288 - }, - "url": "http://developer.mbed.org/platforms/mbed-LPC1768/", - "vendor": "NXP" - }, - "lpc11u24": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0", - "mcu": "lpc11u24" - }, - "frameworks": ["mbed"], - "name": "NXP mbed LPC11U24", - "platform": "nxplpc", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 32768 - }, - "url": "https://developer.mbed.org/platforms/mbed-LPC11U24/", - "vendor": "NXP" - }, - "lpc4088": { - "build": { - "f_cpu": "120000000L", - "cpu": "cortex-m4", - "mcu": "lpc4088" - }, - "frameworks": ["mbed"], - "name": "Embedded Artists LPC4088 QuickStart Board", - "platform": "nxplpc", - "upload": { - "maximum_ram_size": 98304, - "maximum_size": 524288 - }, - "url": "https://developer.mbed.org/platforms/EA-LPC4088/", - "vendor": "Embedded Artists" - }, - "dipcortexm0": { - "build": { - "f_cpu": "50000000L", - "cpu": "cortex-m0", - "mcu": "lpc11u24" - }, - "frameworks": ["mbed"], - "name": "Solder Splash Labs DipCortex M0", - "platform": "nxplpc", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 32768 - }, - "url": "https://developer.mbed.org/platforms/DipCortex-M0/", - "vendor": "Solder Splash Labs" - }, - "blueboard_lpc11u24": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0", - "mcu": "lpc11u24" - }, - "frameworks": ["mbed"], - "name": "NGX Technologies BlueBoard-LPC11U24", - "platform": "nxplpc", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 32768 - }, - "url": "https://developer.mbed.org/platforms/BlueBoard-LPC11U24/", - "vendor": "NGX Technologies" - }, - "seeeduinoArchPro": { - "build": { - "f_cpu": "96000000L", - "cpu": "cortex-m3", - "mcu": "lpc1768" - }, - "frameworks": ["mbed"], - "name": "SeeedStudio Seeeduino-Arch-Pro", - "platform": "nxplpc", - "upload": { - "maximum_ram_size": 65536, - "maximum_size": 524288 - }, - "url": "https://developer.mbed.org/platforms/Seeeduino-Arch-Pro/", - "vendor": "SeeedStudio" - }, - "ubloxc027": { - "build": { - "f_cpu": "96000000L", - "cpu": "cortex-m3", - "mcu": "lpc1768" - }, - "frameworks": ["mbed"], - "name": "u-blox C027", - "platform": "nxplpc", - "upload": { - "maximum_ram_size": 65536, - "maximum_size": 524288 - }, - "url": "https://developer.mbed.org/platforms/u-blox-C027/", - "vendor": "u-blox" - }, - "lpc1114fn28": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0", - "mcu": "lpc1114fn28" - }, - "frameworks": ["mbed"], - "name": "Switch Science mbed LPC1114FN28", - "platform": "nxplpc", - "upload": { - "maximum_ram_size": 4096, - "maximum_size": 32768 - }, - "url": "https://developer.mbed.org/platforms/LPC1114FN28/", - "vendor": "Switch Science" - }, - "lpc11u35": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0", - "mcu": "lpc11u35" - }, - "frameworks": ["mbed"], - "name": "Embedded Artists LPC11U35 QuickStart Board", - "platform": "nxplpc", - "upload": { - "maximum_ram_size": 10240, - "maximum_size": 65536 - }, - "url": "https://developer.mbed.org/platforms/EA-LPC11U35/", - "vendor": "Embedded Artists" - }, - "lpc11u35_501": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0", - "mcu": "lpc11u35" - }, - "frameworks": ["mbed"], - "name": "CQ Publishing TG-LPC11U35-501", - "platform": "nxplpc", - "upload": { - "maximum_ram_size": 10240, - "maximum_size": 65536 - }, - "url": "https://developer.mbed.org/platforms/TG-LPC11U35-501/", - "vendor": "CQ Publishing" - }, - "lpc1549": { - "build": { - "f_cpu": "72000000L", - "cpu": "cortex-m3", - "mcu": "lpc1549" - }, - "frameworks": ["mbed"], - "name": "NXP LPCXpresso1549", - "platform": "nxplpc", - "upload": { - "maximum_ram_size": 36864, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/LPCXpresso1549/", - "vendor": "NXP" - }, - "mbuino": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0", - "mcu": "lpc11u24" - }, - "frameworks": ["mbed"], - "name": "Outrageous Circuits mBuino", - "platform": "nxplpc", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 32768 - }, - "url": "https://developer.mbed.org/platforms/Outrageous-Circuits-mBuino/", - "vendor": "Outrageous Circuits" - }, - "lpc4088_dm": { - "build": { - "f_cpu": "120000000L", - "cpu": "cortex-m4", - "mcu": "lpc4088" - }, - "frameworks": ["mbed"], - "name": "Embedded Artists LPC4088 Display Module", - "platform": "nxplpc", - "upload": { - "maximum_ram_size": 98304, - "maximum_size": 524288 - }, - "url": "https://developer.mbed.org/platforms/EA-LPC4088-Display-Module/", - "vendor": "Embedded Artists" - } -} \ No newline at end of file diff --git a/platformio/boards/punchthrough.json b/platformio/boards/punchthrough.json deleted file mode 100644 index 6e7d41ed..00000000 --- a/platformio/boards/punchthrough.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "lightblue-bean": { - "name": "LightBlue Bean", - "vendor": "Punch Through", - "url": "https://punchthrough.com/bean", - - "platform": "atmelavr", - "frameworks": ["arduino"], - - "build": { - "core": "bean", - "variant": "bean", - "extra_flags": "-DARDUINO_ARCH_AVR", - "mcu": "atmega328p", - "f_cpu": "8000000L" - }, - "upload": { - "maximum_size": 32256, - "maximum_ram_size": 2048 - } - } -} diff --git a/platformio/boards/raspberrypi.json b/platformio/boards/raspberrypi.json deleted file mode 100644 index 25c3485a..00000000 --- a/platformio/boards/raspberrypi.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "raspberrypi_1b": { - "build": { - "extra_flags": "-DRASPBERRYPI -DRASPBERRYPI1", - "f_cpu": "700000000L", - "mcu": "bcm2835" - }, - "frameworks": ["wiringpi"], - "name": "Raspberry Pi 1 Model B", - "platform": "linux_arm", - "upload": { - "maximum_ram_size": 536870912, - "maximum_size": 536870912 - }, - "url": "https://www.raspberrypi.org", - "vendor": "Raspberry Pi" - }, - - "raspberrypi_2b": { - "build": { - "extra_flags": "-DRASPBERRYPI -DRASPBERRYPI2", - "f_cpu": "900000000L", - "mcu": "bcm2836" - }, - "frameworks": ["wiringpi"], - "name": "Raspberry Pi 2 Model B", - "platform": "linux_arm", - "upload": { - "maximum_ram_size": 1073741824, - "maximum_size": 1073741824 - }, - "url": "https://www.raspberrypi.org", - "vendor": "Raspberry Pi" - }, - - "raspberrypi_zero": { - "build": { - "extra_flags": "-DRASPBERRYPI -DRASPBERRYPIZERO", - "f_cpu": "1000000000L", - "mcu": "bcm2835" - }, - "frameworks": ["wiringpi"], - "name": "Raspberry Pi Zero", - "platform": "linux_arm", - "upload": { - "maximum_ram_size": 536870912, - "maximum_size": 536870912 - }, - "url": "https://www.raspberrypi.org", - "vendor": "Raspberry Pi" - } -} diff --git a/platformio/boards/siliconlabsefm32.json b/platformio/boards/siliconlabsefm32.json deleted file mode 100644 index e4d55f18..00000000 --- a/platformio/boards/siliconlabsefm32.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "efm32wg_stk3800": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m4", - "mcu": "efm32wg990f256" - }, - "frameworks": ["mbed"], - "name": "Silicon Labs EFM32WG-STK3800 (Wonder Gecko)", - "platform": "siliconlabsefm32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/EFM32-Wonder-Gecko/", - "vendor": "Silicon Labs" - }, - - "efm32gg_stk3700": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m3", - "mcu": "efm32gg990f1024" - }, - "frameworks": ["mbed"], - "name": "Silicon Labs EFM32GG-STK3700 (Giant Gecko)", - "platform": "siliconlabsefm32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 1048576 - }, - "url": "https://developer.mbed.org/platforms/EFM32-Giant-Gecko/", - "vendor": "Silicon Labs" - }, - - "efm32lg_stk3600": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m3", - "mcu": "efm32lg990f256" - }, - "frameworks": ["mbed"], - "name": "Silicon Labs EFM32LG-STK3600 (Leopard Gecko)", - "platform": "siliconlabsefm32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/EFM32-Leopard-Gecko/", - "vendor": "Silicon Labs" - }, - - "efm32zg_stk3200": { - "build": { - "f_cpu": "24000000L", - "cpu": "cortex-m0plus", - "mcu": "efm2zg222f32" - }, - "frameworks": ["mbed"], - "name": "Silicon Labs EFM32ZG-STK3200 (Zero Gecko)", - "platform": "siliconlabsefm32", - "upload": { - "maximum_ram_size": 4096, - "maximum_size": 32768 - }, - "url": "https://developer.mbed.org/platforms/EFM32-Zero-Gecko/", - "vendor": "Silicon Labs" - }, - - "efm32hg_stk3400": { - "build": { - "f_cpu": "24000000L", - "cpu": "cortex-m3", - "mcu": "efm32hg322f64" - }, - "frameworks": ["mbed"], - "name": "Silicon Labs SLSTK3400A USB-enabled (Happy Gecko)", - "platform": "siliconlabsefm32", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 65536 - }, - "url": "https://developer.mbed.org/platforms/EFM32-Happy-Gecko/", - "vendor": "Silicon Labs" - }, - - "efm32pg_stk3401": { - "build": { - "f_cpu": "40000000L", - "cpu": "cortex-m4", - "mcu": "efm32pg1b200f256" - }, - "frameworks": ["mbed"], - "name": "Silicon Labs SLSTK3401A (Pearl Gecko)", - "platform": "siliconlabsefm32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/EFM32-Pearl-Gecko/", - "vendor": "Silicon Labs" - } -} diff --git a/platformio/boards/sparkfun.json b/platformio/boards/sparkfun.json deleted file mode 100644 index 6bf11499..00000000 --- a/platformio/boards/sparkfun.json +++ /dev/null @@ -1,242 +0,0 @@ - { - "sparkfun_redboard": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_UNO", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "SparkFun RedBoard", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 32256, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.sparkfun.com/products/12757", - "vendor": "SparkFun" - }, - "sparkfun_promicro16": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_PROMICRO16", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "usb_product": "SparkFun Pro Micro", - "variant": "sparkfun_promicro", - "hwid": [ - ["0x1B4F", "0x9205"], - ["0x1B4F", "0x9206"] - ] - }, - "frameworks": ["arduino"], - "name": "SparkFun Pro Micro 5V/16MHz", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "https://www.sparkfun.com/products/12640", - "vendor": "SparkFun" - }, - "sparkfun_promicro8": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_PROMICRO8", - "f_cpu": "8000000L", - "mcu": "atmega32u4", - "usb_product": "SparkFun Pro Micro", - "variant": "sparkfun_promicro", - "hwid": [ - ["0x1B4F", "0x9203"], - ["0x1B4F", "0x9204"] - ] - }, - "frameworks": ["arduino"], - "name": "SparkFun Pro Micro 3.3V/8MHz", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "https://www.sparkfun.com/products/12587", - "vendor": "SparkFun" - }, - "sparkfun_fiov3": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_FIOV3", - "f_cpu": "8000000L", - "mcu": "atmega32u4", - "usb_product": "SparkFun Fio v3", - "variant": "sparkfun_promicro", - "hwid": [ - ["0x1B4F", "0xF100"], - ["0x1B4F", "0xF101"] - ] - }, - "frameworks": ["arduino"], - "name": "SparkFun Fio V3 3.3V/8MHz", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "https://www.sparkfun.com/products/11520", - "vendor": "SparkFun" - }, - "sparkfun_makeymakey": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DAVR_MAKEYMAKEY", - "f_cpu": "16000000L", - "mcu": "atmega32u4", - "usb_product": "SparkFun MaKey", - "variant": "sparkfun_promicro", - "hwid": [ - ["0x1B4F", "0x2B74"], - ["0x1B4F", "0x2B75"] - ] - }, - "frameworks": ["arduino"], - "name": "SparkFun Makey Makey", - "platform": "atmelavr", - "upload": { - "disable_flushing": true, - "maximum_ram_size": 2560, - "maximum_size": 28672, - "protocol": "avr109", - "require_upload_port" : true, - "speed": 57600, - "use_1200bps_touch": true, - "wait_for_upload_port": true - }, - "url": "https://www.sparkfun.com/products/11511", - "vendor": "SparkFun" - }, - "sparkfun_megapro16MHz": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_MEGA2560", - "f_cpu": "16000000L", - "mcu": "atmega2560", - "variant": "mega" - }, - "frameworks": ["arduino"], - "name": "SparkFun Mega Pro 5V/16MHz", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 258048, - "protocol": "stk500v2", - "speed": 57600 - }, - "url": "https://www.sparkfun.com/products/11007", - "vendor": "SparkFun" - }, - "sparkfun_megapro8MHz": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_MEGA2560", - "f_cpu": "8000000L", - "mcu": "atmega2560", - "variant": "mega" - }, - "frameworks": ["arduino"], - "name": "SparkFun Mega Pro 3.3V/8MHz", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 258048, - "protocol": "stk500v2", - "speed": 57600 - }, - "url": "https://www.sparkfun.com/products/10744", - "vendor": "SparkFun" - }, - "sparkfun_megamini": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_MEGA2560", - "f_cpu": "8000000L", - "mcu": "atmega2560", - "variant": "mega" - }, - "frameworks": ["arduino"], - "name": "SparkFun Mega Pro Mini 3.3V", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 258048, - "protocol": "stk500v2", - "speed": 57600 - }, - "url": "https://www.sparkfun.com/products/10743", - "vendor": "SparkFun" - }, - "sparkfun_digitalsandbox": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_UNO", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "SparkFun Digital Sandbox", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 32256, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.sparkfun.com/products/12651", - "vendor": "SparkFun" - }, - - "uview": { - "build": { - "core": "arduino", - "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_UNO", - "f_cpu": "16000000L", - "mcu": "atmega328p", - "variant": "standard" - }, - "frameworks": ["arduino"], - "name": "SparkFun MicroView", - "platform": "atmelavr", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 32256, - "protocol": "arduino", - "require_upload_port" : true, - "speed": 115200 - }, - "url": "https://www.sparkfun.com/products/12923", - "vendor": "SparkFun" - } -} \ No newline at end of file diff --git a/platformio/boards/ststm32.json b/platformio/boards/ststm32.json deleted file mode 100644 index 187d811f..00000000 --- a/platformio/boards/ststm32.json +++ /dev/null @@ -1,625 +0,0 @@ -{ - "disco_f407vg": { - "build": { - "core": "stm32", - "extra_flags": "-DSTM32F4 -DSTM32F407xx -DSTM32F40_41xxx", - "f_cpu": "168000000L", - "ldscript": "stm32f405x6.ld", - "cpu": "cortex-m4", - "mcu": "stm32f407vgt6", - "variant": "stm32f407xx" - }, - "frameworks": ["mbed", "cmsis", "spl", "libopencm3"], - "name": "ST STM32F4DISCOVERY", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 1048576 - }, - "url": "http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1848/PF252419", - "vendor": "ST" - }, - "disco_l152rb": { - "build": { - "core": "stm32", - "extra_flags": "-DSTM32L1 -DSTM32L152xB -DSTM32L1XX_MD", - "f_cpu": "32000000L", - "ldscript": "stm32l15xx6.ld", - "cpu": "cortex-m3", - "mcu": "stm32l152rbt6", - "variant": "stm32l152xb" - }, - "frameworks": ["cmsis", "spl", "libopencm3"], - "name": "ST STM32LDISCOVERY", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 131072 - }, - "url": "http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1848/PF258515", - "vendor": "ST" - }, - "disco_f303vc": { - "build": { - "core": "stm32", - "extra_flags": "-DSTM32F3 -DSTM32F303xC", - "f_cpu": "72000000L", - "ldscript": "stm32f30xx.ld", - "cpu": "cortex-m4", - "mcu": "stm32f303vct6", - "variant": "stm32f303xc" - }, - "frameworks": ["mbed", "cmsis", "spl", "libopencm3"], - "name": "ST STM32F3DISCOVERY", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 49152, - "maximum_size": 262144 - }, - "url": "http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1848/PF254044", - "vendor": "ST" - }, - "disco_f100rb": { - "build": { - "f_cpu": "24000000L", - "cpu": "cortex-m3", - "mcu": "stm32f100rbt6" - }, - "frameworks": ["mbed"], - "name": "ST STM32VLDISCOVERY", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 131072 - }, - "url": "http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1848/PF250863", - "vendor": "ST" - }, - "disco_f051r8": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0", - "mcu": "stm32f051r8t6" - }, - "frameworks": ["mbed"], - "name": "ST STM32F0DISCOVERY", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 65536 - }, - "url": "http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1848/PF253215", - "vendor": "ST" - }, - "disco_f334c8": { - "build": { - "f_cpu": "72000000L", - "cpu": "cortex-m4", - "mcu": "stm32f334c8t6" - }, - "frameworks": ["mbed"], - "name": "ST 32F3348DISCOVERY", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 65536 - }, - "url": "http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1848/PF260318", - "vendor": "ST" - }, - "disco_f401vc": { - "build": { - "f_cpu": "84000000L", - "cpu": "cortex-m4", - "mcu": "stm32f401vct6" - }, - "frameworks": ["mbed"], - "name": "ST 32F401CDISCOVERY", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 65536, - "maximum_size": 262144 - }, - "url": "http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1848/PF259098", - "vendor": "ST" - }, - "disco_f429zi": { - "build": { - "f_cpu": "180000000L", - "cpu": "cortex-m4", - "mcu": "stm32f429zit6" - }, - "frameworks": ["mbed"], - "name": "ST 32F429IDISCOVERY", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 262144, - "maximum_size": 2097152 - }, - "url": "http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1848/PF259090", - "vendor": "ST" - }, - "nucleo_f030r8": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0", - "mcu": "stm32f030r8t6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo F030R8", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 65536 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-F030R8/", - "vendor": "ST" - }, - "nucleo_f070rb": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0", - "mcu": "stm32f070rbt6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo F070RB", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 131072 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-F070RB/", - "vendor": "ST" - }, - "nucleo_f072rb": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0", - "mcu": "stm32f072rbt6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo F072RB", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 131072 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-F072RB/", - "vendor": "ST" - }, - "nucleo_f091rc": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0", - "mcu": "stm32f091rct6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo F091RC", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 262144 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-F091RC/", - "vendor": "ST" - }, - "nucleo_f103rb": { - "build": { - "core": "stm32", - "f_cpu": "72000000L", - "ldscript": "stm32f103xb.ld", - "cpu": "cortex-m3", - "mcu": "stm32f103rbt6", - "variant": "stm32f1" - }, - "frameworks": ["mbed","libopencm3"], - "name": "ST Nucleo F103RB", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 20480, - "maximum_size": 131072 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-F103RB/", - "vendor": "ST" - }, - "nucleo_f302r8": { - "build": { - "f_cpu": "72000000L", - "cpu": "cortex-m4", - "mcu": "stm32f302r8t6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo F302R8", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 65536 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-F302R8/", - "vendor": "ST" - }, - "nucleo_f303re": { - "build": { - "f_cpu": "72000000L", - "cpu": "cortex-m4", - "mcu": "stm32f303ret6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo F303RE", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 65536, - "maximum_size": 524288 - }, - "url": "http://developer.mbed.org/platforms/ST-Nucleo-F303RE/", - "vendor": "ST" - }, - "nucleo_f334r8": { - "build": { - "f_cpu": "72000000L", - "cpu": "cortex-m4", - "mcu": "stm32f334r8t6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo F334R8", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 65536 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-F334R8/", - "vendor": "ST" - }, - "nucleo_f401re": { - "build": { - "core": "stm32", - "extra_flags": "-DSTM32F4 -DSTM32F401xE -DSTM32F40_41xxx", - "f_cpu": "84000000L", - "ldscript": "stm32f401xe.ld", - "cpu": "cortex-m4", - "mcu": "stm32f401ret6", - "variant": "stm32f401xe" - }, - "frameworks": ["mbed", "cmsis", "spl"], - "name": "ST Nucleo F401RE", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 98304, - "maximum_size": 524288 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-F401RE/", - "vendor": "ST" - }, - "nucleo_f411re": { - "build": { - "f_cpu": "100000000L", - "cpu": "cortex-m4", - "mcu": "stm32f411ret6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo F411RE", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 524288 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-F411RE/", - "vendor": "ST" - }, - "nucleo_f446re": { - "build": { - "f_cpu": "180000000L", - "cpu": "cortex-m4", - "mcu": "stm32f446ret6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo F446RE", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 524288 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-F446RE/", - "vendor": "ST" - }, - "nucleo_l053r8": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0", - "mcu": "stm32l053r8t6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo L053R8", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 65536 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-L053R8/", - "vendor": "ST" - }, - "nucleo_l152re": { - "build": { - "f_cpu": "32000000L", - "cpu": "cortex-m3", - "mcu": "stm32l152ret6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo L152RE", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 81920, - "maximum_size": 524288 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-L152RE/", - "vendor": "ST" - }, - "armstrap_eagle512": { - "build": { - "core": "stm32", - "extra_flags": "-DSTM32F40_41xxx", - "f_cpu": "168000000L", - "ldscript": "armstrap_eagle_512.ld", - "cpu": "cortex-m4", - "mcu": "stm32f407vet6", - "variant": "stm32f4" - }, - "frameworks": ["cmsis", "spl"], - "name": "Armstrap Eagle 512", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 196608, - "maximum_size": 524288 - }, - "url": "http://docs.armstrap.org/en/latest/hardware-overview.html", - "vendor": "Armstrap" - }, - "armstrap_eagle1024": { - "build": { - "core": "stm32", - "extra_flags": "-DSTM32F40_41xxx", - "f_cpu": "168000000L", - "ldscript": "armstrap_eagle_1024.ld", - "cpu": "cortex-m4", - "mcu": "stm32f417vgt6", - "variant": "stm32f4" - }, - "frameworks": ["cmsis", "spl"], - "name": "Armstrap Eagle 1024", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 196608, - "maximum_size": 1048576 - }, - "url": "http://docs.armstrap.org/en/latest/hardware-overview.html", - "vendor": "Armstrap" - }, - "armstrap_eagle2048": { - "build": { - "core": "stm32", - "extra_flags": "-DSTM32F427_437xx", - "f_cpu": "168000000L", - "ldscript": "armstrap_eagle_2048.ld", - "cpu": "cortex-m4", - "mcu": "stm32f427vit6", - "variant": "stm32f4" - }, - "frameworks": ["cmsis", "spl"], - "name": "Armstrap Eagle 2048", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 262144, - "maximum_size": 2091752 - }, - "url": "http://docs.armstrap.org/en/latest/hardware-overview.html", - "vendor": "Armstrap" - }, - "disco_l053c8": { - "build": { - "f_cpu": "32000000L", - "cpu": "cortex-m0plus", - "mcu": "stm32l053c8t6" - }, - "frameworks": ["mbed"], - "name": "ST 32L0538DISCOVERY", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 65536 - }, - "url": "http://www.st.com/web/en/catalog/tools/PF260319", - "vendor": "ST" - }, - "disco_f334c8": { - "build": { - "f_cpu": "72000000L", - "cpu": "cortex-m4", - "mcu": "stm32f334c8t6" - }, - "frameworks": ["mbed"], - "name": "ST 32F3348DISCOVERY", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 12288, - "maximum_size": 65536 - }, - "url": "http://www.st.com/web/en/catalog/tools/PF260318", - "vendor": "ST" - }, - "disco_f469ni": { - "build": { - "f_cpu": "180000000L", - "cpu": "cortex-m4", - "mcu": "stm32f469nih6" - }, - "frameworks": ["mbed"], - "name": "ST 32F469IDISCOVERY", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 393216, - "maximum_size": 1048576 - }, - "url": "http://www.st.com/web/catalog/tools/FM116/CL1620/SC959/SS1532/LN1848/PF262395", - "vendor": "ST" - }, - "disco_l476vg": { - "build": { - "f_cpu": "80000000L", - "cpu": "cortex-m4", - "mcu": "stm32l476vgt6" - }, - "frameworks": ["mbed"], - "name": "ST 32L476GDISCOVERY", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 1048576 - }, - "url": "http://www.st.com/web/catalog/tools/FM116/CL1620/SC959/SS1532/LN1848/PF261635", - "vendor": "ST" - }, - "nucleo_f031k6": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0", - "mcu": "stm32f031k6t6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo F031K6", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 4096, - "maximum_size": 32768 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-F031K6/", - "vendor": "ST" - }, - "nucleo_f042k6": { - "build": { - "f_cpu": "48000000L", - "cpu": "cortex-m0", - "mcu": "stm32f042k6t6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo F042K6", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 6144, - "maximum_size": 32768 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-F042K6/", - "vendor": "ST" - }, - "nucleo_f303k8": { - "build": { - "f_cpu": "72000000L", - "cpu": "cortex-m4", - "mcu": "stm32f303k8t6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo F303K8", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 65536 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-F303K8/", - "vendor": "ST" - }, - "nucleo_l476rg": { - "build": { - "f_cpu": "80000000L", - "cpu": "cortex-m4", - "mcu": "stm32l476rgt6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo L476RG", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 1048576 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-L476RG/", - "vendor": "ST" - }, - "nucleo_f410rb": { - "build": { - "f_cpu": "100000000L", - "cpu": "cortex-m4", - "mcu": "stm32f410rbt6" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo F410RB", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 131072 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-F410RB/", - "vendor": "ST" - }, - "nucleo_l073rz": { - "build": { - "f_cpu": "32000000L", - "cpu": "cortex-m0plus", - "mcu": "stm32l073rz" - }, - "frameworks": ["mbed"], - "name": "ST Nucleo L073RZ", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 20480, - "maximum_size": 196608 - }, - "url": "https://developer.mbed.org/platforms/ST-Nucleo-L073RZ/", - "vendor": "ST" - }, - "seeedArchMax": { - "build": { - "f_cpu": "168000000L", - "cpu": "cortex-m4", - "mcu": "stm32f407vet6" - }, - "frameworks": ["mbed"], - "name": "SeeedStudio Arch Max", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 196608, - "maximum_size": 524288 - }, - "url": "https://developer.mbed.org/platforms/Seeed-Arch-Max/", - "vendor": "SeeedStudio" - }, - "b96b_f446ve": { - "build": { - "f_cpu": "168000000L", - "cpu": "cortex-m4", - "mcu": "stm32f446vet6" - }, - "frameworks": ["mbed"], - "name": "96Boards B96B-F446VE", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 524288 - }, - "url": "https://developer.mbed.org/platforms/ST-B96B-F446VE/", - "vendor": "96Boards" - }, - "mts_mdot_f411re": { - "build": { - "f_cpu": "100000000L", - "cpu": "cortex-m4", - "mcu": "stm32f411ret6" - }, - "frameworks": ["mbed"], - "name": "MultiTech mDot F411", - "platform": "ststm32", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 524288 - }, - "url": "https://developer.mbed.org/platforms/MTS-mDot-F411/", - "vendor": "MultiTech" - } -} diff --git a/platformio/boards/teensy.json b/platformio/boards/teensy.json deleted file mode 100644 index dd4816ae..00000000 --- a/platformio/boards/teensy.json +++ /dev/null @@ -1,95 +0,0 @@ -{ - "teensy20": { - "build": { - "core": "teensy", - "f_cpu": "16000000L", - "mcu": "atmega32u4" - }, - "frameworks": ["arduino"], - "name": "Teensy 2.0", - "platform": "teensy", - "upload": { - "maximum_ram_size": 2560, - "maximum_size": 32256 - }, - "url": "https://www.pjrc.com/store/teensy.html", - "vendor": "Teensy" - }, - - "teensy20pp": { - "build": { - "core": "teensy", - "f_cpu": "16000000L", - "mcu": "at90usb1286" - }, - "frameworks": ["arduino"], - "name": "Teensy++ 2.0", - "platform": "teensy", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 130048 - }, - "url": "https://www.pjrc.com/store/teensypp.html", - "vendor": "Teensy" - }, - - "teensy30": { - "build": { - "core": "teensy3", - "extra_flags": "-D__MK20DX128__", - "f_cpu": "48000000L", - "ldscript": "mk20dx128.ld", - "mcu": "mk20dx128", - "cpu": "cortex-m4" - }, - "frameworks": ["arduino"], - "name": "Teensy 3.0", - "platform": "teensy", - "upload": { - "maximum_ram_size": 16384, - "maximum_size": 131072 - }, - "url": "https://www.pjrc.com/store/teensy3.html", - "vendor": "Teensy" - }, - - "teensy31": { - "build": { - "core": "teensy3", - "extra_flags": "-D__MK20DX256__", - "f_cpu": "72000000L", - "ldscript": "mk20dx256.ld", - "mcu": "mk20dx256", - "cpu": "cortex-m4" - }, - "frameworks": ["arduino", "mbed"], - "name": "Teensy 3.1 / 3.2", - "platform": "teensy", - "upload": { - "maximum_ram_size": 65536, - "maximum_size": 262144 - }, - "url": "https://www.pjrc.com/store/teensy31.html", - "vendor": "Teensy" - }, - - "teensylc": { - "build": { - "core": "teensy3", - "extra_flags": "-D__MKL26Z64__", - "f_cpu": "48000000L", - "ldscript": "mkl26z64.ld", - "mcu": "mkl26z64", - "cpu": "cortex-m0plus" - }, - "frameworks": ["arduino"], - "name": "Teensy LC", - "platform": "teensy", - "upload": { - "maximum_ram_size": 8192, - "maximum_size": 63488 - }, - "url": "http://www.pjrc.com/teensy/teensyLC.html", - "vendor": "Teensy" - } -} diff --git a/platformio/boards/timsp430.json b/platformio/boards/timsp430.json deleted file mode 100644 index ca46ffad..00000000 --- a/platformio/boards/timsp430.json +++ /dev/null @@ -1,164 +0,0 @@ -{ - "lpmsp430f5529": { - "build": { - "core": "msp430", - "f_cpu": "16000000L", - "mcu": "msp430f5529", - "variant": "launchpad_f5529" - }, - "frameworks": ["energia"], - "name": "TI LaunchPad w/ msp430f5529 (16MHz)", - "platform": "timsp430", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 131072, - "protocol": "tilib" - }, - "url": "http://www.ti.com/ww/en/launchpad/launchpads-msp430-msp-exp430f5529lp.html", - "vendor": "TI" - }, - "lpmsp430f5529_25": { - "build": { - "core": "msp430", - "f_cpu": "25000000L", - "mcu": "msp430f5529", - "variant": "launchpad_f5529" - }, - "frameworks": ["energia"], - "name": "TI LaunchPad w/ msp430f5529 (25MHz)", - "platform": "timsp430", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 131072, - "protocol": "tilib" - }, - "url": "http://www.ti.com/ww/en/launchpad/launchpads-msp430-msp-exp430f5529lp.html", - "vendor": "TI" - }, - "lpmsp430fr5739": { - "build": { - "core": "msp430", - "f_cpu": "16000000L", - "mcu": "msp430fr5739", - "variant": "fraunchpad" - }, - "frameworks": ["energia"], - "name": "TI FraunchPad w/ msp430fr5739", - "platform": "timsp430", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 15872, - "protocol": "rf2500" - }, - "url": "http://www.ti.com/tool/msp-exp430fr5739", - "vendor": "TI" - }, - "lpmsp430fr5969": { - "build": { - "core": "msp430", - "f_cpu": "8000000L", - "mcu": "msp430fr5969", - "variant": "launchpad_fr5969" - }, - "frameworks": ["energia"], - "name": "TI LaunchPad w/ msp430fr5969", - "platform": "timsp430", - "upload": { - "maximum_ram_size": 1024, - "maximum_size": 65536, - "protocol": "tilib" - }, - "url": "http://www.ti.com/ww/en/launchpad/launchpads-msp430-msp-exp430fr5969.html", - "vendor": "TI" - }, - "lpmsp430g2231": { - "build": { - "core": "msp430", - "f_cpu": "1000000L", - "mcu": "msp430g2231", - "variant": "launchpad" - }, - "frameworks": ["energia"], - "name": "TI LaunchPad w/ msp430g2231 (1 MHz)", - "platform": "timsp430", - "upload": { - "maximum_ram_size": 128, - "maximum_size": 2048, - "protocol": "rf2500" - }, - "url": "http://www.ti.com/ww/en/launchpad/launchpads-msp430-msp-exp430g2.html", - "vendor": "TI" - }, - "lpmsp430g2452": { - "build": { - "core": "msp430", - "f_cpu": "16000000L", - "mcu": "msp430g2452", - "variant": "launchpad" - }, - "frameworks": ["energia"], - "name": "TI LaunchPad w/ msp430g2452 (16MHz)", - "platform": "timsp430", - "upload": { - "maximum_ram_size": 256, - "maximum_size": 8192, - "protocol": "rf2500" - }, - "url": "http://www.ti.com/ww/en/launchpad/launchpads-msp430-msp-exp430g2.html", - "vendor": "TI" - }, - "lpmsp430g2553": { - "build": { - "core": "msp430", - "f_cpu": "16000000L", - "mcu": "msp430g2553", - "variant": "launchpad" - }, - "frameworks": ["energia"], - "name": "TI LaunchPad w/ msp430g2553 (16MHz)", - "platform": "timsp430", - "upload": { - "maximum_ram_size": 512, - "maximum_size": 16384, - "protocol": "rf2500" - }, - "url": "http://www.ti.com/ww/en/launchpad/launchpads-msp430-msp-exp430g2.html", - "vendor": "TI" - }, - "lpmsp430fr4133": { - "build": { - "core": "msp430", - "f_cpu": "16000000L", - "mcu": "msp430g2553", - "variant": "launchpad_fr4133" - }, - "frameworks": ["energia"], - "name": "TI LaunchPad w/ msp430fr4133", - "platform": "timsp430", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 15360, - "protocol": "tilib" - }, - "url": "http://www.ti.com/tool/msp-exp430fr4133", - "vendor": "TI" - }, - "lpmsp430fr6989": { - "build": { - "core": "msp430", - "f_cpu": "16000000L", - "mcu": "msp430g2553", - "variant": "launchpad_fr6989" - }, - "frameworks": ["energia"], - "name": "TI LaunchPad w/ msp430fr6989", - "platform": "timsp430", - "upload": { - "maximum_ram_size": 2048, - "maximum_size": 130048, - "protocol": "tilib" - }, - "url": "http://www.ti.com/tool/msp-exp430fr6989", - "vendor": "TI" - } -} diff --git a/platformio/boards/titiva.json b/platformio/boards/titiva.json deleted file mode 100644 index 29b7944f..00000000 --- a/platformio/boards/titiva.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "lplm4f120h5qr": { - "build": { - "core": "lm4f", - "f_cpu": "80000000L", - "ldscript": "lm4fcpp_blizzard.ld", - "cpu": "cortex-m4", - "mcu": "lplm4f120h5qr", - "variant": "stellarpad" - }, - "frameworks": ["energia", "libopencm3"], - "name": "TI LaunchPad (Stellaris) w/ lm4f120 (80MHz)", - "platform": "titiva", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 262144 - }, - "url": "http://www.ti.com/tool/ek-lm4f120xl", - "vendor": "TI" - }, - "lptm4c1230c3pm": { - "build": { - "core": "lm4f", - "f_cpu": "80000000L", - "ldscript": "lm4fcpp_blizzard.ld", - "cpu": "cortex-m4", - "mcu": "lptm4c1230c3pm", - "variant": "stellarpad" - }, - "frameworks": ["energia", "libopencm3"], - "name": "TI LaunchPad (Tiva C) w/ tm4c123 (80MHz)", - "platform": "titiva", - "upload": { - "maximum_ram_size": 32768, - "maximum_size": 262144 - }, - "url": "http://www.ti.com/ww/en/launchpad/launchpads-connected-ek-tm4c123gxl.html", - "vendor": "TI" - }, - "lptm4c1294ncpdt": { - "build": { - "core": "lm4f", - "f_cpu": "120000000L", - "ldscript": "lm4fcpp_snowflake.ld", - "cpu": "cortex-m4", - "mcu": "lptm4c1294ncpdt", - "variant": "launchpad_129" - }, - "frameworks": ["energia", "libopencm3"], - "name": "TI LaunchPad (Tiva C) w/ tm4c129 (120MHz)", - "platform": "titiva", - "upload": { - "maximum_ram_size": 262144, - "maximum_size": 1048576 - }, - "url": "http://www.ti.com/ww/en/launchpad/launchpads-connected-ek-tm4c1294xl.html", - "vendor": "TI" - } -} \ No newline at end of file diff --git a/platformio/builder/scripts/__init__.py b/platformio/builder/scripts/__init__.py deleted file mode 100644 index 0c05c3b0..00000000 --- a/platformio/builder/scripts/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. diff --git a/platformio/builder/scripts/atmelavr.py b/platformio/builder/scripts/atmelavr.py deleted file mode 100644 index daff63af..00000000 --- a/platformio/builder/scripts/atmelavr.py +++ /dev/null @@ -1,168 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for Atmel AVR series of microcontrollers -""" - -from os.path import join -from time import sleep - -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Default, - DefaultEnvironment, SConscript) - -from platformio.util import get_serialports - - -def BeforeUpload(target, source, env): # pylint: disable=W0613,W0621 - - if "program" in COMMAND_LINE_TARGETS: - return - - if "micronucleus" in env['UPLOADER']: - print "Please unplug/plug device ..." - - upload_options = env.get("BOARD_OPTIONS", {}).get("upload", {}) - - # Deprecated: compatibility with old projects. Use `program` instead - if "usb" in env.subst("$UPLOAD_PROTOCOL"): - upload_options['require_upload_port'] = False - env.Replace(UPLOAD_SPEED=None) - - if env.subst("$UPLOAD_SPEED"): - env.Append(UPLOADERFLAGS=["-b", "$UPLOAD_SPEED"]) - - if upload_options and not upload_options.get("require_upload_port", False): - return - - env.AutodetectUploadPort() - env.Append(UPLOADERFLAGS=["-P", '"$UPLOAD_PORT"']) - - if env.subst("$BOARD") == "raspduino": - - def _rpi_sysgpio(path, value): - with open(path, "w") as f: - f.write(str(value)) - - _rpi_sysgpio("/sys/class/gpio/export", 18) - _rpi_sysgpio("/sys/class/gpio/gpio18/direction", "out") - _rpi_sysgpio("/sys/class/gpio/gpio18/value", 1) - sleep(0.1) - _rpi_sysgpio("/sys/class/gpio/gpio18/value", 0) - _rpi_sysgpio("/sys/class/gpio/unexport", 18) - else: - if not upload_options.get("disable_flushing", False): - env.FlushSerialBuffer("$UPLOAD_PORT") - - before_ports = [i['port'] for i in get_serialports()] - - if upload_options.get("use_1200bps_touch", False): - env.TouchSerialPort("$UPLOAD_PORT", 1200) - - if upload_options.get("wait_for_upload_port", False): - env.Replace(UPLOAD_PORT=env.WaitForNewSerialPort(before_ports)) - - -env = DefaultEnvironment() - -SConscript(env.subst(join("$PIOBUILDER_DIR", "scripts", "baseavr.py"))) - -env.Append( - CFLAGS=[ - "-std=gnu11" - ], - - CXXFLAGS=[ - "-std=gnu++11" - ] -) - -if "digispark" in env.get( - "BOARD_OPTIONS", {}).get("build", {}).get("core", ""): - env.Replace( - UPLOADER=join("$PIOPACKAGES_DIR", "tool-micronucleus", "micronucleus"), - UPLOADERFLAGS=[ - "-c", "$UPLOAD_PROTOCOL", - "--timeout", "60" - ], - UPLOADHEXCMD='"$UPLOADER" $UPLOADERFLAGS $SOURCES' - ) - -else: - env.Replace( - UPLOADER=join("$PIOPACKAGES_DIR", "tool-avrdude", "avrdude"), - UPLOADERFLAGS=[ - "-v", - "-p", "$BOARD_MCU", - "-C", - '"%s"' % join("$PIOPACKAGES_DIR", "tool-avrdude", "avrdude.conf"), - "-c", "$UPLOAD_PROTOCOL" - ], - UPLOADHEXCMD='"$UPLOADER" $UPLOADERFLAGS -D -U flash:w:$SOURCES:i', - UPLOADEEPCMD='"$UPLOADER" $UPLOADERFLAGS -U eeprom:w:$SOURCES:i', - PROGRAMHEXCMD='"$UPLOADER" $UPLOADERFLAGS -U flash:w:$SOURCES:i' - ) - -# -# Target: Build executable and linkable firmware -# - -target_elf = env.BuildProgram() - -# -# Target: Build the .hex file -# - -if "uploadlazy" in COMMAND_LINE_TARGETS: - target_firm = join("$BUILD_DIR", "firmware.hex") -else: - target_firm = env.ElfToHex(join("$BUILD_DIR", "firmware"), target_elf) - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_elf, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Upload by default .hex file -# - -upload = env.Alias(["upload", "uploadlazy"], target_firm, - [BeforeUpload, "$UPLOADHEXCMD"]) -AlwaysBuild(upload) - -# -# Target: Upload EEPROM data (from EEMEM directive) -# - -uploadeep = env.Alias( - "uploadeep", - env.ElfToEep(join("$BUILD_DIR", "firmware"), target_elf), - [BeforeUpload, "$UPLOADEEPCMD"]) -AlwaysBuild(uploadeep) - -# -# Target: Upload firmware using external programmer -# - -program = env.Alias("program", target_firm, [BeforeUpload, "$PROGRAMHEXCMD"]) -AlwaysBuild(program) - -# -# Setup default targets -# - -Default([target_firm, target_size]) diff --git a/platformio/builder/scripts/atmelsam.py b/platformio/builder/scripts/atmelsam.py deleted file mode 100644 index d91b0bf0..00000000 --- a/platformio/builder/scripts/atmelsam.py +++ /dev/null @@ -1,189 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for Atmel SAM series of microcontrollers -""" - -from os.path import basename, join - -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Default, - DefaultEnvironment, SConscript) - -from platformio.util import get_serialports - - -def BeforeUpload(target, source, env): # pylint: disable=W0613,W0621 - env.AutodetectUploadPort() - - board_type = env.subst("$BOARD") - if "zero" not in board_type: - env.Append( - UPLOADERFLAGS=[ - "-U", - "true" if ("usb" in board_type.lower( - ) or board_type == "digix") else "false" - ]) - - upload_options = env.get("BOARD_OPTIONS", {}).get("upload", {}) - - if not upload_options.get("disable_flushing", False): - env.FlushSerialBuffer("$UPLOAD_PORT") - - before_ports = [i['port'] for i in get_serialports()] - - if upload_options.get("use_1200bps_touch", False): - env.TouchSerialPort("$UPLOAD_PORT", 1200) - - if upload_options.get("wait_for_upload_port", False): - env.Replace(UPLOAD_PORT=env.WaitForNewSerialPort(before_ports)) - - # use only port name for BOSSA - if "/" in env.subst("$UPLOAD_PORT"): - env.Replace(UPLOAD_PORT=basename(env.subst("$UPLOAD_PORT"))) - - -env = DefaultEnvironment() - -SConscript(env.subst(join("$PIOBUILDER_DIR", "scripts", "basearm.py"))) - -if env.subst("$BOARD") == "zero": - env.Replace( - UPLOADER=join("$PIOPACKAGES_DIR", "tool-openocd", "bin", "openocd"), - UPLOADERFLAGS=[ - "-d2", - "-s", - join( - "$PIOPACKAGES_DIR", - "tool-openocd", "share", "openocd", "scripts"), - "-f", - join( - "$PLATFORMFW_DIR", "variants", - "${BOARD_OPTIONS['build']['variant']}", "openocd_scripts", - "${BOARD_OPTIONS['build']['variant']}.cfg" - ), - "-c", "\"telnet_port", "disabled;", - "program", "{{$SOURCES}}", - "verify", "reset", "0x00002000;", "shutdown\"" - ], - UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS' - ) -else: - env.Replace( - UPLOADER=join("$PIOPACKAGES_DIR", "$PIOPACKAGE_UPLOADER", "bossac"), - UPLOADERFLAGS=[ - "--info", - "--port", '"$UPLOAD_PORT"', - "--erase", - "--write", - "--verify", - "--reset", - "--debug" - ], - UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS $SOURCES' - ) - -env.Append( - - CCFLAGS=[ - "--param", "max-inline-insns-single=500", - "-MMD" - ], - - CFLAGS=[ - "-std=gnu11" - ], - - CXXFLAGS=[ - "-std=gnu++11", - "-fno-threadsafe-statics" - ], - - CPPDEFINES=[ - "USBCON", - 'USB_MANUFACTURER="PlatformIO"' - ], - - LINKFLAGS=[ - "-Wl,--check-sections", - "-Wl,--unresolved-symbols=report-all", - "-Wl,--warn-common", - "-Wl,--warn-section-align" - ] -) - - -if "sam3x8e" in env.get("BOARD_OPTIONS", {}).get("build", {}).get("mcu", None): - env.Append( - CPPDEFINES=[ - "printf=iprintf" - ], - - LINKFLAGS=[ - "-Wl,--entry=Reset_Handler", - "-Wl,--start-group" - ], - - UPLOADERFLAGS=[ - "--boot", - ] - - ) -elif "zero" in env.subst("$BOARD"): - env.Append( - LINKFLAGS=[ - "--specs=nosys.specs", - "--specs=nano.specs" - ] - ) - -# -# Target: Build executable and linkable firmware -# - -target_elf = env.BuildProgram() - -# -# Target: Build the .bin file -# - -if "uploadlazy" in COMMAND_LINE_TARGETS: - target_firm = join("$BUILD_DIR", "firmware.bin") -else: - target_firm = env.ElfToBin(join("$BUILD_DIR", "firmware"), target_elf) - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_elf, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Upload by default .bin file -# - -if env.subst("$BOARD") == "zero": - upload = env.Alias(["upload", "uploadlazy"], target_firm, "$UPLOADCMD") -else: - upload = env.Alias(["upload", "uploadlazy"], target_firm, - [BeforeUpload, "$UPLOADCMD"]) - -AlwaysBuild(upload) - -# -# Setup default targets -# - -Default([target_firm, target_size]) diff --git a/platformio/builder/scripts/basearm.py b/platformio/builder/scripts/basearm.py deleted file mode 100644 index 20892b18..00000000 --- a/platformio/builder/scripts/basearm.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Base for ARM microcontrollers. -""" - -from SCons.Script import Builder, DefaultEnvironment - -env = DefaultEnvironment() - -env.Replace( - AR="arm-none-eabi-ar", - AS="arm-none-eabi-as", - CC="arm-none-eabi-gcc", - CXX="arm-none-eabi-g++", - OBJCOPY="arm-none-eabi-objcopy", - RANLIB="arm-none-eabi-ranlib", - SIZETOOL="arm-none-eabi-size", - - ARFLAGS=["rcs"], - - ASFLAGS=["-x", "assembler-with-cpp"], - - CCFLAGS=[ - "-g", # include debugging info (so errors include line numbers) - "-Os", # optimize for size - "-ffunction-sections", # place each function in its own section - "-fdata-sections", - "-Wall", - "-mthumb", - "-mcpu=${BOARD_OPTIONS['build']['cpu']}", - "-nostdlib" - ], - - CXXFLAGS=[ - "-fno-rtti", - "-fno-exceptions" - ], - - CPPDEFINES=[ - "F_CPU=$BOARD_F_CPU" - ], - - LINKFLAGS=[ - "-Os", - "-Wl,--gc-sections,--relax", - "-mthumb", - "-mcpu=${BOARD_OPTIONS['build']['cpu']}" - ], - - LIBS=["c", "gcc", "m"], - - SIZEPRINTCMD='"$SIZETOOL" -B -d $SOURCES', - - PROGNAME="firmware", - PROGSUFFIX=".elf" -) - - -env.Append( - ASFLAGS=env.get("CCFLAGS", [])[:], - - BUILDERS=dict( - ElfToBin=Builder( - action=" ".join([ - "$OBJCOPY", - "-O", - "binary", - "$SOURCES", - "$TARGET"]), - suffix=".bin" - ), - ElfToHex=Builder( - action=" ".join([ - "$OBJCOPY", - "-O", - "ihex", - "-R", - ".eeprom", - "$SOURCES", - "$TARGET"]), - suffix=".hex" - ) - ) -) diff --git a/platformio/builder/scripts/baseavr.py b/platformio/builder/scripts/baseavr.py deleted file mode 100644 index 055fb742..00000000 --- a/platformio/builder/scripts/baseavr.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Base for Atmel AVR series of microcontrollers -""" - -from SCons.Script import Builder, DefaultEnvironment - -env = DefaultEnvironment() - -env.Replace( - AR="avr-ar", - AS="avr-as", - CC="avr-gcc", - CXX="avr-g++", - OBJCOPY="avr-objcopy", - RANLIB="avr-ranlib", - SIZETOOL="avr-size", - - ARFLAGS=["rcs"], - - ASFLAGS=["-x", "assembler-with-cpp"], - - CCFLAGS=[ - "-g", # include debugging info (so errors include line numbers) - "-Os", # optimize for size - "-Wall", # show warnings - "-ffunction-sections", # place each function in its own section - "-fdata-sections", - "-mmcu=$BOARD_MCU" - ], - - CXXFLAGS=[ - "-fno-exceptions", - "-fno-threadsafe-statics" - ], - - CPPDEFINES=["F_CPU=$BOARD_F_CPU"], - - LINKFLAGS=[ - "-Os", - "-mmcu=$BOARD_MCU", - "-Wl,--gc-sections,--relax" - ], - - LIBS=["m"], - - SIZEPRINTCMD='"$SIZETOOL" --mcu=$BOARD_MCU -C -d $SOURCES', - - PROGNAME="firmware", - PROGSUFFIX=".elf" -) - -env.Append( - ASFLAGS=env.get("CCFLAGS", [])[:], - - BUILDERS=dict( - ElfToEep=Builder( - action=" ".join([ - "$OBJCOPY", - "-O", - "ihex", - "-j", - ".eeprom", - '--set-section-flags=.eeprom="alloc,load"', - "--no-change-warnings", - "--change-section-lma", - ".eeprom=0", - "$SOURCES", - "$TARGET"]), - suffix=".eep" - ), - - ElfToHex=Builder( - action=" ".join([ - "$OBJCOPY", - "-O", - "ihex", - "-R", - ".eeprom", - "$SOURCES", - "$TARGET"]), - suffix=".hex" - ) - ) -) diff --git a/platformio/builder/scripts/espressif.py b/platformio/builder/scripts/espressif.py deleted file mode 100644 index 8f74ca71..00000000 --- a/platformio/builder/scripts/espressif.py +++ /dev/null @@ -1,357 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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=redefined-outer-name - -""" - Builder for Espressif MCUs -""" - -import re -from os.path import join - -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Builder, Default, - DefaultEnvironment) - - -def _get_flash_size(env): - # use board's flash size by default - board_max_size = int( - env.get("BOARD_OPTIONS", {}).get("upload", {}).get("maximum_size", 0)) - - # check if user overrides LD Script - match = re.search(r"\.flash\.(\d+)(m|k).*\.ld", env.GetActualLDScript()) - if match: - if match.group(2) == "k": - board_max_size = int(match.group(1)) * 1024 - elif match.group(2) == "m": - board_max_size = int(match.group(1)) * 1024 * 1024 - - return ("%dK" % (board_max_size / 1024) if board_max_size < 1048576 - else "%dM" % (board_max_size / 1048576)) - - -def _get_board_f_flash(env): - frequency = env.subst("$BOARD_F_FLASH") - frequency = str(frequency).replace("L", "") - return int(int(frequency) / 1000000) - - -env = DefaultEnvironment() - -env.Replace( - __get_flash_size=_get_flash_size, - __get_board_f_flash=_get_board_f_flash, - - AR="xtensa-lx106-elf-ar", - AS="xtensa-lx106-elf-as", - CC="xtensa-lx106-elf-gcc", - CXX="xtensa-lx106-elf-g++", - OBJCOPY=join("$PIOPACKAGES_DIR", "tool-esptool", "esptool"), - RANLIB="xtensa-lx106-elf-ranlib", - SIZETOOL="xtensa-lx106-elf-size", - - ARFLAGS=["rcs"], - - ASFLAGS=["-x", "assembler-with-cpp"], - - CFLAGS=[ - "-std=gnu99", - "-Wpointer-arith", - "-Wno-implicit-function-declaration", - "-Wl,-EL", - "-fno-inline-functions", - "-nostdlib" - ], - - CCFLAGS=[ - "-Os", # optimize for size - "-mlongcalls", - "-mtext-section-literals", - "-falign-functions=4", - "-U__STRICT_ANSI__", - "-ffunction-sections", - "-fdata-sections", - "-MMD" # output dependancy info - ], - - CXXFLAGS=[ - "-fno-rtti", - "-fno-exceptions", - "-std=c++11" - ], - - CPPDEFINES=[ - "F_CPU=$BOARD_F_CPU", - "__ets__", - "ICACHE_FLASH" - ], - - LINKFLAGS=[ - "-Os", - "-nostdlib", - "-Wl,--no-check-sections", - "-u", "call_user_start", - "-Wl,-static", - "-Wl,--gc-sections" - ], - - # - # Upload - # - - UPLOADER=join("$PIOPACKAGES_DIR", "tool-esptool", "esptool"), - UPLOADEROTA=join("$PLATFORMFW_DIR", "tools", "espota.py"), - - UPLOADERFLAGS=[ - "-vv", - "-cd", "$UPLOAD_RESETMETHOD", - "-cb", "$UPLOAD_SPEED", - "-cp", '"$UPLOAD_PORT"' - ], - UPLOADEROTAFLAGS=[ - "--debug", - "--progress", - "-i", "$UPLOAD_PORT", - "$UPLOAD_FLAGS" - ], - - UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS -cf $SOURCE', - UPLOADOTACMD='"$PYTHONEXE" "$UPLOADEROTA" $UPLOADEROTAFLAGS -f $SOURCE', - - # - # Misc - # - - MKSPIFFSTOOL=join("$PIOPACKAGES_DIR", "tool-mkspiffs", "mkspiffs"), - SIZEPRINTCMD='"$SIZETOOL" -B -d $SOURCES', - - PROGNAME="firmware", - PROGSUFFIX=".elf" -) - -env.Append( - ASFLAGS=env.get("CCFLAGS", [])[:], - - BUILDERS=dict( - ElfToBin=Builder( - action=" ".join([ - '"$OBJCOPY"', - "-eo", - '"%s"' % join("$PLATFORMFW_DIR", "bootloaders", - "eboot", "eboot.elf"), - "-bo", "$TARGET", - "-bm", "$BOARD_FLASH_MODE", - "-bf", "${__get_board_f_flash(__env__)}", - "-bz", "${__get_flash_size(__env__)}", - "-bs", ".text", - "-bp", "4096", - "-ec", - "-eo", "$SOURCES", - "-bs", ".irom0.text", - "-bs", ".text", - "-bs", ".data", - "-bs", ".rodata", - "-bc", "-ec" - ]), - suffix=".bin" - ) - ) -) - - -# -# SPIFFS -# - -def _fetch_spiffs_size(target, source, env): - spiffs_re = re.compile( - r"PROVIDE\s*\(\s*_SPIFFS_(\w+)\s*=\s*(0x[\dA-F]+)\s*\)") - with open(env.GetActualLDScript()) as f: - for line in f.readlines(): - match = spiffs_re.search(line) - if not match: - continue - env["SPIFFS_%s" % match.group(1).upper()] = match.group(2) - - assert all([k in env for k in ["SPIFFS_START", "SPIFFS_END", "SPIFFS_PAGE", - "SPIFFS_BLOCK"]]) - - # esptool flash starts from 0 - for k in ("SPIFFS_START", "SPIFFS_END"): - _value = 0 - if int(env[k], 16) < 0x40300000: - _value = int(env[k], 16) & 0xFFFFF - else: - _value = int(env[k], 16) & 0xFFFFFF - _value -= 0x200000 # esptool offset - - env[k] = hex(_value) - - return (target, source) - - -env.Append( - BUILDERS=dict( - DataToBin=Builder( - action=" ".join([ - '"$MKSPIFFSTOOL"', - "-c", "$SOURCES", - "-p", "${int(SPIFFS_PAGE, 16)}", - "-b", "${int(SPIFFS_BLOCK, 16)}", - "-s", "${int(SPIFFS_END, 16) - int(SPIFFS_START, 16)}", - "$TARGET" - ]), - emitter=_fetch_spiffs_size, - source_factory=env.Dir, - suffix=".bin" - ) - ) -) - -if "uploadfs" in COMMAND_LINE_TARGETS: - env.Append( - UPLOADERFLAGS=["-ca", "$SPIFFS_START"], - UPLOADEROTAFLAGS=["-s"] - ) - -# -# Framework and SDK specific configuration -# - -if "FRAMEWORK" in env: - env.Append( - LINKFLAGS=[ - "-Wl,-wrap,system_restart_local", - "-Wl,-wrap,register_chipv6_phy" - ] - ) - - # Handle uploading via OTA - ota_port = None - if env.get("UPLOAD_PORT"): - ota_port = re.match( - r"\"?((([0-9]{1,3}\.){3}[0-9]{1,3})|.+\.local)\"?$", - env.get("UPLOAD_PORT")) - if ota_port: - env.Replace(UPLOADCMD="$UPLOADOTACMD") - -# Configure native SDK -else: - env.Append( - CPPPATH=[ - join("$PIOPACKAGES_DIR", "sdk-esp8266", "include"), - "$PROJECTSRC_DIR" - ], - - LIBPATH=[ - join("$PIOPACKAGES_DIR", "sdk-esp8266", "lib"), - join("$PIOPACKAGES_DIR", "sdk-esp8266", "ld") - ], - - BUILDERS=dict( - ElfToBin=Builder( - action=" ".join([ - '"$OBJCOPY"', - "-eo", "$SOURCES", - "-bo", "${TARGETS[0]}", - "-bm", "$BOARD_FLASH_MODE", - "-bf", "${__get_board_f_flash(__env__)}", - "-bz", "${__get_flash_size(__env__)}", - "-bs", ".text", - "-bs", ".data", - "-bs", ".rodata", - "-bc", "-ec", - "-eo", "$SOURCES", - "-es", ".irom0.text", "${TARGETS[1]}", - "-ec", "-v" - ]), - suffix=".bin" - ) - ) - ) - env.Replace( - LIBS=[ - "c", "gcc", "phy", "pp", "net80211", "lwip", "wpa", "wpa2", - "main", "wps", "crypto", "json", "ssl", "pwm", "upgrade", - "smartconfig", "airkiss", "at" - ], - - UPLOADERFLAGS=[ - "-vv", - "-cd", "$UPLOAD_RESETMETHOD", - "-cb", "$UPLOAD_SPEED", - "-cp", '"$UPLOAD_PORT"', - "-ca", "0x00000", - "-cf", "${SOURCES[0]}", - "-ca", "0x40000", - "-cf", "${SOURCES[1]}" - ], - - UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS', - ) - -# -# Target: Build executable and linkable firmware -# - -target_elf = env.BuildProgram() - -# -# Target: Build the .hex or SPIFFS image -# - -if set(["uploadfs", "uploadfsota"]) & set(COMMAND_LINE_TARGETS): - target_firm = env.DataToBin( - join("$BUILD_DIR", "spiffs"), "$PROJECTDATA_DIR") - AlwaysBuild(target_firm) - -elif "uploadlazy" in COMMAND_LINE_TARGETS: - if "FRAMEWORK" not in env: - target_firm = [ - join("$BUILD_DIR", "firmware_00000.bin"), - join("$BUILD_DIR", "firmware_40000.bin") - ] - else: - target_firm = join("$BUILD_DIR", "firmware.bin") -else: - if "FRAMEWORK" not in env: - target_firm = env.ElfToBin( - [join("$BUILD_DIR", "firmware_00000"), - join("$BUILD_DIR", "firmware_40000")], target_elf) - else: - target_firm = env.ElfToBin(join("$BUILD_DIR", "firmware"), target_elf) - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_elf, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Upload firmware or SPIFFS image -# - -target_upload = env.Alias( - ["upload", "uploadlazy", "uploadfs"], target_firm, - [lambda target, source, env: env.AutodetectUploadPort(), "$UPLOADCMD"]) -env.AlwaysBuild(target_upload) - - -# -# Target: Define targets -# - -Default([target_firm, target_size]) diff --git a/platformio/builder/scripts/frameworks/__init__.py b/platformio/builder/scripts/frameworks/__init__.py deleted file mode 100644 index 0c05c3b0..00000000 --- a/platformio/builder/scripts/frameworks/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. diff --git a/platformio/builder/scripts/frameworks/arduino.py b/platformio/builder/scripts/frameworks/arduino.py deleted file mode 100644 index d3170687..00000000 --- a/platformio/builder/scripts/frameworks/arduino.py +++ /dev/null @@ -1,339 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" -Arduino - -Arduino Wiring-based Framework allows writing cross-platform software to -control devices attached to a wide range of Arduino boards to create all -kinds of creative coding, interactive objects, spaces or physical experiences. - -http://arduino.cc/en/Reference/HomePage -""" - -from os import listdir, walk -from os.path import isdir, isfile, join - -from SCons.Script import DefaultEnvironment - -env = DefaultEnvironment() - -BOARD_OPTS = env.get("BOARD_OPTIONS", {}) -BOARD_BUILDOPTS = BOARD_OPTS.get("build", {}) -BOARD_CORELIBDIRNAME = BOARD_BUILDOPTS.get("core") - -# -# Determine framework directory -# based on development platform -# - -PLATFORMFW_DIR = join("$PIOPACKAGES_DIR", - "framework-arduino${PLATFORM.replace('atmel', '')}") - -if "digispark" in BOARD_BUILDOPTS.get("core"): - BOARD_CORELIBDIRNAME = "digispark" - PLATFORMFW_DIR = join( - "$PIOPACKAGES_DIR", - "framework-arduino%s" % ( - "sam" if BOARD_BUILDOPTS.get("cpu") == "cortex-m3" else "avr") - ) -elif env.get("PLATFORM") == "timsp430": - PLATFORMFW_DIR = join( - "$PIOPACKAGES_DIR", - "framework-arduinomsp430" - ) -elif env.get("PLATFORM") == "espressif": - env.Prepend( - CPPPATH=[ - join("$PLATFORMFW_DIR", "tools", "sdk", "include"), - join("$PLATFORMFW_DIR", "tools", "sdk", "lwip", "include") - ], - LIBPATH=[join("$PLATFORMFW_DIR", "tools", "sdk", "lib")], - LIBS=["mesh", "wpa2", "smartconfig", "pp", "main", "wpa", "lwip", - "net80211", "wps", "crypto", "phy", "hal", "axtls", "gcc", "m"] - ) - env.VariantDirWrap( - join("$BUILD_DIR", "generic"), - join("$PIOPACKAGES_DIR", "framework-arduinoespressif", - "variants", "generic") - ) - -elif env.get("PLATFORM") == "nordicnrf51": - PLATFORMFW_DIR = join( - "$PIOPACKAGES_DIR", - "framework-arduinonordicnrf51" - ) - env.Prepend( - CPPPATH=[ - join("$PLATFORMFW_DIR", "system", "CMSIS", "CMSIS", "Include"), - join("$PLATFORMFW_DIR", "system", "RFduino"), - join("$PLATFORMFW_DIR", "system", "RFduino", "include") - ], - LIBPATH=[ - join( - "$PLATFORMFW_DIR", - "variants", - "${BOARD_OPTIONS['build']['variant']}" - ), - join( - "$PLATFORMFW_DIR", - "variants", - "${BOARD_OPTIONS['build']['variant']}", - "linker_scripts", - "gcc" - ), - ], - LIBS=["RFduino", "RFduinoBLE", "RFduinoGZLL", "RFduinoSystem"] - ) - -elif env.get("PLATFORM") == "microchippic32": - PLATFORMFW_DIR = join( - "$PIOPACKAGES_DIR", - "framework-arduinomicrochippic32" - ) - env.Prepend( - LIBPATH=[ - join( - "$PLATFORMFW_DIR", "cores", - "${BOARD_OPTIONS['build']['core']}" - ), - join( - "$PLATFORMFW_DIR", "variants", - "${BOARD_OPTIONS['build']['variant']}" - ) - ] - ) - -elif "intel" in env.get("PLATFORM"): - PLATFORMFW_DIR = join( - "$PIOPACKAGES_DIR", - "framework-arduinointel" - ) - - if BOARD_CORELIBDIRNAME == "arc32": - env.Prepend( - CPPPATH=[ - join("$PLATFORMFW_DIR", "system", - "libarc32_arduino101", "drivers"), - join("$PLATFORMFW_DIR", "system", - "libarc32_arduino101", "common"), - join("$PLATFORMFW_DIR", "system", - "libarc32_arduino101", "framework", "include"), - join("$PLATFORMFW_DIR", "system", - "libarc32_arduino101", "bootcode"), - join("$BUILD_DIR", "IntelDrivers") - ] - ) - - env.Prepend( - LIBPATH=[ - join( - "$PLATFORMFW_DIR", "variants", - "${BOARD_OPTIONS['build']['variant']}" - ), - join( - "$PLATFORMFW_DIR", "variants", - "${BOARD_OPTIONS['build']['variant']}", - "linker_scripts" - ) - ] - ) - -env.Replace(PLATFORMFW_DIR=PLATFORMFW_DIR) - -# -# Lookup for specific core's libraries -# - -if isdir(join(env.subst("$PLATFORMFW_DIR"), "libraries", "__cores__", - BOARD_CORELIBDIRNAME)): - lib_dirs = env.get("LIBSOURCE_DIRS") - lib_dirs.insert( - lib_dirs.index(join("$PLATFORMFW_DIR", "libraries")), - join(PLATFORMFW_DIR, "libraries", "__cores__", BOARD_CORELIBDIRNAME) - ) - env.Replace( - LIBSOURCE_DIRS=lib_dirs - ) - -# -# Base -# - -ARDUINO_VERSION = int( - open(join(env.subst("$PLATFORMFW_DIR"), - "version.txt")).read().replace(".", "").strip()) - -# usb flags -ARDUINO_USBDEFINES = [] -if "usb_product" in BOARD_BUILDOPTS: - ARDUINO_USBDEFINES = [ - "USB_VID=${BOARD_OPTIONS['build']['hwid'][0][0]}", - "USB_PID=${BOARD_OPTIONS['build']['hwid'][0][1]}", - 'USB_PRODUCT=\\"%s\\"' % (env.subst( - "${BOARD_OPTIONS['build']['usb_product']}").replace('"', "")), - 'USB_MANUFACTURER=\\"%s\\"' % (env.subst( - "${BOARD_OPTIONS['vendor']}").replace('"', "")) - ] - -if env.get("PLATFORM") == "teensy": - ARDUINO_USBDEFINES += [ - "ARDUINO=10600", - "TEENSYDUINO=%d" % ARDUINO_VERSION - ] -else: - ARDUINO_USBDEFINES += ["ARDUINO=%d" % ARDUINO_VERSION] - -env.Append( - CPPDEFINES=ARDUINO_USBDEFINES, - - CPPPATH=[ - join("$BUILD_DIR", "FrameworkArduino") - ] -) - -# -# Atmel SAM platform -# - -if env.subst("${PLATFORMFW_DIR}")[-3:] == "sam": - env.VariantDirWrap( - join("$BUILD_DIR", "FrameworkCMSISInc"), - join("$PLATFORMFW_DIR", "system", "CMSIS", "CMSIS", "Include") - ) - env.VariantDirWrap( - join("$BUILD_DIR", "FrameworkDeviceInc"), - join("$PLATFORMFW_DIR", "system", "CMSIS", "Device", "ATMEL") - ) - env.VariantDirWrap( - join("$BUILD_DIR", "FrameworkLibSam"), - join("$PLATFORMFW_DIR", "system", "libsam") - ) - - env.VariantDirWrap( - join("$BUILD_DIR", "FrameworkArduinoInc"), - join("$PLATFORMFW_DIR", "cores", "${BOARD_OPTIONS['build']['core']}") - ) - env.Append( - CPPPATH=[ - join("$BUILD_DIR", "FrameworkCMSISInc"), - join("$BUILD_DIR", "FrameworkLibSam"), - join("$BUILD_DIR", "FrameworkLibSam", "include"), - join("$BUILD_DIR", "FrameworkDeviceInc"), - join( - "$BUILD_DIR", - "FrameworkDeviceInc", - "${BOARD_OPTIONS['build']['mcu'][3:]}", - "include" - ) - ], - - LIBPATH=[ - join( - "$PLATFORMFW_DIR", - "variants", - "${BOARD_OPTIONS['build']['variant']}", - "linker_scripts", - "gcc" - ) - ] - ) - - # search relative includes in lib SAM directories - core_dir = join(env.subst("$PLATFORMFW_DIR"), "system", "libsam") - for root, _, files in walk(core_dir): - for lib_file in files: - file_path = join(root, lib_file) - if not isfile(file_path): - continue - content = None - content_changed = False - with open(file_path) as fp: - content = fp.read() - if '#include "../' in content: - content_changed = True - content = content.replace('#include "../', '#include "') - if not content_changed: - continue - with open(file_path, "w") as fp: - fp.write(content) - -# -# Teensy platform -# - -# Teensy 2.x Core -if BOARD_BUILDOPTS.get("core", None) == "teensy": - # search relative includes in teensy directories - core_dir = join(env.get("PIOHOME_DIR"), "packages", - "framework-arduinoteensy", "cores", "teensy") - for item in sorted(listdir(core_dir)): - file_path = join(core_dir, item) - if not isfile(file_path): - continue - content = None - content_changed = False - with open(file_path) as fp: - content = fp.read() - if '#include "../' in content: - content_changed = True - content = content.replace('#include "../', '#include "') - if not content_changed: - continue - with open(file_path, "w") as fp: - fp.write(content) - -# -# Target: Build Core Library -# - -libs = [] - -if "variant" in BOARD_BUILDOPTS: - env.Append( - CPPPATH=[ - join("$BUILD_DIR", "FrameworkArduinoVariant") - ] - ) - libs.append(env.BuildLibrary( - join("$BUILD_DIR", "FrameworkArduinoVariant"), - join("$PLATFORMFW_DIR", "variants", - "${BOARD_OPTIONS['build']['variant']}") - )) - -envsafe = env.Clone() - -if BOARD_BUILDOPTS.get("core", None) == "teensy3": - libs.append("arm_cortex%sl_math" % ( - "M4" if BOARD_BUILDOPTS.get("cpu") == "cortex-m4" else "M0")) - -if env.subst("$BOARD") == "genuino101": - libs.append("libarc32drv_arduino101") - -libs.append(envsafe.BuildLibrary( - join("$BUILD_DIR", "FrameworkArduino"), - join("$PLATFORMFW_DIR", "cores", "${BOARD_OPTIONS['build']['core']}") -)) - -if "sam3x8e" in BOARD_BUILDOPTS.get("mcu", ""): - env.Append( - LIBPATH=[ - join("$PLATFORMFW_DIR", "variants", - "${BOARD_OPTIONS['build']['variant']}") - ] - ) - - libs.append("sam_sam3x8e_gcc_rel") - -env.Prepend(LIBS=libs) diff --git a/platformio/builder/scripts/frameworks/cmsis.py b/platformio/builder/scripts/frameworks/cmsis.py deleted file mode 100644 index e0ea99d5..00000000 --- a/platformio/builder/scripts/frameworks/cmsis.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" -CMSIS - -The ARM Cortex Microcontroller Software Interface Standard (CMSIS) is a -vendor-independent hardware abstraction layer for the Cortex-M processor -series and specifies debugger interfaces. The CMSIS enables consistent and -simple software interfaces to the processor for interface peripherals, -real-time operating systems, and middleware. It simplifies software -re-use, reducing the learning curve for new microcontroller developers -and cutting the time-to-market for devices. - -http://www.arm.com/products/processors/cortex-m/cortex-microcontroller-software-interface-standard.php -""" - -from os.path import isfile, join - -from SCons.Script import DefaultEnvironment - -env = DefaultEnvironment() - -env.Replace( - PLATFORMFW_DIR=join("$PIOPACKAGES_DIR", "framework-cmsis") -) - -env.VariantDirWrap( - join("$BUILD_DIR", "FrameworkCMSIS"), - join("$PLATFORMFW_DIR", "cores", "${BOARD_OPTIONS['build']['core']}") -) - -env.Append( - CPPPATH=[ - join("$BUILD_DIR", "FrameworkCMSIS"), - join("$BUILD_DIR", "FrameworkCMSISCommon"), - join("$BUILD_DIR", "FrameworkCMSISVariant") - ] -) - -envsafe = env.Clone() - -# -# Target: Build Core Library -# - -# use mbed ldscript with bootloader section -ldscript = env.get("BOARD_OPTIONS", {}).get("build", {}).get("ldscript") -if not isfile(join(env.subst("$PIOPACKAGES_DIR"), "ldscripts", ldscript)): - if "mbed" in env.get("BOARD_OPTIONS", {}).get("frameworks", {}): - env.Append( - LINKFLAGS=[ - '-Wl,-T"%s"' % - join( - "$PIOPACKAGES_DIR", "framework-mbed", "variant", - env.subst("$BOARD").upper(), "mbed", - "TARGET_%s" % env.subst( - "$BOARD").upper(), "TOOLCHAIN_GCC_ARM", - "%s.ld" % ldscript.upper()[:-3] - ) - ] - ) - -libs = [] -libs.append(envsafe.BuildLibrary( - join("$BUILD_DIR", "FrameworkCMSISVariant"), - join( - "$PLATFORMFW_DIR", "variants", - env.subst("${BOARD_OPTIONS['build']['variant']}")[0:7], - "${BOARD_OPTIONS['build']['variant']}" - ) -)) - -libs.append(envsafe.BuildLibrary( - join("$BUILD_DIR", "FrameworkCMSISCommon"), - join( - "$PLATFORMFW_DIR", "variants", - env.subst("${BOARD_OPTIONS['build']['variant']}")[0:7], "common" - ) -)) - -env.Append(LIBS=libs) diff --git a/platformio/builder/scripts/frameworks/energia.py b/platformio/builder/scripts/frameworks/energia.py deleted file mode 100644 index 24bc9760..00000000 --- a/platformio/builder/scripts/frameworks/energia.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" -Energia - -Energia Wiring-based framework enables pretty much anyone to start easily -creating microcontroller-based projects and applications. Its easy-to-use -libraries and functions provide developers of all experience levels to start -blinking LEDs, buzzing buzzers and sensing sensors more quickly than ever -before. - -http://energia.nu/reference/ -""" - -from os.path import join - -from SCons.Script import DefaultEnvironment - -env = DefaultEnvironment() - -env.Replace( - PLATFORMFW_DIR=join("$PIOPACKAGES_DIR", "framework-energia${PLATFORM[2:]}") -) - -ENERGIA_VERSION = int( - open(join(env.subst("$PLATFORMFW_DIR"), - "version.txt")).read().replace(".", "").strip()) - -# include board variant -env.VariantDirWrap( - join("$BUILD_DIR", "FrameworkEnergiaVariant"), - join("$PLATFORMFW_DIR", "variants", "${BOARD_OPTIONS['build']['variant']}") -) - -env.Append( - CPPDEFINES=[ - "ARDUINO=101", - "ENERGIA=%d" % ENERGIA_VERSION - ], - CPPPATH=[ - join("$BUILD_DIR", "FrameworkEnergia"), - join("$BUILD_DIR", "FrameworkEnergiaVariant") - ] -) - -if env.get("BOARD_OPTIONS", {}).get("build", {}).get("core") == "lm4f": - env.Append( - LINKFLAGS=["-Wl,--entry=ResetISR"] - ) - -# -# Target: Build Core Library -# - -libs = [] - -libs.append(env.BuildLibrary( - join("$BUILD_DIR", "FrameworkEnergia"), - join("$PLATFORMFW_DIR", "cores", "${BOARD_OPTIONS['build']['core']}") -)) - -env.Append(LIBS=libs) diff --git a/platformio/builder/scripts/frameworks/libopencm3.py b/platformio/builder/scripts/frameworks/libopencm3.py deleted file mode 100644 index e48e61a3..00000000 --- a/platformio/builder/scripts/frameworks/libopencm3.py +++ /dev/null @@ -1,191 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" -libOpenCM3 - -The libOpenCM3 framework aims to create a free/libre/open-source -firmware library for various ARM Cortex-M0(+)/M3/M4 microcontrollers, -including ST STM32, Ti Tiva and Stellaris, NXP LPC 11xx, 13xx, 15xx, -17xx parts, Atmel SAM3, Energy Micro EFM32 and others. - -http://www.libopencm3.org/wiki/Main_Page -""" - -from __future__ import absolute_import - -import re -from os import listdir, sep, walk -from os.path import isfile, join, normpath - -from SCons.Script import DefaultEnvironment - -from platformio.util import exec_command - -env = DefaultEnvironment() - -env.Replace( - PLATFORMFW_DIR=join("$PIOPACKAGES_DIR", "framework-libopencm3") -) - -BOARD_BUILDOPTS = env.get("BOARD_OPTIONS", {}).get("build", {}) - - -def find_ldscript(src_dir): - ldscript = None - matches = [] - for item in sorted(listdir(src_dir)): - _path = join(src_dir, item) - if not isfile(_path) or not item.endswith(".ld"): - continue - matches.append(_path) - - if len(matches) == 1: - ldscript = matches[0] - elif isfile(join(src_dir, BOARD_BUILDOPTS['ldscript'])): - ldscript = join(src_dir, BOARD_BUILDOPTS['ldscript']) - - return ldscript - - -def generate_nvic_files(): - fw_dir = env.subst("$PLATFORMFW_DIR") - for root, _, files in walk(join(fw_dir, "include", "libopencm3")): - if "irq.json" not in files or isfile(join(root, "nvic.h")): - continue - - exec_command( - ["python", join("scripts", "irq2nvic_h"), - join("." + root.replace(fw_dir, ""), - "irq.json").replace("\\", "/")], - cwd=fw_dir - ) - - -def parse_makefile_data(makefile): - data = {"includes": [], "objs": [], "vpath": ["./"]} - - with open(makefile) as f: - content = f.read() - - # fetch "includes" - re_include = re.compile(r"^include\s+([^\r\n]+)", re.M) - for match in re_include.finditer(content): - data['includes'].append(match.group(1)) - - # fetch "vpath"s - re_vpath = re.compile(r"^VPATH\s+\+?=\s+([^\r\n]+)", re.M) - for match in re_vpath.finditer(content): - data['vpath'] += match.group(1).split(":") - - # fetch obj files - objs_match = re.search( - r"^OBJS\s+\+?=\s+([^\.]+\.o\s*(?:\s+\\s+)?)+", content, re.M) - assert objs_match - data['objs'] = re.sub( - r"(OBJS|[\+=\\\s]+)", "\n", objs_match.group(0)).split() - return data - - -def get_source_files(src_dir): - mkdata = parse_makefile_data(join(src_dir, "Makefile")) - - for include in mkdata['includes']: - _mkdata = parse_makefile_data(normpath(join(src_dir, include))) - for key, value in _mkdata.iteritems(): - for v in value: - if v not in mkdata[key]: - mkdata[key].append(v) - - sources = [] - lib_root = env.subst("$PLATFORMFW_DIR") - for obj_file in mkdata['objs']: - src_file = obj_file[:-1] + "c" - for search_path in mkdata['vpath']: - src_path = normpath(join(src_dir, search_path, src_file)) - if isfile(src_path): - sources.append(join("$BUILD_DIR", "FrameworkLibOpenCM3", - src_path.replace(lib_root + sep, ""))) - break - return sources - - -def merge_ld_scripts(main_ld_file): - - def _include_callback(match): - included_ld_file = match.group(1) - # search included ld file in lib directories - for root, _, files in walk(env.subst(join("$PLATFORMFW_DIR", "lib"))): - if included_ld_file not in files: - continue - with open(join(root, included_ld_file)) as fp: - return fp.read() - return match.group(0) - - content = "" - with open(main_ld_file) as f: - content = f.read() - - incre = re.compile(r"^INCLUDE\s+\"?([^\.]+\.ld)\"?", re.M) - with open(main_ld_file, "w") as f: - f.write(incre.sub(_include_callback, content)) - -# -# Processing ... -# - -if BOARD_BUILDOPTS.get("core") == "lm4f": - env.Append( - CPPDEFINES=["LM4F"] - ) - -env.VariantDirWrap( - join("$BUILD_DIR", "FrameworkLibOpenCM3Variant"), - join("$PLATFORMFW_DIR", "include") -) - -env.Append( - CPPPATH=[ - join("$BUILD_DIR", "FrameworkLibOpenCM3"), - join("$BUILD_DIR", "FrameworkLibOpenCM3Variant") - ] -) - -root_dir = env.subst( - join("$PLATFORMFW_DIR", "lib", BOARD_BUILDOPTS.get("core"))) -if BOARD_BUILDOPTS.get("core") == "stm32": - root_dir = join(root_dir, BOARD_BUILDOPTS.get("variant")[5:7]) - -ldscript_path = find_ldscript(root_dir) -if ldscript_path: - merge_ld_scripts(ldscript_path) -generate_nvic_files() - -# override ldscript by libopencm3 -assert "LDSCRIPT_PATH" in env -env.Replace( - LDSCRIPT_PATH=ldscript_path -) - -libs = [] -env.VariantDirWrap( - join("$BUILD_DIR", "FrameworkLibOpenCM3"), - "$PLATFORMFW_DIR" -) -libs.append(env.Library( - join("$BUILD_DIR", "FrameworkLibOpenCM3"), - get_source_files(root_dir) -)) - -env.Append(LIBS=libs) diff --git a/platformio/builder/scripts/frameworks/mbed.py b/platformio/builder/scripts/frameworks/mbed.py deleted file mode 100644 index 24b04dbe..00000000 --- a/platformio/builder/scripts/frameworks/mbed.py +++ /dev/null @@ -1,289 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" -mbed - -The mbed framework The mbed SDK has been designed to provide enough -hardware abstraction to be intuitive and concise, yet powerful enough to -build complex projects. It is built on the low-level ARM CMSIS APIs, -allowing you to code down to the metal if needed. In addition to RTOS, -USB and Networking libraries, a cookbook of hundreds of reusable -peripheral and module libraries have been built on top of the SDK by -the mbed Developer Community. - -http://mbed.org/ -""" - -from __future__ import print_function - -import re -import sys -import xml.etree.ElementTree as ElementTree -from binascii import crc32 -from os import walk -from os.path import basename, isfile, join, normpath - -from SCons.Script import DefaultEnvironment - -env = DefaultEnvironment() - -BOARD_OPTS = env.get("BOARD_OPTIONS", {}).get("build", {}) - -env.Replace( - PLATFORMFW_DIR=join("$PIOPACKAGES_DIR", "framework-mbed") -) - -MBED_VARIANTS = { - "blueboard_lpc11u24": "LPC11U24", - "dipcortexm0": "LPC11U24", - "seeeduinoArchPro": "ARCH_PRO", - "seeedArchMax": "ARCH_MAX", - "ubloxc027": "UBLOX_C027", - "lpc1114fn28": "LPC1114", - "lpc11u35": "LPC11U35_401", - "mbuino": "LPC11U24", - "nrf51_mkit": "NRF51822", - "seeedTinyBLE": "SEEED_TINY_BLE", - "redBearLab": "RBLAB_NRF51822", - "nrf51-dt": "NRF51_DK", - "redBearLabBLENano": "RBLAB_BLENANO", - "wallBotBLE": "NRF51822", - "frdm_kl25z": "KL25Z", - "frdm_kl46z": "KL46Z", - "frdm_k64f": "K64F", - "frdm_kl05z": "KL05Z", - "frdm_k20d50m": "K20D50M", - "frdm_k22f": "K22F", - "teensy31": "TEENSY3_1", - "dfcm_nnn40": "DELTA_DFCM_NNN40", - "samr21_xpro": "SAMR21G18A", - "saml21_xpro_b": "SAML21J18A", - "samd21_xpro": "SAMD21J18A", - "bbcmicrobit": "NRF51822" -} - -MBED_LIBS_MAP = { - "dsp": {"ar": ["dsp", "cmsis_dsp"]}, - "eth": {"ar": ["eth"], "deps": ["rtos"]}, - "fat": {"ar": ["fat"]}, - "rtos": {"ar": ["rtos", "rtx"]}, - "usb": {"ar": ["USBDevice"]}, - "usb_host": {"ar": ["USBHost"]} -} - - -def get_mbedlib_includes(): - result = [] - for lib in MBED_LIBS_MAP.keys(): - includes = [] - lib_dir = join(env.subst("$PLATFORMFW_DIR"), "libs", lib) - for _, _, files in walk(lib_dir): - for libfile in files: - if libfile.endswith(".h"): - includes.append(libfile) - result.append((lib, set(includes))) - return result - - -def get_used_mbedlibs(): - re_includes = re.compile(r"^(#include\s+(?:\<|\")([^\r\n\"]+))", - re.M | re.I) - srcincs = [] - for root, _, files in walk(env.get("PROJECTSRC_DIR")): - for pfile in files: - if not any([pfile.endswith(ext) for ext in (".h", ".c", ".cpp")]): - continue - with open(join(root, pfile)) as fp: - srcincs.extend([i[1] for i in re_includes.findall(fp.read())]) - srcincs = set(srcincs) - - result = {} - for libname, libincs in get_mbedlib_includes(): - if libincs & srcincs and libname not in result: - result[libname] = MBED_LIBS_MAP[libname] - - return result - - -def add_mbedlib(libname, libar): - if libar in env.get("LIBS"): - return - - lib_dir = join(env.subst("$PLATFORMFW_DIR"), "libs", libname) - if not isfile(join(lib_dir, "TARGET_%s" % variant, - "TOOLCHAIN_GCC_ARM", "lib%s.a" % libar)): - print( - "Warning: %s board doesn't have native support for '%s' library!" % - (env.get("BOARD"), libname), file=sys.stderr) - return - - env.Append( - LIBPATH=[ - join(env.subst("$PLATFORMFW_DIR"), "libs", libname, - "TARGET_%s" % variant, "TOOLCHAIN_GCC_ARM") - ], - LIBS=[libar] - ) - - sysincdirs = ( - "eth", - "include", - "ipv4", - "lwip-eth", - "lwip-sys" - ) - - for root, _, files in walk(lib_dir): - if (not any(f.endswith(".h") for f in files) and - basename(root) not in sysincdirs): - continue - var_dir = join("$BUILD_DIR", "FrameworkMbed%sInc%d" % - (libname.upper(), crc32(root))) - if var_dir in env.get("CPPPATH"): - continue - env.VariantDirWrap(var_dir, root) - env.Append(CPPPATH=[var_dir]) - - -def parse_eix_file(filename): - result = {} - paths = ( - ("CFLAGS", "./Target/Source/CC/Switch"), - ("CXXFLAGS", "./Target/Source/CPPC/Switch"), - ("CPPDEFINES", "./Target/Source/Symbols/Symbol"), - ("FILES", "./Target/Files/File"), - ("LINKFLAGS", "./Target/Source/LD/Switch"), - ("OBJFILES", "./Target/Source/Addobjects/Addobject"), - ("LIBPATH", "./Target/Linker/Librarypaths/Librarypath"), - ("STDLIBS", "./Target/Source/Syslibs/Library"), - ("LDSCRIPT_PATH", "./Target/Source/Scriptfile"), - ("CPPPATH", "./Target/Compiler/Includepaths/Includepath") - ) - - tree = ElementTree.parse(filename) - - for (key, path) in paths: - if key not in result: - result[key] = [] - - for node in tree.findall(path): - _nkeys = node.keys() - result[key].append( - node.get(_nkeys[0]) if len(_nkeys) == 1 else node.attrib) - - return result - - -def get_build_flags(data): - flags = {} - cflags = set(data.get("CFLAGS", [])) - cxxflags = set(data.get("CXXFLAGS", [])) - ccflags = set(cflags & cxxflags) - flags['CCFLAGS'] = list(ccflags) - flags['CXXFLAGS'] = list(cxxflags - ccflags) - flags['CFLAGS'] = list(cflags - ccflags) - return flags - - -def _mbed_whole_archive_hook(libs_): - if (not isinstance(libs_, list) or - env.get("BOARD_OPTIONS", {}).get("platform") != "ststm32"): - return libs_ - - _dynlibs = [] - _stlibs = [] - for l_ in libs_: - if isinstance(l_, basestring): - _stlibs.append(l_) - else: - _dynlibs.append(l_) - - libs_ = [] - if _dynlibs: - libs_.append("-Wl,-whole-archive") - libs_.extend(_dynlibs) - libs_.append("-Wl,-no-whole-archive") - libs_.extend(_stlibs) - - return libs_ - - -board_type = env.subst("$BOARD") -variant = MBED_VARIANTS[ - board_type] if board_type in MBED_VARIANTS else board_type.upper() -eixdata = parse_eix_file( - join(env.subst("$PLATFORMFW_DIR"), "variant", variant, "%s.eix" % variant)) - -build_flags = get_build_flags(eixdata) -variant_dir = join("$PLATFORMFW_DIR", "variant", variant) - -env.Replace( - _mbed_whole_archive_hook=_mbed_whole_archive_hook, - _LIBFLAGS="${_mbed_whole_archive_hook(%s)}" % env.get("_LIBFLAGS")[2:-1], - CCFLAGS=build_flags.get("CCFLAGS", []), - CFLAGS=build_flags.get("CFLAGS", []), - CXXFLAGS=build_flags.get("CXXFLAGS", []), - LINKFLAGS=eixdata.get("LINKFLAGS", []), - CPPDEFINES=[define for define in eixdata.get("CPPDEFINES", [])], - LDSCRIPT_PATH=normpath( - join(variant_dir, eixdata.get("LDSCRIPT_PATH")[0])) -) - -# restore external build flags -env.ProcessFlags([ - env.get("BOARD_OPTIONS", {}).get("build", {}).get("extra_flags"), - env.get("BUILD_FLAGS") -]) - -# Hook for K64F and K22F -if board_type in ("frdm_k22f", "frdm_k64f"): - env.Append( - LINKFLAGS=["-Wl,--start-group"] - ) - -for lib_path in eixdata.get("CPPPATH"): - _vdir = join("$BUILD_DIR", "FrameworkMbedInc%d" % crc32(lib_path)) - env.VariantDirWrap(_vdir, join(variant_dir, lib_path)) - env.Append(CPPPATH=[_vdir]) - -env.Append( - LIBPATH=[join(variant_dir, lib_path) - for lib_path in eixdata.get("LIBPATH", []) - if lib_path.startswith("mbed")] -) - -# -# Target: Build mbed Library -# - -libs = [l for l in eixdata.get("STDLIBS", []) if l not in env.get("LIBS", [])] -libs.extend(["mbed", "c", "gcc"]) - -libs.append(env.Library( - join("$BUILD_DIR", "FrameworkMbed"), - [join(variant_dir, f) - for f in eixdata.get("OBJFILES", [])] -)) - -env.Prepend(LIBS=libs) - -for _libname, _libdata in get_used_mbedlibs().iteritems(): - for _libar in _libdata['ar']: - add_mbedlib(_libname, _libar) - if "deps" not in _libdata: - continue - for libdep in _libdata['deps']: - for _libar in MBED_LIBS_MAP[libdep]['ar']: - add_mbedlib(libdep, _libar) diff --git a/platformio/builder/scripts/frameworks/simba.py b/platformio/builder/scripts/frameworks/simba.py deleted file mode 100755 index 52c875e4..00000000 --- a/platformio/builder/scripts/frameworks/simba.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -"""Simba - -Simba is an RTOS and build framework. It aims to make embedded -programming easy and portable. - -http://simba-os.readthedocs.org - -""" - -from os.path import join - -from SCons.Script import DefaultEnvironment, SConscript - -env = DefaultEnvironment() - -env.Replace( - PLATFORMFW_DIR=join("$PIOPACKAGES_DIR", "framework-simba") -) - -SConscript( - [env.subst(join("$PLATFORMFW_DIR", "make", "platformio.sconscript"))]) diff --git a/platformio/builder/scripts/frameworks/spl.py b/platformio/builder/scripts/frameworks/spl.py deleted file mode 100644 index e521ae9f..00000000 --- a/platformio/builder/scripts/frameworks/spl.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" -SPL - -The ST Standard Peripheral Library provides a set of functions for -handling the peripherals on the STM32 Cortex-M3 family. -The idea is to save the user (the new user, in particular) having to deal -directly with the registers. - -http://www.st.com/web/en/catalog/tools/FM147/CL1794/SC961/SS1743?sc=stm32embeddedsoftware -""" - -from os.path import isfile, join - -from SCons.Script import DefaultEnvironment - -env = DefaultEnvironment() - -env.Replace( - PLATFORMFW_DIR=join("$PIOPACKAGES_DIR", "framework-spl") -) - -env.VariantDirWrap( - join("$BUILD_DIR", "FrameworkCMSIS"), - join("$PLATFORMFW_DIR", "${BOARD_OPTIONS['build']['core']}", - "cmsis", "cores", "${BOARD_OPTIONS['build']['core']}") -) - -env.VariantDirWrap( - join("$BUILD_DIR", "FrameworkSPLInc"), - join( - "$PLATFORMFW_DIR", "${BOARD_OPTIONS['build']['core']}", "spl", - "variants", env.subst("${BOARD_OPTIONS['build']['variant']}")[0:7], - "inc" - ) -) - -env.Append( - CPPPATH=[ - join("$BUILD_DIR", "FrameworkCMSIS"), - join("$BUILD_DIR", "FrameworkCMSISVariant"), - join("$BUILD_DIR", "FrameworkSPLInc"), - join("$BUILD_DIR", "FrameworkSPL") - ] -) - -envsafe = env.Clone() - -envsafe.Append( - CPPPATH=["$BUILDSRC_DIR"], - CPPDEFINES=[ - "USE_STDPERIPH_DRIVER" - ] -) - -# -# Target: Build SPL Library -# - -# use mbed ldscript with bootloader section -ldscript = env.get("BOARD_OPTIONS", {}).get("build", {}).get("ldscript") -if not isfile(join(env.subst("$PIOPACKAGES_DIR"), "ldscripts", ldscript)): - if "mbed" in env.get("BOARD_OPTIONS", {}).get("frameworks", {}): - env.Append( - LINKFLAGS=[ - '-Wl,-T"%s"' % - join( - "$PIOPACKAGES_DIR", "framework-mbed", "variant", - env.subst("$BOARD").upper(), "mbed", - "TARGET_%s" % env.subst( - "$BOARD").upper(), "TOOLCHAIN_GCC_ARM", - "%s.ld" % ldscript.upper()[:-3] - ) - ] - ) - -extra_flags = env.get("BOARD_OPTIONS", {}).get("build", {}).get("extra_flags") -src_filter_patterns = ["+<*>"] -if "STM32F40_41xxx" in extra_flags: - src_filter_patterns += ["-"] -if "STM32F427_437xx" in extra_flags: - src_filter_patterns += ["-"] -elif "STM32F303xC" in extra_flags: - src_filter_patterns += ["-"] -elif "STM32L1XX_MD" in extra_flags: - src_filter_patterns += ["-"] - -libs = [] - -libs.append(envsafe.BuildLibrary( - join("$BUILD_DIR", "FrameworkCMSISVariant"), - join( - "$PLATFORMFW_DIR", "${BOARD_OPTIONS['build']['core']}", "cmsis", - "variants", env.subst("${BOARD_OPTIONS['build']['variant']}")[0:7] - ) -)) - -libs.append(envsafe.BuildLibrary( - join("$BUILD_DIR", "FrameworkSPL"), - join("$PLATFORMFW_DIR", "${BOARD_OPTIONS['build']['core']}", - "spl", "variants", - env.subst("${BOARD_OPTIONS['build']['variant']}")[0:7], "src"), - src_filter=" ".join(src_filter_patterns) -)) - -env.Append(LIBS=libs) diff --git a/platformio/builder/scripts/frameworks/wiringpi.py b/platformio/builder/scripts/frameworks/wiringpi.py deleted file mode 100644 index c17b4801..00000000 --- a/platformio/builder/scripts/frameworks/wiringpi.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" -WiringPi - -WiringPi is a GPIO access library written in C for the BCM2835 used in the -Raspberry Pi. It's designed to be familiar to people who have used the Arduino -"wiring" system. - -http://wiringpi.com -""" - -from os.path import join - -from SCons.Script import DefaultEnvironment - -env = DefaultEnvironment() - -env.Replace( - CPPFLAGS=[ - "-O2", - "-Wformat=2", - "-Wall", - "-Winline", - "-pipe", - "-fPIC" - ], - - LIBS=["pthread"] -) - -env.Append( - CPPDEFINES=[ - "_GNU_SOURCE" - ], - - CPPPATH=[ - join("$BUILD_DIR", "FrameworkWiringPi") - ] -) - - -# -# Target: Build Core Library -# - -libs = [] -libs.append(env.BuildLibrary( - join("$BUILD_DIR", "FrameworkWiringPi"), - join("$PIOPACKAGES_DIR", "framework-wiringpi", "wiringPi") -)) - -env.Append(LIBS=libs) diff --git a/platformio/builder/scripts/freescalekinetis.py b/platformio/builder/scripts/freescalekinetis.py deleted file mode 100644 index af832d00..00000000 --- a/platformio/builder/scripts/freescalekinetis.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for Freescale Kinetis series ARM microcontrollers. -""" - -from os.path import join - -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Default, - DefaultEnvironment, SConscript) - -env = DefaultEnvironment() - -SConscript(env.subst(join("$PIOBUILDER_DIR", "scripts", "basearm.py"))) - -# -# Target: Build executable and linkable firmware -# - -target_elf = env.BuildProgram() - -# -# Target: Build the .bin file -# - -if "uploadlazy" in COMMAND_LINE_TARGETS: - target_firm = join("$BUILD_DIR", "firmware.bin") -else: - target_firm = env.ElfToBin(join("$BUILD_DIR", "firmware"), target_elf) - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_elf, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Upload by default .bin file -# - -upload = env.Alias(["upload", "uploadlazy"], target_firm, env.UploadToDisk) -AlwaysBuild(upload) - -# -# Target: Define targets -# - -Default([target_firm, target_size]) diff --git a/platformio/builder/scripts/intel_arc32.py b/platformio/builder/scripts/intel_arc32.py deleted file mode 100644 index e5db85d8..00000000 --- a/platformio/builder/scripts/intel_arc32.py +++ /dev/null @@ -1,200 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for Intel ARC32 microcontrollers -""" - -from os.path import join - -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Builder, Default, - DefaultEnvironment) - - -def BeforeUpload(target, source, env): # pylint: disable=W0613,W0621 - - if "program" in COMMAND_LINE_TARGETS: - return - - env.AutodetectUploadPort() - env.Prepend(UPLOADERFLAGS=['"$UPLOAD_PORT"']) - - if env.get("BOARD_OPTIONS", {}).get("upload", {}).get( - "use_1200bps_touch", False): - env.TouchSerialPort("$UPLOAD_PORT", 1200) - - -env = DefaultEnvironment() - -env.Replace( - AR="arc-elf32-ar", - AS="arc-elf32-as", - CC="arc-elf32-gcc", - CXX="arc-elf32-g++", - OBJCOPY="arc-elf32-objcopy", - RANLIB="arc-elf32-ranlib", - SIZETOOL="arc-elf32-size", - - ARFLAGS=["rcs"], - - ASFLAGS=["-x", "assembler-with-cpp"], - - CCFLAGS=[ - "-g", - "-Os", - "-ffunction-sections", - "-fdata-sections", - "-Wall", - "-mav2em", - "-mlittle-endian", - "-m${BOARD_OPTIONS['build']['mcu']}", - "-fno-reorder-functions", - "-fno-asynchronous-unwind-tables", - "-fno-omit-frame-pointer", - "-fno-defer-pop", - "-Wno-unused-but-set-variable", - "-Wno-main", - "-ffreestanding", - "-fno-stack-protector", - "-mno-sdata", - "-fsigned-char" - ], - - CXXFLAGS=[ - "-fno-rtti", - "-std=c++11", - "-fno-exceptions" - ], - - CPPDEFINES=[ - "F_CPU=$BOARD_F_CPU", - "ARDUINO_ARC32_TOOLS", - "__CPU_ARC__", - "CLOCK_SPEED=%d" % ( - int(env.subst("${BOARD_OPTIONS['build']['f_cpu']}").replace( - "L", ""))/1000000), - "CONFIG_SOC_GPIO_32", - "CONFIG_SOC_GPIO_AON", - "INFRA_MULTI_CPU_SUPPORT", - "CFW_MULTI_CPU_SUPPORT", - "HAS_SHARED_MEM" - ], - - LINKFLAGS=[ - "-Os", - "-Wl,--gc-sections", - "-Wl,-X", - "-Wl,-N", - "-Wl,-m${BOARD_OPTIONS['build']['mcu']}", - "-Wl,-marcelf", - "-static", - "-nostdlib", - "-nodefaultlibs", - "-nostartfiles", - "-Wl,--whole-archive", - "-larc32drv_arduino101", - "-Wl,--no-whole-archive" - ], - - LIBS=["c", "m", "gcc"], - - SIZEPRINTCMD='"$SIZETOOL" -B -d $SOURCES', - - UPLOADER=join("$PIOPACKAGES_DIR", "tool-arduino101load", "arduino101load"), - DFUUTIL=join("$PIOPACKAGES_DIR", "tool-arduino101load", "dfu-util"), - UPLOADCMD='"$UPLOADER" $DFUUTIL $SOURCES $UPLOADERFLAGS verbose', - - PROGNAME="firmware", - PROGSUFFIX=".elf" -) - - -env.Append( - ASFLAGS=env.get("CCFLAGS", [])[:], - - BUILDERS=dict( - ElfToBin=Builder( - action=" ".join([ - "$OBJCOPY", - "-S", - "-O", - "binary", - "-R", - ".note", - "-R", - ".comment", - "-R", - "COMMON", - "-R", - ".eh_frame", - "$SOURCES", - "$TARGET"]), - suffix=".bin" - ), - ElfToHex=Builder( - action=" ".join([ - "$OBJCOPY", - "-S", - "-O", - "binary", - "-R", - ".note", - "-R", - ".comment", - "-R", - "COMMON", - "-R", - ".eh_frame", - "$SOURCES", - "$TARGET"]), - suffix=".hex" - ) - ) -) - -# -# Target: Build executable and linkable firmware -# - -target_elf = env.BuildProgram() - -# -# Target: Build the .bin -# - -if "uploadlazy" in COMMAND_LINE_TARGETS: - target_firm = join("$BUILD_DIR", "firmware.bin") -else: - target_firm = env.ElfToBin(join("$BUILD_DIR", "firmware"), target_elf) - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_elf, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Upload firmware -# - -upload = env.Alias( - ["upload", "uploadlazy"], target_firm, [BeforeUpload, "$UPLOADCMD"]) -AlwaysBuild(upload) - -# -# Target: Define targets -# - -Default([target_firm, target_size]) diff --git a/platformio/builder/scripts/lattice_ice40.py b/platformio/builder/scripts/lattice_ice40.py deleted file mode 100755 index c2059a11..00000000 --- a/platformio/builder/scripts/lattice_ice40.py +++ /dev/null @@ -1,149 +0,0 @@ -""" - Build script for lattice ice40 FPGAs - latticeice40-builder.py -""" -import os -from os.path import join - -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Builder, Default, - DefaultEnvironment, Environment, Exit, GetOption, - Glob) - -env = DefaultEnvironment() -env.Replace(PROGNAME="hardware") -env.Append(SIMULNAME="simulation") - -# -- Get the local folder in which the icestorm tools should be installed -piopackages_dir = env.subst('$PIOPACKAGES_DIR') -bin_dir = join(piopackages_dir, 'toolchain-icestorm', 'bin') - -# -- Add this path to the PATH env variable. First the building tools will be -# -- searched in the local PATH. If they are not founde, the global ones will -# -- be executed (if installed) -env.PrependENVPath('PATH', bin_dir) - -# -- Target name for synthesis -TARGET = join(env['BUILD_DIR'], env['PROGNAME']) - -# -- Target name for simulation -# TARGET_SIM = join(env['PROJECT_DIR'], env['SIMULNAME']) - -# -- Get a list of all the verilog files in the src folfer, in ASCII, with -# -- the full path. All these files are used for the simulation -v_nodes = Glob(join(env['PROJECTSRC_DIR'], '*.v')) -src_sim = [str(f) for f in v_nodes] - -# --------- Get the Testbench file (there should be only 1) -# -- Create a list with all the files finished in _tb.v. It should contain -# -- the test bench -list_tb = [f for f in src_sim if f[-5:].upper() == "_TB.V"] - -if len(list_tb) > 1: - print "---> WARNING: More than one testbenches used" - -# -- Error checking -try: - testbench = list_tb[0] - -# -- there is no testbench -except IndexError: - testbench = None - -if 'sim' in COMMAND_LINE_TARGETS: - if testbench is None: - print "ERROR!!! NO testbench found for simulation" - Exit(1) - - # -- Simulation name - testbench_file = os.path.split(testbench)[-1] - SIMULNAME, ext = os.path.splitext(testbench_file) -else: - SIMULNAME = '' - - -TARGET_SIM = join(env.subst('$BUILD_DIR'), SIMULNAME) - -# -------- Get the synthesis files. They are ALL the files except the -# -------- testbench -src_synth = [f for f in src_sim if f not in list_tb] - -# -- For debugging -print "Testbench: %s" % testbench - -# -- Get the PCF file -src_dir = env.subst('$PROJECTSRC_DIR') -PCFs = join(src_dir, '*.pcf') -PCF_list = Glob(PCFs) - -try: - PCF = PCF_list[0] -except IndexError: - print "\n--------> ERROR: no .pcf file found <----------\n" - Exit(2) - -# -- Debug -print "----> PCF Found: %s" % PCF - -# -- Builder 1 (.v --> .blif) -synth = Builder(action='yosys -p \"synth_ice40 -blif %s.blif\" \ - $SOURCES' % TARGET, - suffix='.blif', - src_suffix='.v') - -# -- Builder 2 (.blif --> .asc) -pnr = Builder(action='arachne-pnr -d 1k -o $TARGET -p %s \ - $SOURCE' % PCF, - suffix='.asc', - src_suffix='.blif') - -# -- Builder 3 (.asc --> .bin) -bitstream = Builder(action='icepack $SOURCE $TARGET', - suffix='.bin', - src_suffix='.asc') - -# -- Builder 4 (.asc --> .rpt) -time_rpt = Builder(action='icetime -mtr $TARGET $SOURCE', - suffix='.rpt', - src_suffix='.asc') - -env.Append(BUILDERS={'Synth': synth, 'PnR': pnr, 'Bin': bitstream, - 'Time': time_rpt}) - -blif = env.Synth(TARGET, [src_synth]) -asc = env.PnR(TARGET, [blif, PCF]) -binf = env.Bin(TARGET, asc) - -upload = env.Alias('upload', binf, 'iceprog ' + ' $SOURCE') -AlwaysBuild(upload) - -# -- Target for calculating the time (.rpt) -# rpt = env.Time(asc) -t = env.Alias('time', env.Time('time.rpt', asc)) - -# -------------------- Simulation ------------------ -# -- Constructor para generar simulacion: icarus Verilog -iverilog = Builder(action='iverilog -o $TARGET $SOURCES ', - suffix='.out', - src_suffix='.v') - -vcd = Builder(action=' $SOURCE', - suffix='.vcd', src_suffix='.out') - -simenv = Environment(BUILDERS={'IVerilog': iverilog, 'VCD': vcd}, - ENV=os.environ) - -out = simenv.IVerilog(TARGET_SIM, src_sim) -vcd_file = simenv.VCD(SIMULNAME, out) - -waves = simenv.Alias('sim', vcd_file, 'gtkwave ' + - join(env['PROJECT_DIR'], "%s " % vcd_file[0]) + - join(env['PROJECTSRC_DIR'], SIMULNAME) + - '.gtkw') -AlwaysBuild(waves) - -Default([binf]) - -# -- These is for cleaning the files generated using the alias targets -if GetOption('clean'): - env.Default([t]) - simenv.Default([out, vcd_file]) diff --git a/platformio/builder/scripts/linux_arm.py b/platformio/builder/scripts/linux_arm.py deleted file mode 100644 index 15e73370..00000000 --- a/platformio/builder/scripts/linux_arm.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for Linux ARM -""" - -from SCons.Script import AlwaysBuild, Default, DefaultEnvironment - -from platformio.util import get_systype - -env = DefaultEnvironment() - -env.Replace( - _BINPREFIX="", - AR="${_BINPREFIX}ar", - AS="${_BINPREFIX}as", - CC="${_BINPREFIX}gcc", - CXX="${_BINPREFIX}g++", - OBJCOPY="${_BINPREFIX}objcopy", - RANLIB="${_BINPREFIX}ranlib", - SIZETOOL="${_BINPREFIX}size", - - SIZEPRINTCMD='"$SIZETOOL" $SOURCES' -) - -if get_systype() == "darwin_x86_64": - env.Replace( - _BINPREFIX="arm-linux-gnueabihf-" - ) - -# -# Target: Build executable program -# - -target_bin = env.BuildProgram() - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_bin, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Define targets -# - -Default([target_bin]) diff --git a/platformio/builder/scripts/linux_i686.py b/platformio/builder/scripts/linux_i686.py deleted file mode 100644 index b9aaecde..00000000 --- a/platformio/builder/scripts/linux_i686.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for Linux Linux i686 / 32-bit -""" - -from SCons.Script import AlwaysBuild, Default, DefaultEnvironment - -from platformio.util import get_systype - -env = DefaultEnvironment() - -env.Replace( - _BINPREFIX="", - AR="${_BINPREFIX}ar", - AS="${_BINPREFIX}as", - CC="${_BINPREFIX}gcc", - CXX="${_BINPREFIX}g++", - OBJCOPY="${_BINPREFIX}objcopy", - RANLIB="${_BINPREFIX}ranlib", - SIZETOOL="${_BINPREFIX}size", - - SIZEPRINTCMD='"$SIZETOOL" $SOURCES' -) - -if get_systype() == "darwin_x86_64": - env.Replace( - _BINPREFIX="i586-pc-linux-" - ) - -# -# Target: Build executable program -# - -target_bin = env.BuildProgram() - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_bin, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Define targets -# - -Default([target_bin]) diff --git a/platformio/builder/scripts/linux_x86_64.py b/platformio/builder/scripts/linux_x86_64.py deleted file mode 100644 index e837d2a5..00000000 --- a/platformio/builder/scripts/linux_x86_64.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for Linux Linux x64_64 / 64-bit -""" - -from SCons.Script import AlwaysBuild, Default, DefaultEnvironment - -from platformio.util import get_systype - -env = DefaultEnvironment() - -env.Replace( - _BINPREFIX="", - AR="${_BINPREFIX}ar", - AS="${_BINPREFIX}as", - CC="${_BINPREFIX}gcc", - CXX="${_BINPREFIX}g++", - OBJCOPY="${_BINPREFIX}objcopy", - RANLIB="${_BINPREFIX}ranlib", - SIZETOOL="${_BINPREFIX}size", - - SIZEPRINTCMD='"$SIZETOOL" $SOURCES' -) - -if get_systype() == "darwin_x86_64": - env.Replace( - _BINPREFIX="x86_64-pc-linux-" - ) - -# -# Target: Build executable program -# - -target_bin = env.BuildProgram() - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_bin, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Define targets -# - -Default([target_bin]) diff --git a/platformio/builder/scripts/microchippic32.py b/platformio/builder/scripts/microchippic32.py deleted file mode 100644 index 01695a96..00000000 --- a/platformio/builder/scripts/microchippic32.py +++ /dev/null @@ -1,190 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for Microchip PIC32 microcontrollers -""" - -from os.path import join - -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Builder, Default, - DefaultEnvironment) - - -def BeforeUpload(target, source, env): # pylint: disable=W0613,W0621 - - env.AutodetectUploadPort() - env.Prepend(UPLOADERFLAGS=["-d", '"$UPLOAD_PORT"']) - -env = DefaultEnvironment() - -env.Replace( - AR="pic32-ar", - AS="pic32-as", - CC="pic32-gcc", - CXX="pic32-g++", - OBJCOPY="pic32-objcopy", - RANLIB="pic32-ranlib", - SIZETOOL="pic32-size", - - ARFLAGS=["rcs"], - - ASFLAGS=[ - "-g1", - "-O2", - "-Wa,--gdwarf-2", - "-mprocessor=$BOARD_MCU" - ], - - CCFLAGS=[ - "-w", - "-g", - "-O2", - "-MMD", - "-mdebugger", - "-mno-smart-io", - "-mprocessor=$BOARD_MCU", - "-ffunction-sections", - "-fdata-sections", - "-Wcast-align", - "-fno-short-double", - "-ftoplevel-reorder" - ], - - CXXFLAGS=["-fno-exceptions"], - - CPPDEFINES=[ - "F_CPU=$BOARD_F_CPU", - "MPIDEVER=16777998", - "MPIDE=150" - ], - - LINKFLAGS=[ - "-w", - "-Os", - "-mdebugger", - "-mprocessor=$BOARD_MCU", - "-mno-peripheral-libs", - "-nostartfiles", - "-Wl,--gc-sections" - ], - - LIBS=["m"], - - SIZEPRINTCMD='"$SIZETOOL" -B -d $SOURCES', - - UPLOADER=join("$PIOPACKAGES_DIR", "tool-pic32prog", "pic32prog"), - UPLOADERFLAGS=[ - "-b", "$UPLOAD_SPEED" - ], - UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS $SOURCES', - - PROGNAME="firmware", - PROGSUFFIX=".elf" -) - -if int(env.get("BOARD_OPTIONS", {}).get( - "upload", {}).get("maximum_ram_size", 0)) < 65535: - env.Append( - CCFLAGS=["-G1024"] - ) - - -env.Append( - BUILDERS=dict( - ElfToEep=Builder( - action=" ".join([ - "$OBJCOPY", - "-O", - "ihex", - "-j", - ".eeprom", - '--set-section-flags=.eeprom="alloc,load"', - "--no-change-warnings", - "--change-section-lma", - ".eeprom=0", - "$SOURCES", - "$TARGET"]), - suffix=".eep" - ), - - ElfToHex=Builder( - action=" ".join([ - "$OBJCOPY", - "-O", - "ihex", - "-R", - ".eeprom", - "$SOURCES", - "$TARGET"]), - suffix=".hex" - ) - ) -) - -# -# Target: Build executable and linkable firmware -# - -target_elf = env.BuildProgram() - -# -# Hook: Fix option for LD script -# - -_new_linkflags = [] -for f in env['LINKFLAGS']: - if not f.startswith("-Wl,-T"): - _new_linkflags.append(f) - else: - _new_linkflags.append("-Wl,--script=%s" % f[6:]) - -env.Replace(LINKFLAGS=_new_linkflags) -env.Append( - LINKFLAGS=[ - "-Wl,--script=chipKIT-application-COMMON%s.ld" % ( - "-MZ" if "MZ" in env.get("BOARD_OPTIONS", {}).get( - "build", {}).get("mcu") else "") - ] -) - -# -# Target: Build the .hex -# - -if "uploadlazy" in COMMAND_LINE_TARGETS: - target_firm = join("$BUILD_DIR", "firmware.hex") -else: - target_firm = env.ElfToHex(join("$BUILD_DIR", "firmware"), target_elf) - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_elf, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Upload firmware -# - -upload = env.Alias( - ["upload", "uploadlazy"], target_firm, [BeforeUpload, "$UPLOADCMD"]) -AlwaysBuild(upload) - -# -# Target: Define targets -# - -Default([target_firm, target_size]) diff --git a/platformio/builder/scripts/native.py b/platformio/builder/scripts/native.py deleted file mode 100644 index 41259514..00000000 --- a/platformio/builder/scripts/native.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for native platform -""" - -from SCons.Script import AlwaysBuild, Default, DefaultEnvironment - -env = DefaultEnvironment() - -env.Replace( - SIZEPRINTCMD="size $SOURCES" -) - -# -# Target: Build executable program -# - -target_bin = env.BuildProgram() - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_bin, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Define targets -# - -Default([target_bin]) diff --git a/platformio/builder/scripts/nordicnrf51.py b/platformio/builder/scripts/nordicnrf51.py deleted file mode 100644 index a39e94fa..00000000 --- a/platformio/builder/scripts/nordicnrf51.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for Nordic nRF51 series ARM microcontrollers. -""" - -from os.path import join - -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Default, - DefaultEnvironment, SConscript) - -env = DefaultEnvironment() - -SConscript(env.subst(join("$PIOBUILDER_DIR", "scripts", "basearm.py"))) - -if env.subst("$BOARD") == "rfduino": - env.Append( - CCFLAGS=["-fno-builtin"], - LINKFLAGS=["--specs=nano.specs"] - ) - env.Replace( - UPLOADER=join("$PIOPACKAGES_DIR", "tool-rfdloader", "rfdloader"), - UPLOADERFLAGS=["-q", '"$UPLOAD_PORT"'], - UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS $SOURCES' - ) - -# -# Target: Build executable and linkable firmware -# - -target_elf = env.BuildProgram() - -# -# Target: Build the .bin file -# - -if "uploadlazy" in COMMAND_LINE_TARGETS: - target_firm = join("$BUILD_DIR", "firmware.hex") -else: - target_firm = env.ElfToHex(join("$BUILD_DIR", "firmware"), target_elf) - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_elf, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Upload by default .bin file -# - -if env.subst("$BOARD") == "rfduino": - upload = env.Alias( - ["upload", "uploadlazy"], target_firm, - [lambda target, source, env: env.AutodetectUploadPort(), "$UPLOADCMD"]) -else: - upload = env.Alias(["upload", "uploadlazy"], target_firm, env.UploadToDisk) -AlwaysBuild(upload) - -# -# Target: Define targets -# - -Default([target_firm, target_size]) diff --git a/platformio/builder/scripts/nxplpc.py b/platformio/builder/scripts/nxplpc.py deleted file mode 100644 index a3f5eed3..00000000 --- a/platformio/builder/scripts/nxplpc.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for NXP LPC series ARM microcontrollers. -""" - -from os.path import join -from shutil import copyfile - -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Default, - DefaultEnvironment, SConscript) - - -def UploadToDisk(target, source, env): # pylint: disable=W0613,W0621 - env.AutodetectUploadPort() - copyfile(join(env.subst("$BUILD_DIR"), "firmware.bin"), - join(env.subst("$UPLOAD_PORT"), "firmware.bin")) - print("Firmware has been successfully uploaded.\n" - "Please restart your board.") - -env = DefaultEnvironment() - -SConscript(env.subst(join("$PIOBUILDER_DIR", "scripts", "basearm.py"))) - -# -# Target: Build executable and linkable firmware -# - -target_elf = env.BuildProgram() - -# -# Target: Build the .bin file -# - -if "uploadlazy" in COMMAND_LINE_TARGETS: - target_firm = join("$BUILD_DIR", "firmware.bin") -else: - target_firm = env.ElfToBin(join("$BUILD_DIR", "firmware"), target_elf) - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_elf, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Upload by default .bin file -# - -upload = env.Alias(["upload", "uploadlazy"], target_firm, UploadToDisk) -AlwaysBuild(upload) - -# -# Target: Define targets -# - -Default([target_firm, target_size]) diff --git a/platformio/builder/scripts/siliconlabsefm32.py b/platformio/builder/scripts/siliconlabsefm32.py deleted file mode 100644 index ca2d617d..00000000 --- a/platformio/builder/scripts/siliconlabsefm32.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for Silicon Labs EFM32 series ARM microcontrollers. -""" - -from os.path import join - -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Default, - DefaultEnvironment, SConscript) - -env = DefaultEnvironment() - -SConscript(env.subst(join("$PIOBUILDER_DIR", "scripts", "basearm.py"))) - -# -# Target: Build executable and linkable firmware -# - -target_elf = env.BuildProgram() - -# -# Target: Build the .bin file -# - -if "uploadlazy" in COMMAND_LINE_TARGETS: - target_firm = join("$BUILD_DIR", "firmware.bin") -else: - target_firm = env.ElfToBin(join("$BUILD_DIR", "firmware"), target_elf) - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_elf, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Upload by default .bin file -# - -upload = env.Alias(["upload", "uploadlazy"], target_firm, env.UploadToDisk) -AlwaysBuild(upload) - -# -# Target: Define targets -# - -Default([target_firm, target_size]) diff --git a/platformio/builder/scripts/ststm32.py b/platformio/builder/scripts/ststm32.py deleted file mode 100644 index 34eee8d8..00000000 --- a/platformio/builder/scripts/ststm32.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for ST STM32 Series ARM microcontrollers. -""" - -from os.path import isfile, join - -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Default, - DefaultEnvironment, SConscript) - -env = DefaultEnvironment() - -SConscript(env.subst(join("$PIOBUILDER_DIR", "scripts", "basearm.py"))) - -if env.subst("$UPLOAD_PROTOCOL") == "gdb": - if not isfile(join(env.subst("$PROJECT_DIR"), "upload.gdb")): - env.Exit( - "Error: You are using GDB as firmware uploader. " - "Please specify upload commands in upload.gdb " - "file in project directory!" - ) - env.Replace( - UPLOADER=join( - "$PIOPACKAGES_DIR", "toolchain-gccarmnoneeabi", - "bin", "arm-none-eabi-gdb" - ), - UPLOADERFLAGS=[ - join("$BUILD_DIR", "firmware.elf"), - "-batch", - "-x", - '"%s"' % join("$PROJECT_DIR", "upload.gdb") - ], - - UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS' - ) -else: - env.Replace( - UPLOADER=join("$PIOPACKAGES_DIR", "tool-stlink", "st-flash"), - UPLOADERFLAGS=[ - "write", # write in flash - "$SOURCES", # firmware path to flash - "0x08000000" # flash start adress - ], - - UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS' - ) - - -env.Append( - CPPDEFINES=[ - env.get("BOARD_OPTIONS", {}).get( - "build", {}).get("variant", "").upper() - ], - - LIBS=["stdc++", "nosys"], - - LINKFLAGS=[ - "-nostartfiles", - "-nostdlib" - ] -) - -# -# Target: Build executable and linkable firmware -# - -target_elf = env.BuildProgram() - -# -# Target: Build the .bin file -# - -if "uploadlazy" in COMMAND_LINE_TARGETS: - target_firm = join("$BUILD_DIR", "firmware.bin") -else: - target_firm = env.ElfToBin(join("$BUILD_DIR", "firmware"), target_elf) - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_elf, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Upload by default .bin file -# - -if "mbed" in env.subst("$FRAMEWORK") and not env.subst("$UPLOAD_PROTOCOL"): - upload = env.Alias(["upload", "uploadlazy"], - target_firm, env.UploadToDisk) -else: - upload = env.Alias(["upload", "uploadlazy"], target_firm, "$UPLOADCMD") -AlwaysBuild(upload) - -# -# Target: Define targets -# - -Default([target_firm, target_size]) diff --git a/platformio/builder/scripts/teensy.py b/platformio/builder/scripts/teensy.py deleted file mode 100644 index 43e293f3..00000000 --- a/platformio/builder/scripts/teensy.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for Teensy boards -""" - -from os.path import isfile, join - -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Default, - DefaultEnvironment, SConscript) - -env = DefaultEnvironment() - -if env.get("BOARD_OPTIONS", {}).get("build", {}).get("core") == "teensy": - SConscript(env.subst(join("$PIOBUILDER_DIR", "scripts", "baseavr.py"))) -elif env.get("BOARD_OPTIONS", {}).get("build", {}).get("core") == "teensy3": - SConscript(env.subst(join("$PIOBUILDER_DIR", "scripts", "basearm.py"))) - env.Append( - LINKFLAGS=[ - "-Wl,--defsym=__rtc_localtime=$UNIX_TIME", - "-fsingle-precision-constant", - "--specs=nano.specs" - ], - CCFLAGS=[ - "-fsingle-precision-constant" - ] - ) - -env.Append( - CPPDEFINES=[ - "USB_SERIAL", - "LAYOUT_US_ENGLISH" - ], - - CXXFLAGS=[ - "-std=gnu++0x", - "-felide-constructors" - ] -) - -if isfile(env.subst(join( - "$PIOPACKAGES_DIR", "tool-teensy", "teensy_loader_cli"))): - env.Append( - UPLOADER=join( - "$PIOPACKAGES_DIR", "tool-teensy", "teensy_loader_cli"), - UPLOADERFLAGS=[ - "-mmcu=$BOARD_MCU", - "-w", # wait for device to apear - "-s", # soft reboot if device not online - "-v" # verbose output - ], - UPLOADHEXCMD='"$UPLOADER" $UPLOADERFLAGS $SOURCES' - ) -else: - env.Append( - REBOOTER=join( - "$PIOPACKAGES_DIR", "tool-teensy", "teensy_reboot"), - UPLOADER=join( - "$PIOPACKAGES_DIR", "tool-teensy", "teensy_post_compile"), - UPLOADERFLAGS=[ - "-file=firmware", - '-path="$BUILD_DIR"', - '-tools="%s"' % join("$PIOPACKAGES_DIR", "tool-teensy") - ], - UPLOADHEXCMD='"$UPLOADER" $UPLOADERFLAGS' - ) - -# -# Target: Build executable and linkable firmware -# - -target_elf = env.BuildProgram() - -# -# Target: Build the firmware file -# - -if "uploadlazy" in COMMAND_LINE_TARGETS: - target_firm = join("$BUILD_DIR", "firmware.hex") -else: - target_firm = env.ElfToHex(join("$BUILD_DIR", "firmware"), target_elf) - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_elf, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Upload by default firmware file -# - -upload = env.Alias( - ["upload", "uploadlazy"], target_firm, - ["$UPLOADHEXCMD"] + (["$REBOOTER"] if "REBOOTER" in env else [])) -AlwaysBuild(upload) - -# -# Target: Define targets -# - -Default([target_firm, target_size]) diff --git a/platformio/builder/scripts/timsp430.py b/platformio/builder/scripts/timsp430.py deleted file mode 100644 index a0cd720c..00000000 --- a/platformio/builder/scripts/timsp430.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for Texas Instruments - MSP430 Ultra-Low Power 16-bit microcontrollers -""" - -from os.path import join -from platform import system - -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Builder, Default, - DefaultEnvironment) - -env = DefaultEnvironment() - -env.Replace( - AR="msp430-ar", - AS="msp430-as", - CC="msp430-gcc", - CXX="msp430-g++", - OBJCOPY="msp430-objcopy", - RANLIB="msp430-ranlib", - SIZETOOL="msp430-size", - - ARFLAGS=["rcs"], - - ASFLAGS=["-x", "assembler-with-cpp"], - - CCFLAGS=[ - "-g", # include debugging info (so errors include line numbers) - "-Os", # optimize for size - # "-Wall", # show warnings - "-ffunction-sections", # place each function in its own section - "-fdata-sections", - "-mmcu=$BOARD_MCU" - ], - - CPPDEFINES=[ - "F_CPU=$BOARD_F_CPU" - ], - - LINK="$CC", - LINKFLAGS=[ - "-Os", - "-mmcu=$BOARD_MCU", - "-Wl,-gc-sections,-u,main" - ], - - LIBS=["m"], - - SIZEPRINTCMD='"$SIZETOOL" -B -d $SOURCES', - - UPLOADER=join("$PIOPACKAGES_DIR", "tool-mspdebug", "mspdebug"), - UPLOADERFLAGS=[ - "$UPLOAD_PROTOCOL" if system() != "Windows" else "tilib", - "--force-reset" - ], - UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS "prog $SOURCES"', - - PROGNAME="firmware", - PROGSUFFIX=".elf" -) - -env.Append( - ASFLAGS=env.get("CCFLAGS", [])[:], - - BUILDERS=dict( - ElfToHex=Builder( - action=" ".join([ - "$OBJCOPY", - "-O", - "ihex", - "-R", - ".eeprom", - "$SOURCES", - "$TARGET"]), - suffix=".hex" - ) - ) -) - -# -# Target: Build executable and linkable firmware -# - -target_elf = env.BuildProgram() - -# -# Target: Build the .hex -# - -if "uploadlazy" in COMMAND_LINE_TARGETS: - target_firm = join("$BUILD_DIR", "firmware.hex") -else: - target_firm = env.ElfToHex(join("$BUILD_DIR", "firmware"), target_elf) - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_elf, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Upload firmware -# - -upload = env.Alias(["upload", "uploadlazy"], target_firm, "$UPLOADCMD") -AlwaysBuild(upload) - -# -# Target: Define targets -# - -Default([target_firm, target_size]) diff --git a/platformio/builder/scripts/titiva.py b/platformio/builder/scripts/titiva.py deleted file mode 100644 index e705cd62..00000000 --- a/platformio/builder/scripts/titiva.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for Texas Instruments - Tiva C Series ARM Cortex-M4 microcontrollers. -""" - -from os.path import join - -from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Default, - DefaultEnvironment, SConscript) - -env = DefaultEnvironment() - -SConscript(env.subst(join("$PIOBUILDER_DIR", "scripts", "basearm.py"))) - -env.Replace( - UPLOADER=join("$PIOPACKAGES_DIR", "tool-lm4flash", "lm4flash"), - UPLOADCMD='"$UPLOADER" $SOURCES' -) - -env.Append( - LINKFLAGS=[ - "-nostartfiles", - "-nostdlib" - ] -) - -# -# Target: Build executable and linkable firmware -# - -target_elf = env.BuildProgram() - -# -# Target: Build the .bin file -# - -if "uploadlazy" in COMMAND_LINE_TARGETS: - target_firm = join("$BUILD_DIR", "firmware.bin") -else: - target_firm = env.ElfToBin(join("$BUILD_DIR", "firmware"), target_elf) - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_elf, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Upload firmware -# - -upload = env.Alias(["upload", "uploadlazy"], target_firm, "$UPLOADCMD") -AlwaysBuild(upload) - -# -# Target: Define targets -# - -Default([target_firm, target_size]) diff --git a/platformio/builder/scripts/windows_x86.py b/platformio/builder/scripts/windows_x86.py deleted file mode 100644 index db78f6c1..00000000 --- a/platformio/builder/scripts/windows_x86.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. - -""" - Builder for Windows x86 / 32bit -""" - -from SCons.Script import AlwaysBuild, Default, DefaultEnvironment - -from platformio.util import get_systype - -env = DefaultEnvironment() - -env.Replace( - _BINPREFIX="", - AR="${_BINPREFIX}ar", - AS="${_BINPREFIX}as", - CC="${_BINPREFIX}gcc", - CXX="${_BINPREFIX}g++", - OBJCOPY="${_BINPREFIX}objcopy", - RANLIB="${_BINPREFIX}ranlib", - SIZETOOL="${_BINPREFIX}size", - - SIZEPRINTCMD='"$SIZETOOL" $SOURCES', - PROGSUFFIX=".exe" -) - -if get_systype() == "darwin_x86_64": - env.Replace( - _BINPREFIX="i586-mingw32-" - ) -elif get_systype() in ("linux_x86_64", "linux_i686"): - env.Replace( - _BINPREFIX="i686-w64-mingw32-" - ) - -# -# Target: Build executable program -# - -target_bin = env.BuildProgram() - -# -# Target: Print binary size -# - -target_size = env.Alias("size", target_bin, "$SIZEPRINTCMD") -AlwaysBuild(target_size) - -# -# Target: Define targets -# - -Default([target_bin]) diff --git a/platformio/commands/platforms.py b/platformio/commands/platform.py similarity index 100% rename from platformio/commands/platforms.py rename to platformio/commands/platform.py diff --git a/platformio/pkgmanager.py b/platformio/managers/package.py similarity index 100% rename from platformio/pkgmanager.py rename to platformio/managers/package.py diff --git a/platformio/platforms/base.py b/platformio/managers/platform.py similarity index 100% rename from platformio/platforms/base.py rename to platformio/managers/platform.py diff --git a/platformio/platforms/__init__.py b/platformio/platforms/__init__.py deleted file mode 100644 index 0c05c3b0..00000000 --- a/platformio/platforms/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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. diff --git a/platformio/platforms/atmelavr.py b/platformio/platforms/atmelavr.py deleted file mode 100644 index 62fef55d..00000000 --- a/platformio/platforms/atmelavr.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform -from platformio.util import get_boards - - -class AtmelavrPlatform(BasePlatform): - - """ - Atmel AVR 8- and 32-bit MCUs deliver a unique combination of - performance, power efficiency and design flexibility. Optimized to - speed time to market-and easily adapt to new ones-they are based on - the industrys most code-efficient architecture for C and assembly - programming. - - http://www.atmel.com/products/microcontrollers/avr/default.aspx - """ - - PACKAGES = { - - "toolchain-atmelavr": { - "alias": "toolchain", - "default": True - }, - - "tool-avrdude": { - "alias": "uploader" - }, - - "tool-micronucleus": { - "alias": "uploader" - }, - - "framework-arduinoavr": { - "alias": "framework" - }, - - "framework-simba": { - "alias": "framework" - } - } - - def get_name(self): - return "Atmel AVR" - - def configure_default_packages(self, envoptions, targets): - if envoptions.get("board"): - board = get_boards(envoptions.get("board")) - disable_tool = "tool-micronucleus" - if "digispark" in board['build']['core']: - disable_tool = "tool-avrdude" - del self.PACKAGES[disable_tool]['alias'] - - return BasePlatform.configure_default_packages( - self, envoptions, targets) - - def on_run_err(self, line): # pylint: disable=R0201 - # fix STDERR "flash written" for avrdude - if "avrdude" in line: - self.on_run_out(line) - else: - BasePlatform.on_run_err(self, line) diff --git a/platformio/platforms/atmelsam.py b/platformio/platforms/atmelsam.py deleted file mode 100644 index 0e8d7da2..00000000 --- a/platformio/platforms/atmelsam.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform - - -class AtmelsamPlatform(BasePlatform): - - """ - Atmel | SMART offers Flash- based ARM products based on the ARM - Cortex-M0+, Cortex-M3 and Cortex-M4 architectures, ranging from 8KB - to 2MB of Flash including a rich peripheral and feature mix. - - http://www.atmel.com/products/microcontrollers/arm/default.aspx - """ - - PACKAGES = { - - "toolchain-gccarmnoneeabi": { - "alias": "toolchain", - "default": True - }, - - "ldscripts": { - "default": True - }, - - "framework-arduinosam": { - "alias": "framework" - }, - - "framework-mbed": { - "alias": "framework" - }, - - "framework-simba": { - "alias": "framework" - }, - - "tool-bossac": { - "alias": "uploader" - }, - - "tool-openocd": { - "alias": "uploader" - } - } - - def get_name(self): - return "Atmel SAM" diff --git a/platformio/platforms/espressif.py b/platformio/platforms/espressif.py deleted file mode 100644 index 97d95c10..00000000 --- a/platformio/platforms/espressif.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform - - -class EspressifPlatform(BasePlatform): - - """ - Espressif Systems is a privately held fabless semiconductor company. - They provide wireless communications and Wi-Fi chips which are widely - used in mobile devices and the Internet of Things applications. - - https://espressif.com/ - """ - - PACKAGES = { - - "toolchain-xtensa": { - "alias": "toolchain", - "default": True - }, - - "ldscripts": { - "default": True - }, - - "tool-esptool": { - "alias": "uploader", - "default": True - }, - - "tool-mkspiffs": { - "alias": "uploader" - }, - - "sdk-esp8266": { - }, - - "framework-arduinoespressif": { - "alias": "framework" - }, - - "framework-simba": { - "alias": "framework" - } - } - - def get_name(self): - return "Espressif" - - def configure_default_packages(self, envoptions, targets): - if not envoptions.get("framework"): - self.PACKAGES['sdk-esp8266']['default'] = True - - return BasePlatform.configure_default_packages( - self, envoptions, targets) diff --git a/platformio/platforms/freescalekinetis.py b/platformio/platforms/freescalekinetis.py deleted file mode 100644 index 47e387d0..00000000 --- a/platformio/platforms/freescalekinetis.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform - - -class FreescalekinetisPlatform(BasePlatform): - - """ - Freescale Kinetis Microcontrollers is family of multiple hardware- and - software-compatible ARM Cortex-M0+, Cortex-M4 and Cortex-M7-based MCU - series. Kinetis MCUs offer exceptional low-power performance, - scalability and feature integration. - - http://www.freescale.com/webapp/sps/site/homepage.jsp?code=KINETIS - """ - - PACKAGES = { - - "toolchain-gccarmnoneeabi": { - "alias": "toolchain", - "default": True - }, - - "framework-mbed": { - "alias": "framework" - } - } - - def get_name(self): - return "Freescale Kinetis" diff --git a/platformio/platforms/intel_arc32.py b/platformio/platforms/intel_arc32.py deleted file mode 100644 index a0aa7535..00000000 --- a/platformio/platforms/intel_arc32.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform - - -class Intel_arc32Platform(BasePlatform): - - """ - ARC embedded processors are a family of 32-bit CPUs that are widely used - in SoC devices for storage, home, mobile, automotive, and Internet of - Things applications. - - http://www.intel.com/content/www/us/en/wearables/wearable-soc.html - """ - - PACKAGES = { - - "toolchain-intelarc32": { - "alias": "toolchain", - "default": True - }, - - "framework-arduinointel": { - "alias": "framework" - }, - - "tool-arduino101load": { - "alias": "uploader" - }, - } - - def get_name(self): - return "Intel ARC32" diff --git a/platformio/platforms/lattice_ice40.py b/platformio/platforms/lattice_ice40.py deleted file mode 100755 index 35d41ed8..00000000 --- a/platformio/platforms/lattice_ice40.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform - - -class Lattice_ice40Platform(BasePlatform): - - """ - The iCE40 family of ultra-low power, non-volatile FPGAs has five devices - with densities ranging from 384 to 7680 Look-Up Tables (LUTs). In addition - to LUT-based,low-cost programmable logic, these devices feature Embedded - Block RAM (EBR), Non-volatile Configuration Memory (NVCM) and Phase Locked - Loops (PLLs). These features allow the devices to be used in low-cost, - high-volume consumer and system applications. - - http://www.latticesemi.com/Products/FPGAandCPLD/iCE40.aspx - """ - - PACKAGES = { - - "toolchain-icestorm": { - "alias": "toolchain", - "default": True - } - } - - def get_name(self): - return "Lattice iCE40" - - def is_embedded(self): - return True diff --git a/platformio/platforms/linux_arm.py b/platformio/platforms/linux_arm.py deleted file mode 100644 index 79c03ad5..00000000 --- a/platformio/platforms/linux_arm.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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, util -from platformio.platforms.base import BasePlatform - - -class Linux_armPlatform(BasePlatform): - - """ - Linux ARM is a Unix-like and mostly POSIX-compliant computer - operating system (OS) assembled under the model of free and open-source - software development and distribution. - - Using host OS (Mac OS X, Linux ARM) you can build native application - for Linux ARM platform. - - http://platformio.org/platforms/linux_arm - """ - - PACKAGES = { - - "toolchain-gccarmlinuxgnueabi": { - "alias": "toolchain", - "default": True - }, - - "framework-wiringpi": { - "alias": "framework" - } - } - - def __init__(self): - if "linux_arm" in util.get_systype(): - del self.PACKAGES['toolchain-gccarmlinuxgnueabi'] - BasePlatform.__init__(self) - - def configure_default_packages(self, envoptions, targets): - if (envoptions.get("framework") == "wiringpi" and - "linux_arm" not in util.get_systype()): - raise exception.PlatformioException( - "PlatformIO does not support temporary cross-compilation " - "for WiringPi framework. Please run PlatformIO directly on " - "Raspberry Pi" - ) - - return BasePlatform.configure_default_packages( - self, envoptions, targets) diff --git a/platformio/platforms/linux_i686.py b/platformio/platforms/linux_i686.py deleted file mode 100644 index 11f1ac01..00000000 --- a/platformio/platforms/linux_i686.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform -from platformio.util import get_systype - - -class Linux_i686Platform(BasePlatform): - - """ - Linux i686 (32-bit) is a Unix-like and mostly POSIX-compliant - computer operating system (OS) assembled under the model of free and - open-source software development and distribution. - - Using host OS (Mac OS X or Linux 32-bit) you can build native - application for Linux i686 platform. - - http://platformio.org/platforms/linux_i686 - """ - - PACKAGES = { - - "toolchain-gcclinux32": { - "alias": "toolchain", - "default": True - } - } - - def __init__(self): - if get_systype() == "linux_i686": - del self.PACKAGES['toolchain-gcclinux32'] - BasePlatform.__init__(self) diff --git a/platformio/platforms/linux_x86_64.py b/platformio/platforms/linux_x86_64.py deleted file mode 100644 index c3bf330e..00000000 --- a/platformio/platforms/linux_x86_64.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform -from platformio.util import get_systype - - -class Linux_x86_64Platform(BasePlatform): - - """ - Linux x86_64 (64-bit) is a Unix-like and mostly POSIX-compliant - computer operating system (OS) assembled under the model of free and - open-source software development and distribution. - - Using host OS (Mac OS X or Linux 64-bit) you can build native - application for Linux x86_64 platform. - - http://platformio.org/platforms/linux_i686 - """ - - PACKAGES = { - - "toolchain-gcclinux64": { - "alias": "toolchain", - "default": True - } - } - - def __init__(self): - if get_systype() == "linux_x86_64": - del self.PACKAGES['toolchain-gcclinux64'] - BasePlatform.__init__(self) diff --git a/platformio/platforms/microchippic32.py b/platformio/platforms/microchippic32.py deleted file mode 100644 index 22888125..00000000 --- a/platformio/platforms/microchippic32.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform - - -class Microchippic32Platform(BasePlatform): - - """ - Microchip's 32-bit portfolio with the MIPS microAptiv or M4K core offer - high performance microcontrollers, and all the tools needed to develop - your embedded projects. PIC32 MCUs gives your application the processing - power, memory and peripherals your design needs! - - http://www.microchip.com/design-centers/32-bit - """ - - PACKAGES = { - - "toolchain-microchippic32": { - "alias": "toolchain", - "default": True - }, - - "framework-arduinomicrochippic32": { - "alias": "framework" - }, - - "tool-pic32prog": { - "alias": "uploader" - } - } - - def get_name(self): - return "Microchip PIC32" diff --git a/platformio/platforms/native.py b/platformio/platforms/native.py deleted file mode 100644 index 9c4ed8bb..00000000 --- a/platformio/platforms/native.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform - - -class NativePlatform(BasePlatform): - - """ - Native development platform is intended to be used for desktop OS. - This platform uses built-in toolchains (preferable based on GCC), - frameworks, libs from particular OS where it will be run. - - http://platformio.org/platforms/native - """ - - PACKAGES = { - } diff --git a/platformio/platforms/nordicnrf51.py b/platformio/platforms/nordicnrf51.py deleted file mode 100644 index b68e240b..00000000 --- a/platformio/platforms/nordicnrf51.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform - - -class Nordicnrf51Platform(BasePlatform): - - """ - The Nordic nRF51 Series is a family of highly flexible, - multi-protocol, system-on-chip (SoC) devices for ultra-low power - wireless applications. nRF51 Series devices support a range of - protocol stacks including Bluetooth Smart (previously called - Bluetooth low energy), ANT and proprietary 2.4GHz protocols such as - Gazell. - - https://www.nordicsemi.com/eng/Products/nRF51-Series-SoC - """ - - PACKAGES = { - - "toolchain-gccarmnoneeabi": { - "alias": "toolchain", - "default": True - }, - - "framework-mbed": { - "alias": "framework" - }, - - "framework-arduinonordicnrf51": { - "alias": "framework" - }, - - "tool-rfdloader": { - } - } - - def get_name(self): - return "Nordic nRF51" - - def configure_default_packages(self, envoptions, targets): - if envoptions.get("board") == "rfduino": - self.PACKAGES['tool-rfdloader']['alias'] = "uploader" - - return BasePlatform.configure_default_packages( - self, envoptions, targets) diff --git a/platformio/platforms/nxplpc.py b/platformio/platforms/nxplpc.py deleted file mode 100644 index d359b117..00000000 --- a/platformio/platforms/nxplpc.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform - - -class NxplpcPlatform(BasePlatform): - - """ - The NXP LPC is a family of 32-bit microcontroller integrated circuits - by NXP Semiconductors. The LPC chips are grouped into related series - that are based around the same 32-bit ARM processor core, such as the - Cortex-M4F, Cortex-M3, Cortex-M0+, or Cortex-M0. Internally, each - microcontroller consists of the processor core, static RAM memory, - flash memory, debugging interface, and various peripherals. - - http://www.nxp.com/products/microcontrollers/ - """ - - PACKAGES = { - - "toolchain-gccarmnoneeabi": { - "alias": "toolchain", - "default": True - }, - - "framework-mbed": { - "alias": "framework" - } - } - - def get_name(self): - return "NXP LPC" diff --git a/platformio/platforms/siliconlabsefm32.py b/platformio/platforms/siliconlabsefm32.py deleted file mode 100644 index 8aa642ea..00000000 --- a/platformio/platforms/siliconlabsefm32.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform - - -class Siliconlabsefm32Platform(BasePlatform): - - """ - Silicon Labs EFM32 Gecko 32-bit microcontroller (MCU) family includes - devices that offer flash memory configurations up to 256 kB, 32 kB of - RAM and CPU speeds up to 48 MHz. - - Based on the powerful ARM Cortex-M core, the Gecko family features - innovative low energy techniques, short wake-up time from energy saving - modes and a wide selection of peripherals, making it ideal for battery - operated applications and other systems requiring high performance and - low-energy consumption. - - http://www.silabs.com/products/mcu/32-bit/efm32-gecko/Pages/efm32-gecko.aspx - """ - - PACKAGES = { - - "toolchain-gccarmnoneeabi": { - "alias": "toolchain", - "default": True - }, - - "framework-mbed": { - "alias": "framework" - } - } - - def get_name(self): - return "Silicon Labs EFM32" diff --git a/platformio/platforms/ststm32.py b/platformio/platforms/ststm32.py deleted file mode 100644 index 10203ec4..00000000 --- a/platformio/platforms/ststm32.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform - - -class Ststm32Platform(BasePlatform): - - """ - The STM32 family of 32-bit Flash MCUs based on the ARM Cortex-M - processor is designed to offer new degrees of freedom to MCU users. - It offers a 32-bit product range that combines very high performance, - real-time capabilities, digital signal processing, and low-power, - low-voltage operation, while maintaining full integration and ease of - development. - - http://www.st.com/web/en/catalog/mmc/FM141/SC1169?sc=stm32 - """ - - PACKAGES = { - - "toolchain-gccarmnoneeabi": { - "alias": "toolchain", - "default": True - }, - - "ldscripts": { - "default": True - }, - - "tool-stlink": { - "alias": "uploader" - }, - - "framework-cmsis": { - "alias": "framework" - }, - - "framework-spl": { - "alias": "framework" - }, - - "framework-libopencm3": { - "alias": "framework" - }, - - "framework-mbed": { - "alias": "framework" - } - } - - def get_name(self): - return "ST STM32" - - def configure_default_packages(self, envoptions, targets): - if envoptions.get("framework") == "cmsis": - self.PACKAGES['framework-mbed']['default'] = True - - return BasePlatform.configure_default_packages( - self, envoptions, targets) diff --git a/platformio/platforms/teensy.py b/platformio/platforms/teensy.py deleted file mode 100644 index 45e62562..00000000 --- a/platformio/platforms/teensy.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform -from platformio.util import get_boards - - -class TeensyPlatform(BasePlatform): - - """ - Teensy is a complete USB-based microcontroller development system, in - a very small footprint, capable of implementing many types of projects. - All programming is done via the USB port. No special programmer is - needed, only a standard USB cable and a PC or Macintosh with a USB port. - - https://www.pjrc.com/teensy - """ - - PACKAGES = { - - "toolchain-atmelavr": { - }, - - "toolchain-gccarmnoneeabi": { - }, - - "ldscripts": { - "default": True - }, - - "framework-arduinoteensy": { - "alias": "framework" - }, - - "framework-mbed": { - "alias": "framework" - }, - - "tool-teensy": { - "alias": "uploader" - } - } - - def get_name(self): - return "Teensy" - - def configure_default_packages(self, envoptions, targets): - if envoptions.get("board"): - board = get_boards(envoptions.get("board")) - if board['build']['core'] == "teensy": - name = "toolchain-atmelavr" - else: - name = "toolchain-gccarmnoneeabi" - self.PACKAGES[name]['alias'] = "toolchain" - self.PACKAGES[name]['default'] = True - - return BasePlatform.configure_default_packages( - self, envoptions, targets) diff --git a/platformio/platforms/timsp430.py b/platformio/platforms/timsp430.py deleted file mode 100644 index e3ce6ee4..00000000 --- a/platformio/platforms/timsp430.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform - - -class Timsp430Platform(BasePlatform): - - """ - MSP430 microcontrollers (MCUs) from Texas Instruments (TI) - are 16-bit, RISC-based, mixed-signal processors designed for ultra-low - power. These MCUs offer the lowest power consumption and the perfect - mix of integrated peripherals for thousands of applications. - - http://www.ti.com/lsds/ti/microcontrollers_16-bit_32-bit/msp/overview.page - """ - - PACKAGES = { - - "toolchain-timsp430": { - "alias": "toolchain", - "default": True - }, - - "tool-mspdebug": { - "alias": "uploader" - }, - - "framework-energiamsp430": { - "alias": "framework" - }, - - "framework-arduinomsp430": { - "alias": "framework" - } - } - - def get_name(self): - return "TI MSP430" diff --git a/platformio/platforms/titiva.py b/platformio/platforms/titiva.py deleted file mode 100644 index fbe4981e..00000000 --- a/platformio/platforms/titiva.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform - - -class TitivaPlatform(BasePlatform): - - """ - Texas Instruments TM4C12x MCUs offer the industrys most popular - ARM Cortex-M4 core with scalable memory and package options, unparalleled - connectivity peripherals, advanced application functions, industry-leading - analog integration, and extensive software solutions. - - http://www.ti.com/lsds/ti/microcontrollers_16-bit_32-bit/c2000_performance/control_automation/tm4c12x/overview.page - """ - - PACKAGES = { - - "toolchain-gccarmnoneeabi": { - "alias": "toolchain", - "default": True - }, - - "ldscripts": { - "default": True - }, - - "tool-lm4flash": { - "alias": "uploader" - }, - - "framework-energiativa": { - "alias": "framework" - }, - - "framework-libopencm3": { - "alias": "framework" - } - } - - def get_name(self): - return "TI TIVA" diff --git a/platformio/platforms/windows_x86.py b/platformio/platforms/windows_x86.py deleted file mode 100644 index bf52cc1c..00000000 --- a/platformio/platforms/windows_x86.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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.platforms.base import BasePlatform - - -class Windows_x86Platform(BasePlatform): - - """ - Windows x86 (32-bit) is a metafamily of graphical operating systems - developed and marketed by Microsoft. - Using host OS (Windows, Linux 32/64 or Mac OS X) you can build native - application for Windows x86 platform. - - http://platformio.org/platforms/windows_x86 - """ - - PACKAGES = { - - "toolchain-gccmingw32": { - "alias": "toolchain", - "default": True - } - } From d68eb2862985cba157ca5ae3343374b71eaa466b Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 26 May 2016 19:43:36 +0300 Subject: [PATCH 002/284] Decentralized architecture for development platforms // Issue #479 --- .isort.cfg | 2 +- HISTORY.rst | 11 + docs/ci/circleci.rst | 4 +- docs/demo.rst | 12 +- docs/index.rst | 6 +- docs/platforms/creating_board.rst | 6 +- docs/platforms/creating_platform.rst | 12 +- docs/platforms/index.rst | 6 +- docs/projectconf.rst | 6 +- docs/userguide/cmd_boards.rst | 7 +- docs/userguide/cmd_update.rst | 4 +- docs/userguide/index.rst | 4 +- docs/userguide/platforms/cmd_install.rst | 18 +- docs/userguide/platforms/cmd_list.rst | 49 +- docs/userguide/platforms/cmd_search.rst | 145 +++-- docs/userguide/platforms/cmd_show.rst | 81 ++- docs/userguide/platforms/cmd_uninstall.rst | 14 +- docs/userguide/platforms/cmd_update.rst | 78 ++- docs/userguide/platforms/index.rst | 8 +- docs/what-is-platformio.rst | 4 +- platformio/__init__.py | 4 +- platformio/__main__.py | 14 +- platformio/builder/main.py | 60 +- platformio/builder/tools/devplatform.py | 107 ++++ platformio/builder/tools/piomisc.py | 41 +- platformio/builder/tools/pioupload.py | 12 +- platformio/builder/tools/platformio.py | 16 +- platformio/commands/boards.py | 85 +-- platformio/commands/ci.py | 18 +- platformio/commands/init.py | 63 +- platformio/commands/platform.py | 232 +++---- platformio/commands/run.py | 4 +- platformio/commands/update.py | 7 +- platformio/exception.py | 15 +- platformio/maintenance.py | 111 ++-- platformio/managers/__init__.py | 13 + platformio/managers/package.py | 318 +++++++--- platformio/managers/platform.py | 682 ++++++++++----------- platformio/util.py | 28 +- setup.py | 4 +- 40 files changed, 1269 insertions(+), 1042 deletions(-) create mode 100644 platformio/builder/tools/devplatform.py create mode 100644 platformio/managers/__init__.py diff --git a/.isort.cfg b/.isort.cfg index 907a398d..9ac98225 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -1,3 +1,3 @@ [settings] line_length=79 -known_third_party=bottle,click,lockfile,pytest,requests,serial,SCons +known_third_party=bottle,click,lockfile,pytest,requests,semantic_version,serial,SCons diff --git a/HISTORY.rst b/HISTORY.rst index 8f8afef1..a9f78dca 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,17 @@ Release Notes ============= +PlatformIO 3.0 +-------------- + +3.0.0 (2016-??-??) +~~~~~~~~~~~~~~~~~~ + +* Decentralized architecture for development platforms: "platform.json", + semantic versioning, package dependencies, embedded board configs, isolated + build scripts + (`issue #479 `_) + PlatformIO 2.0 -------------- diff --git a/docs/ci/circleci.rst b/docs/ci/circleci.rst index ba6d6932..f8d4e333 100644 --- a/docs/ci/circleci.rst +++ b/docs/ci/circleci.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -152,7 +152,7 @@ Examples - sudo pip install -U platformio # pre-install PlatformIO development platforms, they will be cached - - platformio platforms install atmelavr atmelsam teensy + - platformio platform install atmelavr atmelsam teensy # # Libraries from PlatformIO Library Registry: diff --git a/docs/demo.rst b/docs/demo.rst index e53a31fa..7d073458 100644 --- a/docs/demo.rst +++ b/docs/demo.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -41,11 +41,11 @@ Platform Manager Used in demo ~~~~~~~~~~~~ -1. :ref:`userguide_platforms` -2. :ref:`cmd_platforms_list` command -3. :ref:`platformio platforms search avr ` command -4. :ref:`platformio platforms show teensy ` command -5. :ref:`cmd_platforms_update` command. +1. :ref:`userguide_platform` +2. :ref:`cmd_platform_list` command +3. :ref:`platformio platform search avr ` command +4. :ref:`platformio platform show teensy ` command +5. :ref:`cmd_platform_update` command. Library Manager --------------- diff --git a/docs/index.rst b/docs/index.rst index b2f1fcca..ec3acee8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -58,7 +58,7 @@ Embedded Development. *Easier Than Ever.* * Built-in :ref:`Serial Port Monitor ` and configurable build :ref:`-flags/-options ` * Pre-built toolchains, :ref:`frameworks` for the - :ref:`Development Platforms ` + :ref:`platforms` Smart Build System. *Fast and Reliable.* ---------------------------------------- @@ -108,7 +108,7 @@ Contents :caption: Instruments :maxdepth: 3 - Platforms & Boards + platforms/index frameworks/index .. toctree:: diff --git a/docs/platforms/creating_board.rst b/docs/platforms/creating_board.rst index 60c6e2e5..b618498d 100644 --- a/docs/platforms/creating_board.rst +++ b/docs/platforms/creating_board.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -33,10 +33,10 @@ JSON Structure The key fields: -* ``build`` data will be used by :ref:`Platforms ` and +* ``build`` data will be used by :ref:`platforms` and :ref:`frameworks` builders * ``frameworks`` is the list with supported :ref:`frameworks` -* ``platform`` main type of :ref:`Platforms ` +* ``platform`` main type of :ref:`platforms` * ``upload`` upload settings which depend on the ``platform`` .. code-block:: json diff --git a/docs/platforms/creating_platform.rst b/docs/platforms/creating_platform.rst index 1b606a40..df7e803c 100644 --- a/docs/platforms/creating_platform.rst +++ b/docs/platforms/creating_platform.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -27,7 +27,7 @@ different/own build scripts, uploader and etc. .. note:: If you want to change some build flags for the existing - :ref:`Platforms `, you don't need to create (or duplicate) own + :ref:`platforms`, you don't need to create (or duplicate) own development platforms! Please use :ref:`projectconf_build_flags` option. **Step-by-Step Manual** @@ -361,9 +361,9 @@ Installation 1. Create ``platforms`` directory in :ref:`projectconf_pio_home_dir` if it doesn't exist. 2. Copy ``test.py`` and ``test-builder.py`` files to ``platforms`` directory. -3. Search available platforms via :ref:`cmd_platforms_search` command. You should see +3. Search available platforms via :ref:`cmd_platform_search` command. You should see ``test`` platform. -4. Install ``test`` platform via :ref:`cmd_platforms_install` command. +4. Install ``test`` platform via :ref:`cmd_platform_install` command. Now, you can use ``test`` for the :ref:`projectconf_env_platform` option in :ref:`projectconf`. @@ -480,6 +480,6 @@ and copy there two files: Default([target_firm, target_size]) -Now, we should see ``ststm32gdb`` platform using :ref:`cmd_platforms_search` command output -and can install it via :ref:`platformio platforms install ststm32gdb ` command. +Now, we should see ``ststm32gdb`` platform using :ref:`cmd_platform_search` command output +and can install it via :ref:`platformio platform install ststm32gdb ` command. diff --git a/docs/platforms/index.rst b/docs/platforms/index.rst index 01b6df47..c02760aa 100644 --- a/docs/platforms/index.rst +++ b/docs/platforms/index.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -11,8 +11,8 @@ .. _platforms: -Platforms & Embedded Boards -=========================== +Development Platforms +===================== *PlatformIO* has pre-built different development platforms for popular OS (*Mac OS X, Linux (+ARM) and Windows*). Each of them include compiler, diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 0af9c5f5..145b241d 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -194,7 +194,7 @@ General options ``platform`` ^^^^^^^^^^^^ -:ref:`Platform ` type. +:ref:`platforms` name. .. _projectconf_env_framework: @@ -202,7 +202,7 @@ General options ``framework`` ^^^^^^^^^^^^^ -:ref:`Framework ` type. +:ref:`frameworks` name. The multiple frameworks are allowed, split them with comma ``,`` separator. diff --git a/docs/userguide/cmd_boards.rst b/docs/userguide/cmd_boards.rst index 83b7f86f..8083e8bb 100644 --- a/docs/userguide/cmd_boards.rst +++ b/docs/userguide/cmd_boards.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -33,6 +33,11 @@ Options .. program:: platformio boards +.. option:: + --installed + +List boards only from the installed platforms + .. option:: --json-output diff --git a/docs/userguide/cmd_update.rst b/docs/userguide/cmd_update.rst index 22a65099..d429bb0d 100644 --- a/docs/userguide/cmd_update.rst +++ b/docs/userguide/cmd_update.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -27,7 +27,7 @@ Usage Description ----------- -Check or update installed :ref:`Platforms ` and +Check or update installed :ref:`platforms` and :ref:`Libraries ` diff --git a/docs/userguide/index.rst b/docs/userguide/index.rst index d447a775..1d9851ab 100644 --- a/docs/userguide/index.rst +++ b/docs/userguide/index.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -62,7 +62,7 @@ Commands cmd_boards cmd_ci cmd_init - platformio platforms + platformio platform cmd_run cmd_serialports cmd_settings diff --git a/docs/userguide/platforms/cmd_install.rst b/docs/userguide/platforms/cmd_install.rst index fc36d9ed..b3753537 100644 --- a/docs/userguide/platforms/cmd_install.rst +++ b/docs/userguide/platforms/cmd_install.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -9,10 +9,10 @@ See the License for the specific language governing permissions and limitations under the License. -.. _cmd_platforms_install: +.. _cmd_platform_install: -platformio platforms install -============================ +platformio platform install +=========================== .. contents:: @@ -21,13 +21,13 @@ Usage .. code-block:: bash - platformio platforms install [OPTIONS] [PLATFORMS] + platformio platform install [OPTIONS] [PLATFORMS] Description ----------- -Install pre-built development :ref:`Platforms ` with related +Install pre-built development :ref:`platforms` with related packages. There are several predefined aliases for packages, such as: @@ -38,7 +38,7 @@ There are several predefined aliases for packages, such as: Options ------- -.. program:: platformio platforms install +.. program:: platformio platform install .. option:: --with-package @@ -63,7 +63,7 @@ Examples .. code-block:: bash - $ platformio platforms install timsp430 + $ platformio platform install timsp430 Installing toolchain-timsp430 package: Downloading [####################################] 100% Unpacking [####################################] 100% @@ -81,7 +81,7 @@ Examples .. code-block:: bash - $ platformio platforms install timsp430 --skip-default-package --with-package=uploader + $ platformio platform install timsp430 --skip-default-package --with-package=uploader Installing tool-mspdebug package: Downloading [####################################] 100% Unpacking [####################################] 100% diff --git a/docs/userguide/platforms/cmd_list.rst b/docs/userguide/platforms/cmd_list.rst index b1b9bb2d..aca7aec1 100644 --- a/docs/userguide/platforms/cmd_list.rst +++ b/docs/userguide/platforms/cmd_list.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -9,10 +9,10 @@ See the License for the specific language governing permissions and limitations under the License. -.. _cmd_platforms_list: +.. _cmd_platform_list: -platformio platforms list -========================= +platformio platform list +======================== .. contents:: @@ -21,18 +21,18 @@ Usage .. code-block:: bash - platformio platforms list [OPTIONS] + platformio platform list [OPTIONS] Description ----------- -List installed :ref:`Platforms ` +List installed :ref:`platforms` Options ~~~~~~~ -.. program:: platformio platforms list +.. program:: platformio platform list .. option:: --json-output @@ -44,13 +44,28 @@ Examples .. code-block:: bash - $ platformio platforms list - atmelavr with packages: toolchain-atmelavr, tool-avrdude, framework-arduinoavr, tool-micronucleus - atmelsam with packages: framework-arduinosam, ldscripts, toolchain-gccarmnoneeabi, tool-bossac - freescalekinetis with packages: framework-mbed, toolchain-gccarmnoneeabi - nordicnrf51 with packages: framework-mbed, toolchain-gccarmnoneeabi - nxplpc with packages: framework-mbed, toolchain-gccarmnoneeabi - ststm32 with packages: framework-libopencm3, toolchain-gccarmnoneeabi, tool-stlink, framework-spl, framework-cmsis, framework-mbed, ldscripts - teensy with packages: toolchain-atmelavr, ldscripts, framework-arduinoteensy, toolchain-gccarmnoneeabi, tool-teensy - timsp430 with packages: toolchain-timsp430, tool-mspdebug, framework-energiamsp430, framework-arduinomsp430 - titiva with packages: ldscripts, framework-libopencm3, toolchain-gccarmnoneeabi, tool-lm4flash, framework-energiativa + $ platformio platform list + atmelavr ~ Atmel AVR + ==================== + Atmel AVR 8- and 32-bit MCUs deliver a unique combination of performance, power efficiency and design flexibility. Optimized to speed time to market-and easily adapt to new ones-they are based on the industrys most code-efficient architecture for C and assembly programming. + + Home: http://platformio.org/platforms/atmelavr + Packages: toolchain-atmelavr, framework-simba + Version: 0.0.0 + + atmelsam ~ Atmel SAM + ==================== + Atmel | SMART offers Flash- based ARM products based on the ARM Cortex-M0+, Cortex-M3 and Cortex-M4 architectures, ranging from 8KB to 2MB of Flash including a rich peripheral and feature mix. + + Home: http://platformio.org/platforms/atmelsam + Packages: framework-arduinosam, framework-mbed, framework-simba, toolchain-gccarmnoneeabi, tool-bossac + Version: 0.0.0 + + espressif ~ Espressif + ===================== + Espressif Systems is a privately held fabless semiconductor company. They provide wireless communications and Wi-Fi chips which are widely used in mobile devices and the Internet of Things applications. + + Home: http://platformio.org/platforms/espressif + Packages: framework-simba, tool-esptool, framework-arduinoespressif, sdk-esp8266, toolchain-xtensa + Version: 0.0.0 + ... diff --git a/docs/userguide/platforms/cmd_search.rst b/docs/userguide/platforms/cmd_search.rst index 1f372518..96f1bf5e 100644 --- a/docs/userguide/platforms/cmd_search.rst +++ b/docs/userguide/platforms/cmd_search.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -9,10 +9,10 @@ See the License for the specific language governing permissions and limitations under the License. -.. _cmd_platforms_search: +.. _cmd_platform_search: -platformio platforms search -=========================== +platformio platform search +========================== .. contents:: @@ -21,18 +21,18 @@ Usage .. code-block:: bash - platformio platforms search QUERY [OPTIONS] + platformio platform search QUERY [OPTIONS] Description ----------- -Search for development :ref:`Platforms ` +Search for development :ref:`platforms` Options ~~~~~~~ -.. program:: platformio platforms search +.. program:: platformio platform search .. option:: --json-output @@ -47,73 +47,100 @@ Examples .. code-block:: bash - $ platformio platforms search - atmelavr (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - -------- - Atmel AVR 8- and 32-bit MCUs deliver a unique combination of performance... + $ platformio platform search + atmelavr ~ Atmel AVR + ==================== + Atmel AVR 8- and 32-bit MCUs deliver a unique combination of performance, power efficiency and design flexibility. Optimized to speed time to market-and easily adapt to new ones-they are based on the industrys most code-efficient architecture for C and assembly programming. - atmelsam (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - -------- - Atmel | SMART offers Flash- based ARM products based on the ... + Home: http://platformio.org/platforms/atmelavr + Packages: toolchain-atmelavr, framework-simba + Version: 0.0.0 - freescalekinetis (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - ---------------- - Freescale Kinetis Microcontrollers is family of multiple hardware- and ... + atmelsam ~ Atmel SAM + ==================== + Atmel | SMART offers Flash- based ARM products based on the ARM Cortex-M0+, Cortex-M3 and Cortex-M4 architectures, ranging from 8KB to 2MB of Flash including a rich peripheral and feature mix. - nordicnrf51 (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - ----------- - The Nordic nRF51 Series is a family of highly flexible, multi-protocol ... + Home: http://platformio.org/platforms/atmelsam + Packages: framework-arduinosam, framework-mbed, framework-simba, toolchain-gccarmnoneeabi, tool-bossac + Version: 0.0.0 - nxplpc (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - ------ - The NXP LPC is a family of 32-bit microcontroller integrated circuits ... + espressif ~ Espressif + ===================== + Espressif Systems is a privately held fabless semiconductor company. They provide wireless communications and Wi-Fi chips which are widely used in mobile devices and the Internet of Things applications. - ststm32 (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - ------- - The STM32 family of 32-bit Flash MCUs based on the ARM Cortex-M ... - - teensy (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - ------ - Teensy is a complete USB-based microcontroller development syste ... - - timsp430 (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - -------- - MSP430 microcontrollers (MCUs) from Texas Instruments (TI) are ... - - titiva (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - ------ - Texas Instruments TM4C12x MCUs offer the industrys most popular ... + Home: http://platformio.org/platforms/espressif + Packages: framework-simba, tool-esptool, framework-arduinoespressif, sdk-esp8266, toolchain-xtensa + Version: 0.0.0 + ... 2. Search for TI development platforms .. code-block:: bash - $ platformio platforms search ti - timsp430 (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - -------- - MSP430 microcontrollers (MCUs) from Texas Instruments (TI) are ... + $ platformio platform search texas + timsp430 ~ TI MSP430 + ==================== + MSP430 microcontrollers (MCUs) from Texas Instruments (TI) are 16-bit, RISC-based, mixed-signal processors designed for ultra-low power. These MCUs offer the lowest power consumption and the perfect mix of integrated peripherals for thousands of applications. - titiva (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - ------ - Texas Instruments TM4C12x MCUs offer the industrys most popular ... + Home: http://platformio.org/platforms/timsp430 + Packages: toolchain-timsp430, tool-mspdebug, framework-energiamsp430, framework-arduinomsp430 -3. Search for development platforms which support "mbed Framework" + titiva ~ TI TIVA + ================ + Texas Instruments TM4C12x MCUs offer the industrys most popular ARM Cortex-M4 core with scalable memory and package options, unparalleled connectivity peripherals, advanced application functions, industry-leading analog integration, and extensive software solutions. + + Home: http://platformio.org/platforms/titiva + Packages: ldscripts, framework-libopencm3, toolchain-gccarmnoneeabi, tool-lm4flash, framework-energiativa .. code-block:: bash - $ platformio platforms search mbed - freescalekinetis (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - ---------------- - Freescale Kinetis Microcontrollers is family of multiple hardware- and ... + $ platformio platform search framework-mbed + atmelsam ~ Atmel SAM + ==================== + Atmel | SMART offers Flash- based ARM products based on the ARM Cortex-M0+, Cortex-M3 and Cortex-M4 architectures, ranging from 8KB to 2MB of Flash including a rich peripheral and feature mix. - nordicnrf51 (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - ----------- - The Nordic nRF51 Series is a family of highly flexible, multi-protocol ... + Home: http://platformio.org/platforms/atmelsam + Packages: toolchain-gccarmnoneeabi, framework-arduinosam, framework-simba, tool-openocd, framework-mbed, ldscripts, tool-bossac - nxplpc (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - ------ - The NXP LPC is a family of 32-bit microcontroller integrated circuits ... + freescalekinetis ~ Freescale Kinetis + ==================================== + Freescale Kinetis Microcontrollers is family of multiple hardware- and software-compatible ARM Cortex-M0+, Cortex-M4 and Cortex-M7-based MCU series. Kinetis MCUs offer exceptional low-power performance, scalability and feature integration. - ststm32 (available packages: ldscripts, toolchain-gccarmnoneeabi, tool-lm4flash, framework-opencm3, framework-energiativa) - ------- - The STM32 family of 32-bit Flash MCUs based on the ARM Cortex-M ... + Home: http://platformio.org/platforms/freescalekinetis + Packages: framework-mbed, toolchain-gccarmnoneeabi + + nordicnrf51 ~ Nordic nRF51 + ========================== + The Nordic nRF51 Series is a family of highly flexible, multi-protocol, system-on-chip (SoC) devices for ultra-low power wireless applications. nRF51 Series devices support a range of protocol stacks including Bluetooth Smart (previously called Bluetooth low energy), ANT and proprietary 2.4GHz protocols such as Gazell. + + Home: http://platformio.org/platforms/nordicnrf51 + Packages: framework-mbed, tool-rfdloader, toolchain-gccarmnoneeabi, framework-arduinonordicnrf51 + + nxplpc ~ NXP LPC + ================ + The NXP LPC is a family of 32-bit microcontroller integrated circuits by NXP Semiconductors. The LPC chips are grouped into related series that are based around the same 32-bit ARM processor core, such as the Cortex-M4F, Cortex-M3, Cortex-M0+, or Cortex-M0. Internally, each microcontroller consists of the processor core, static RAM memory, flash memory, debugging interface, and various peripherals. + + Home: http://platformio.org/platforms/nxplpc + Packages: framework-mbed, toolchain-gccarmnoneeabi + + siliconlabsefm32 ~ Silicon Labs EFM32 + ===================================== + Silicon Labs EFM32 Gecko 32-bit microcontroller (MCU) family includes devices that offer flash memory configurations up to 256 kB, 32 kB of RAM and CPU speeds up to 48 MHz. Based on the powerful ARM Cortex-M core, the Gecko family features innovative low energy techniques, short wake-up time from energy saving modes and a wide selection of peripherals, making it ideal for battery operated applications and other systems requiring high performance and low-energy consumption. + + Home: http://platformio.org/platforms/siliconlabsefm32 + Packages: framework-mbed, toolchain-gccarmnoneeabi + + ststm32 ~ ST STM32 + ================== + The STM32 family of 32-bit Flash MCUs based on the ARM Cortex-M processor is designed to offer new degrees of freedom to MCU users. It offers a 32-bit product range that combines very high performance, real-time capabilities, digital signal processing, and low-power, low-voltage operation, while maintaining full integration and ease of development. + + Home: http://platformio.org/platforms/ststm32 + Packages: framework-libopencm3, toolchain-gccarmnoneeabi, tool-stlink, framework-spl, framework-cmsis, framework-mbed, ldscripts + + teensy ~ Teensy + =============== + Teensy is a complete USB-based microcontroller development system, in a very small footprint, capable of implementing many types of projects. All programming is done via the USB port. No special programmer is needed, only a standard USB cable and a PC or Macintosh with a USB port. + + Home: http://platformio.org/platforms/teensy + Packages: framework-arduinoteensy, tool-teensy, toolchain-gccarmnoneeabi, framework-mbed, toolchain-atmelavr, ldscripts + ... diff --git a/docs/userguide/platforms/cmd_show.rst b/docs/userguide/platforms/cmd_show.rst index 20f005b0..114b4bce 100644 --- a/docs/userguide/platforms/cmd_show.rst +++ b/docs/userguide/platforms/cmd_show.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -9,10 +9,10 @@ See the License for the specific language governing permissions and limitations under the License. -.. _cmd_platforms_show: +.. _cmd_platform_show: -platformio platforms show -========================= +platformio platform show +======================== .. contents:: @@ -21,13 +21,13 @@ Usage .. code-block:: bash - platformio platforms show PLATFORM + platformio platform show PLATFORM Description ----------- -Show details about the installed :ref:`Platforms ` +Show details about the installed :ref:`platforms` Examples @@ -35,22 +35,53 @@ Examples .. code-block:: bash - $ platformio platforms show atmelavr - atmelavr - An embedded platform for Atmel AVR microcontrollers (with Arduino Framework) - ---------- - Package: toolchain-atmelavr - Alias: toolchain - Version: 1 - Installed: 2014-12-13 23:58:48 - ---------- - Package: tool-avrdude - Version: 2 - Installed: 2015-02-13 22:23:17 - ---------- - Package: framework-arduinoavr - Version: 12 - Installed: 2015-02-23 20:57:40 - ---------- - Package: tool-micronucleus - Version: 1 - Installed: 2015-02-23 21:20:14 + $ platformio platform show atmelavr + atmelavr ~ Atmel AVR + ==================== + Atmel AVR 8- and 32-bit MCUs deliver a unique combination of performance, power efficiency and design flexibility. Optimized to speed time to market-and easily adapt to new ones-they are based on the industrys most code-efficient architecture for C and assembly programming. + + Version: 0.0.0 + Home: http://platformio.org/platforms/atmelavr + License: Apache-2.0 + Frameworks: simba, arduino + + Package toolchain-atmelavr + -------------------------- + Type: toolchain + Optional: No + Requirements: ~1.40801.0 + Installed: Yes + Description: avr-gcc + Url: https://gcc.gnu.org/wiki/avr-gcc + Version: 1.40801.0 + + Package framework-arduinoavr + ---------------------------- + Type: framework + Optional: Yes + Requirements: ~1.10608.0 + Installed: No (optional) + + Package framework-simba + ----------------------- + Type: framework + Optional: Yes + Requirements: ~1.50.0 + Installed: Yes + Description: framework-simba + Url: https://github.com/eerimoq/simba + Version: 1.50.0 + + Package tool-avrdude + -------------------- + Type: uploader + Optional: Yes + Requirements: >=1.60001.0,<=1.60100.0 + Installed: No (optional) + + Package tool-micronucleus + ------------------------- + Type: uploader + Optional: Yes + Requirements: ~1.200.0 + Installed: No (optional) diff --git a/docs/userguide/platforms/cmd_uninstall.rst b/docs/userguide/platforms/cmd_uninstall.rst index a9e5411a..67cc273a 100644 --- a/docs/userguide/platforms/cmd_uninstall.rst +++ b/docs/userguide/platforms/cmd_uninstall.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -9,10 +9,10 @@ See the License for the specific language governing permissions and limitations under the License. -.. _cmd_platforms_uninstall: +.. _cmd_platform_uninstall: -platformio platforms uninstall -============================== +platformio platform uninstall +============================= .. contents:: @@ -21,13 +21,13 @@ Usage .. code-block:: bash - platformio platforms uninstall PLATFORM + platformio platform uninstall PLATFORM Description ----------- -Uninstall specified :ref:`Platforms ` +Uninstall specified :ref:`platforms` Examples @@ -35,7 +35,7 @@ Examples .. code-block:: bash - $ platformio platforms uninstall timsp430 + $ platformio platform uninstall timsp430 Uninstalling toolchain-timsp430 package: [OK] Uninstalling tool-mspdebug package: [OK] Uninstalling framework-energiamsp430 package: [OK] diff --git a/docs/userguide/platforms/cmd_update.rst b/docs/userguide/platforms/cmd_update.rst index f8ba36c9..8e4fec64 100644 --- a/docs/userguide/platforms/cmd_update.rst +++ b/docs/userguide/platforms/cmd_update.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -9,10 +9,10 @@ See the License for the specific language governing permissions and limitations under the License. -.. _cmd_platforms_update: +.. _cmd_platform_update: -platformio platforms update -=========================== +platformio platform update +========================== .. contents:: @@ -21,90 +21,100 @@ Usage .. code-block:: bash - platformio platforms update + platformio platform update Description ----------- -Check or update installed :ref:`Platforms ` +Check or update installed :ref:`platforms` +Options +------- + +.. program:: platformio platform update + +.. option:: + --only-packages + +Update only platform related packages. Do not update development platform +build scripts, board configs and etc. Examples -------- .. code-block:: bash - $ platformio platforms update + $ platformio platform update Platform atmelavr -------- Updating toolchain-atmelavr package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating tool-avrdude package: - Versions: Current=2, Latest=2 [Up-to-date] + Versions: Current=2, Latest=2 [Up-to-date] Updating framework-arduinoavr package: - Versions: Current=12, Latest=12 [Up-to-date] + Versions: Current=12, Latest=12 [Up-to-date] Updating tool-micronucleus package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Platform atmelsam -------- Updating framework-arduinosam package: - Versions: Current=3, Latest=3 [Up-to-date] + Versions: Current=3, Latest=3 [Up-to-date] Updating ldscripts package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating toolchain-gccarmnoneeabi package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating tool-bossac package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Platform stm32 -------- Updating toolchain-gccarmnoneeabi package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating tool-stlink package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating framework-spl package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating framework-cmsis package: - Versions: Current=2, Latest=2 [Up-to-date] + Versions: Current=2, Latest=2 [Up-to-date] Updating framework-opencm3 package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating ldscripts package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Platform teensy -------- Updating toolchain-atmelavr package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating ldscripts package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating framework-arduinoteensy package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating toolchain-gccarmnoneeabi package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating tool-teensy package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Platform timsp430 -------- Updating toolchain-timsp430 package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating tool-mspdebug package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating framework-energiamsp430 package: - Versions: Current=2, Latest=2 [Up-to-date] + Versions: Current=2, Latest=2 [Up-to-date] Platform titiva -------- Updating ldscripts package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating toolchain-gccarmnoneeabi package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating tool-lm4flash package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating framework-opencm3 package: - Versions: Current=1, Latest=1 [Up-to-date] + Versions: Current=1, Latest=1 [Up-to-date] Updating framework-energiativa package: - Versions: Current=4, Latest=4 [Up-to-date] + Versions: Current=4, Latest=4 [Up-to-date] diff --git a/docs/userguide/platforms/index.rst b/docs/userguide/platforms/index.rst index 1d084ccd..437826f1 100644 --- a/docs/userguide/platforms/index.rst +++ b/docs/userguide/platforms/index.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -9,7 +9,7 @@ See the License for the specific language governing permissions and limitations under the License. -.. _userguide_platforms: +.. _userguide_platform: Platform Manager ================ @@ -18,8 +18,8 @@ To print all available commands and options use: .. code-block:: bash - $ platformio platforms --help - $ platformio platforms COMMAND --help + $ platformio platform --help + $ platformio platform COMMAND --help .. image:: ../../_static/platformio-demo-platforms.gif diff --git a/docs/what-is-platformio.rst b/docs/what-is-platformio.rst index 0eb61dd5..f7849078 100644 --- a/docs/what-is-platformio.rst +++ b/docs/what-is-platformio.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -76,7 +76,7 @@ Alright, so PlatformIO can run on different operating systems. But more importantly, from development perspective at least, is a list of supported boards and MCUs. To keep things short: PlatformIO supports approximately 200 `Embedded Boards `_ and all major -:ref:`Development Platforms `. +:ref:`platforms`. User SHOULD have a choice ------------------------- diff --git a/platformio/__init__.py b/platformio/__init__.py index d8d22716..fe5bd51c 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ import sys -VERSION = (2, 9, "2.dev0") +VERSION = (3, 0, "0.dev0") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/__main__.py b/platformio/__main__.py index c553e8f6..a9d6b8b8 100644 --- a/platformio/__main__.py +++ b/platformio/__main__.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -51,15 +51,9 @@ class PlatformioCLI(click.MultiCommand): # pylint: disable=R0904 @staticmethod def _handle_obsolate_command(name): - if name in ("install", "list", "search", "show", "uninstall"): - click.secho( - "Warning! `platformio %s` command is deprecated and will be " - "removed in the next release! Please use " - "`platformio platforms %s` instead." % (name, name), - fg="yellow" - ) - from platformio.commands import platforms - return getattr(platforms, "platforms_" + name) + if name == "platforms": + from platformio.commands import platform + return platform.cli raise AttributeError() diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 8b01c7b2..b4f00241 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -22,23 +22,18 @@ from time import time from SCons.Script import COMMAND_LINE_TARGETS, DefaultEnvironment, Variables from platformio import util -from platformio.exception import UnknownBoard # AllowSubstExceptions() # allow common variables from INI file commonvars = Variables(None) commonvars.AddVariables( + ("PLATFORM_MANIFEST",), ("BUILD_SCRIPT",), ("EXTRA_SCRIPT",), ("PIOENV",), ("PLATFORM",), - # package aliases - ("PIOPACKAGE_TOOLCHAIN",), - ("PIOPACKAGE_FRAMEWORK",), - ("PIOPACKAGE_UPLOADER",), - # options ("FRAMEWORK",), ("BUILD_FLAGS",), @@ -67,9 +62,9 @@ commonvars.AddVariables( DefaultEnvironment( tools=[ "gcc", "g++", "as", "ar", "gnulink", - "platformio", "pioupload", "pioar", "piomisc" + "platformio", "devplatform", "pioupload", "pioar", "piomisc" ], - toolpath=[join("$PIOBUILDER_DIR", "tools")], + toolpath=[join(util.get_source_dir(), "builder", "tools")], variables=commonvars, # Propagating External Environment @@ -85,15 +80,11 @@ DefaultEnvironment( PROJECTDATA_DIR=util.get_projectdata_dir(), PIOENVS_DIR=util.get_pioenvs_dir(), - PIOBUILDER_DIR=join(util.get_source_dir(), "builder"), - PIOPACKAGES_DIR=join("$PIOHOME_DIR", "packages"), - BUILD_DIR=join("$PIOENVS_DIR", "$PIOENV"), BUILDSRC_DIR=join("$BUILD_DIR", "src"), LIBSOURCE_DIRS=[ "$PROJECTLIB_DIR", - util.get_lib_dir(), - join("$PLATFORMFW_DIR", "libraries") + util.get_lib_dir() ], PYTHONEXE=normpath(sys.executable) @@ -106,58 +97,27 @@ for k in commonvars.keys(): if k in env: env[k] = base64.b64decode(env[k]) -env.Prepend(LIBPATH=[join("$PIOPACKAGES_DIR", "ldscripts")]) - -if "BOARD" in env: - try: - env.Replace(BOARD_OPTIONS=util.get_boards(env.subst("$BOARD"))) - except UnknownBoard as e: - env.Exit("Error: %s" % str(e)) - - for k in commonvars.keys(): - if (k in env or - not any([k.startswith("BOARD_"), k.startswith("UPLOAD_")])): - continue - _opt, _val = k.lower().split("_", 1) - if _opt == "board": - _opt = "build" - if _val in env['BOARD_OPTIONS'][_opt]: - env.Replace(**{k: "${BOARD_OPTIONS['%s']['%s']}" % (_opt, _val)}) - - if "ldscript" in env.get("BOARD_OPTIONS", {}).get("build", {}): - env.Replace( - LDSCRIPT_PATH="${BOARD_OPTIONS['build']['ldscript']}" - ) - - if env['PLATFORM'] != env.get("BOARD_OPTIONS", {}).get("platform"): - env.Exit( - "Error: '%s' platform doesn't support this board. " - "Use '%s' platform instead." % ( - env['PLATFORM'], env.get("BOARD_OPTIONS", {}).get("platform"))) - +env.LoadDevPlatform(commonvars) +# Parse library names for opt in ("LIB_IGNORE", "LIB_USE"): if opt not in env: continue env[opt] = [l.strip() for l in env[opt].split(",") if l.strip()] -if env.subst("$PIOPACKAGE_TOOLCHAIN"): - env.PrependENVPath( - "PATH", - env.subst(join("$PIOPACKAGES_DIR", "$PIOPACKAGE_TOOLCHAIN", "bin")) - ) - -# handle custom variable from system environment +# Handle custom variables from system environment for var in ("BUILD_FLAGS", "SRC_BUILD_FLAGS", "SRC_FILTER", "EXTRA_SCRIPT", "UPLOAD_PORT", "UPLOAD_FLAGS"): k = "PLATFORMIO_%s" % var if environ.get(k): env[var] = environ.get(k) + env.SConscriptChdir(0) env.SConsignFile(join("$PIOENVS_DIR", ".sconsign.dblite")) env.SConscript("$BUILD_SCRIPT") + if "UPLOAD_FLAGS" in env: env.Append(UPLOADERFLAGS=["$UPLOAD_FLAGS"]) diff --git a/platformio/builder/tools/devplatform.py b/platformio/builder/tools/devplatform.py new file mode 100644 index 00000000..ac5cda6d --- /dev/null +++ b/platformio/builder/tools/devplatform.py @@ -0,0 +1,107 @@ +# Copyright 2014-present Ivan Kravets +# +# 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 isdir, isfile, join + +from SCons.Script import COMMAND_LINE_TARGETS + +from platformio import exception, util +from platformio.managers.platform import PlatformFactory + + +@util.memoized +def initDevPlatform(name): + return PlatformFactory.newPlatform(name) + + +def DevPlatform(env): + variables = {} + for key in ("board", "framework"): + if key not in env: + continue + variables[key] = env[key.upper()] + p = initDevPlatform(env['PLATFORM_MANIFEST']) + p.configure_default_packages(variables, COMMAND_LINE_TARGETS) + return p + + +def BoardConfig(env, board=None): + p = initDevPlatform(env['PLATFORM_MANIFEST']) + try: + config = p.board_config(board if board else env['BOARD']) + except exception.UnknownBoard as e: + env.Exit("Error: %s" % str(e)) + return config + + +def GetFrameworkScript(env, framework): + p = env.DevPlatform() + frameworks = p.get_frameworks() + assert frameworks and framework in frameworks + script_path = env.subst(frameworks[framework]['script']) + if not isfile(script_path): + script_path = join(p.get_dir(), script_path) + return script_path + + +def LoadDevPlatform(env, variables): + p = env.DevPlatform() + installed_packages = p.get_installed_packages() + + # Add toolchains and uploaders to $PATH + for name in installed_packages.keys(): + type_ = p.get_package_type(name) + if type_ not in ("toolchain", "uploader"): + continue + path = p.get_package_dir(name) + if isdir(join(path, "bin")): + path = join(path, "bin") + env.PrependENVPath("PATH", path) + + # Platform specific LD Scripts + if isdir(join(p.get_dir(), "ldscripts")): + env.Prepend(LIBPATH=[join(p.get_dir(), "ldscripts")]) + + if "BOARD" not in env: + return + + board_config = env.BoardConfig() + for k in variables.keys(): + if (k in env or + not any([k.startswith("BOARD_"), k.startswith("UPLOAD_")])): + 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))}) + + if "build.ldscript" in board_config: + env.Replace( + LDSCRIPT_PATH=board_config.get("build.ldscript") + ) + + +def exists(_): + return True + + +def generate(env): + env.AddMethod(DevPlatform) + env.AddMethod(BoardConfig) + env.AddMethod(GetFrameworkScript) + env.AddMethod(LoadDevPlatform) + return env diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 1fa62f93..396ef4b1 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ from glob import glob from os import environ, listdir, remove from os.path import isdir, isfile, join -from platformio.util import exec_command, where_is_program +from platformio import util class InoToCPPConverter(object): @@ -143,8 +143,6 @@ def ConvertInoToCpp(env): def DumpIDEData(env): - BOARD_CORE = env.get("BOARD_OPTIONS", {}).get("build", {}).get("core") - def get_includes(env_): includes = [] # includes from used framework and libs @@ -164,15 +162,18 @@ def DumpIDEData(env): lsd_dir = env_.subst(d) _append_lib_includes(env_, lsd_dir, includes) - # includes from toolchain - toolchain_dir = env_.subst( - join("$PIOPACKAGES_DIR", "$PIOPACKAGE_TOOLCHAIN")) - toolchain_incglobs = [ - join(toolchain_dir, "*", "include*"), - join(toolchain_dir, "lib", "gcc", "*", "*", "include*") - ] - for g in toolchain_incglobs: - includes.extend(glob(g)) + # includes from toolchains + p = env.DevPlatform() + for name in p.get_installed_packages().keys(): + if p.get_package_type(name) != "toolchain": + continue + toolchain_dir = p.get_package_dir(name) + toolchain_incglobs = [ + join(toolchain_dir, "*", "include*"), + join(toolchain_dir, "lib", "gcc", "*", "*", "include*") + ] + for g in toolchain_incglobs: + includes.extend(glob(g)) return includes @@ -186,9 +187,10 @@ def DumpIDEData(env): if name in env_.get("LIB_IGNORE", []): continue if name == "__cores__": - if isdir(join(libs_dir, name, BOARD_CORE)): + board_core = env_.BoardConfig().get("build.core") + if isdir(join(libs_dir, name, board_core)): _append_lib_includes( - env_, join(libs_dir, name, BOARD_CORE), includes) + env_, join(libs_dir, name, board_core), includes) return include = ( @@ -208,10 +210,9 @@ def DumpIDEData(env): defines.append(env_.subst(item).replace('\\"', '"')) # special symbol for Atmel AVR MCU - board = env_.get("BOARD_OPTIONS", {}) - if board and board['platform'] == "atmelavr": + if env.subst("$PLATFORM") == "atmelavr": defines.append( - "__AVR_%s__" % board['build']['mcu'].upper() + "__AVR_%s__" % env.BoardConfig().get("build.mcu").upper() .replace("ATMEGA", "ATmega") .replace("ATTINY", "ATtiny") ) @@ -226,7 +227,7 @@ def DumpIDEData(env): "includes": get_includes(env_), "cc_flags": env_.subst(LINTCCOM), "cxx_flags": env_.subst(LINTCXXCOM), - "cxx_path": where_is_program( + "cxx_path": util.where_is_program( env_.subst("$CXX"), env_.subst("${ENV['PATH']}")) } @@ -254,7 +255,7 @@ def GetCompilerType(env): try: sysenv = environ.copy() sysenv['PATH'] = str(env['ENV']['PATH']) - result = exec_command([env.subst("$CC"), "-v"], env=sysenv) + result = util.exec_command([env.subst("$CC"), "-v"], env=sysenv) except OSError: return None if result['returncode'] != 0: diff --git a/platformio/builder/tools/pioupload.py b/platformio/builder/tools/pioupload.py index d1cd6dab..1b3ae2ac 100644 --- a/platformio/builder/tools/pioupload.py +++ b/platformio/builder/tools/pioupload.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -83,14 +83,16 @@ def AutodetectUploadPort(env): env.Replace(UPLOAD_PORT=item['disk']) break else: - board_build_opts = env.get("BOARD_OPTIONS", {}).get("build", {}) + board_hwids = [] + if "BOARD" in env and "build.hwids" in env.BoardConfig(): + board_hwids = env.BoardConfig().get("build.hwids") for item in get_serialports(): if "VID:PID" not in item['hwid']: continue env.Replace(UPLOAD_PORT=item['port']) - for hwid in board_build_opts.get("hwid", []): - board_hwid = ("%s:%s" % (hwid[0], hwid[1])).replace("0x", "") - if board_hwid in item['hwid']: + for hwid in board_hwids: + hwid_str = ("%s:%s" % (hwid[0], hwid[1])).replace("0x", "") + if hwid_str in item['hwid']: break if "UPLOAD_PORT" in env: diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index f897d24a..10c93f6b 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -43,9 +43,8 @@ def BuildProgram(env): ) # process extra flags from board - env.ProcessFlags([ - env.get("BOARD_OPTIONS", {}).get("build", {}).get("extra_flags") - ]) + 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 @@ -208,20 +207,21 @@ def BuildFrameworks(env, frameworks): if not frameworks or "uploadlazy" in COMMAND_LINE_TARGETS: return - board_frameworks = env.get("BOARD_OPTIONS", {}).get("frameworks", []) + board_frameworks = [] + if "BOARD" in env: + board_frameworks = env.BoardConfig().get("frameworks", []) if frameworks == ["platformio"]: if board_frameworks: frameworks.insert(0, board_frameworks[0]) else: - env.Exit("Error: Please specify board type") + env.Exit("Error: Please specify `board` in `platformio.ini`") for f in frameworks: if f in ("arduino", "energia"): env.ConvertInoToCpp() if f in board_frameworks: - SConscript(env.subst( - join("$PIOBUILDER_DIR", "scripts", "frameworks", "%s.py" % f))) + SConscript(env.GetFrameworkScript(f)) else: env.Exit("Error: This board doesn't support %s framework!" % f) diff --git a/platformio/commands/boards.py b/platformio/commands/boards.py index 0ccdfa6f..585ff84b 100644 --- a/platformio/commands/boards.py +++ b/platformio/commands/boards.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,30 +16,30 @@ import json import click -from platformio.util import get_boards +from platformio.managers.platform import PlatformManager -@click.command("list", short_help="Pre-configured Embedded Boards") +@click.command("boards", short_help="Pre-configured Embedded Boards") @click.argument("query", required=False) +@click.option("--installed", is_flag=True) @click.option("--json-output", is_flag=True) -def cli(query, json_output): # pylint: disable=R0912 - +def cli(query, installed, json_output): # pylint: disable=R0912 if json_output: - return ouput_boards_json(query) + return _ouput_boards_json(query, installed) BOARDLIST_TPL = ("{type:<30} {mcu:<14} {frequency:<8} " " {flash:<7} {ram:<6} {name}") terminal_width, _ = click.get_terminal_size() grpboards = {} - for type_, data in get_boards().items(): - if data['platform'] not in grpboards: - grpboards[data['platform']] = {} - grpboards[data['platform']][type_] = data + for board in _get_boards(installed): + if board['platform'] not in grpboards: + grpboards[board['platform']] = [] + grpboards[board['platform']].append(board) - for (platform, boards) in sorted(grpboards.items()): + for (platform, pboards) in sorted(grpboards.items()): if query: - search_data = json.dumps(boards).lower() + search_data = json.dumps(pboards).lower() if query.lower() not in search_data.lower(): continue @@ -48,45 +48,56 @@ def cli(query, json_output): # pylint: disable=R0912 click.secho(platform, bold=True) click.echo("-" * terminal_width) click.echo(BOARDLIST_TPL.format( - type=click.style("Type", fg="cyan"), mcu="MCU", + type=click.style("ID", fg="cyan"), mcu="MCU", frequency="Frequency", flash="Flash", ram="RAM", name="Name")) click.echo("-" * terminal_width) - for type_, data in sorted(boards.items(), key=lambda b: b[1]['name']): + for board in sorted(pboards, key=lambda b: b['id']): if query: - search_data = "%s %s" % (type_, json.dumps(data).lower()) + search_data = "%s %s" % ( + board['id'], json.dumps(board).lower()) if query.lower() not in search_data.lower(): continue - flash_size = "" - if "maximum_size" in data.get("upload", None): - flash_size = int(data['upload']['maximum_size']) - flash_size = "%dkB" % (flash_size / 1024) + flash_size = "%dkB" % (board['rom'] / 1024) - ram_size = "" - if "maximum_ram_size" in data.get("upload", None): - ram_size = int(data['upload']['maximum_ram_size']) - if ram_size >= 1024: - if ram_size % 1024: - ram_size = "%.1fkB" % (ram_size / 1024.0) - else: - ram_size = "%dkB" % (ram_size / 1024) + ram_size = board['ram'] + if ram_size >= 1024: + if ram_size % 1024: + ram_size = "%.1fkB" % (ram_size / 1024.0) else: - ram_size = "%dB" % ram_size + ram_size = "%dkB" % (ram_size / 1024) + else: + ram_size = "%dB" % ram_size click.echo(BOARDLIST_TPL.format( - type=click.style(type_, fg="cyan"), mcu=data['build']['mcu'], - frequency="%dMhz" % ( - int(data['build']['f_cpu'][:-1]) / 1000000), - flash=flash_size, ram=ram_size, name=data['name'])) + type=click.style(board['id'], fg="cyan"), + mcu=board['mcu'], + frequency="%dMhz" % (board['fcpu'] / 1000000), + flash=flash_size, ram=ram_size, name=board['name'])) -def ouput_boards_json(query): - result = {} - for type_, data in get_boards().items(): +def _get_boards(installed=False): + boards = PlatformManager.get_registered_boards() + if installed: + _installed_boards = [ + "%s:%s" % (b['platform'], b['id']) + for b in PlatformManager().get_installed_boards() + ] + _new_boards = [] + for board in boards: + key = "%s:%s" % (board['platform'], board['id']) + if key in _installed_boards: + _new_boards.append(board) + boards = _new_boards + return boards + +def _ouput_boards_json(query, installed=False): + result = [] + for board in _get_boards(installed): if query: - search_data = "%s %s" % (type_, json.dumps(data).lower()) + search_data = "%s %s" % (board['id'], json.dumps(board).lower()) if query.lower() not in search_data.lower(): continue - result[type_] = data + result.append(board) click.echo(json.dumps(result)) diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index 602ef67d..f18f077c 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,9 +23,9 @@ import click from platformio import app 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.exception import CIBuildEnvsEmpty -from platformio.util import get_boards def validate_path(ctx, param, value): # pylint: disable=W0613 @@ -45,22 +45,12 @@ def validate_path(ctx, param, value): # pylint: disable=W0613 raise click.BadParameter("Found invalid path: %s" % invalid_path) -def validate_boards(ctx, param, value): # pylint: disable=W0613 - unknown_boards = set(value) - set(get_boards().keys()) - try: - assert not unknown_boards - return value - except AssertionError: - raise click.BadParameter( - "%s. Please search for the board types using " - "`platformio boards` command" % ", ".join(unknown_boards)) - - @click.command("ci", short_help="Continuous Integration") @click.argument("src", nargs=-1, callback=validate_path) @click.option("--lib", "-l", multiple=True, callback=validate_path) @click.option("--exclude", multiple=True) -@click.option("--board", "-b", multiple=True, callback=validate_boards) +@click.option("--board", "-b", 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)) diff --git a/platformio/commands/init.py b/platformio/commands/init.py index d9b48288..c0837fad 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,21 +19,26 @@ from shutil import copyfile import click from platformio import app, exception, util -from platformio.commands.platforms import \ - platforms_install as cli_platforms_install +from platformio.commands.platform import \ + platform_install as cli_platform_install from platformio.ide.projectgenerator import ProjectGenerator -from platformio.platforms.base import PlatformFactory -from platformio.util import get_boards, get_source_dir +from platformio.managers.platform import PlatformManager def validate_boards(ctx, param, value): # pylint: disable=W0613 - unknown_boards = set(value) - set(get_boards().keys()) + pm = PlatformManager() + # check installed boards + known_boards = set([b['id'] for b in pm.get_installed_boards()]) + # if boards are not listed as installed, check registered boards + if set(value) - known_boards: + known_boards = set([b['id'] for b in pm.get_registered_boards()]) + unknown_boards = set(value) - known_boards try: assert not unknown_boards return value except AssertionError: raise click.BadParameter( - "%s. Please search for the board types using " + "%s. Please search for the board ID using " "`platformio boards` command" % ", ".join(unknown_boards)) @@ -41,7 +46,7 @@ def validate_boards(ctx, param, value): # pylint: disable=W0613 @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("--board", "-b", multiple=True, metavar="TYPE", +@click.option("--board", "-b", multiple=True, metavar="ID", callback=validate_boards) @click.option("--ide", type=click.Choice(ProjectGenerator.get_supported_ides())) @@ -90,9 +95,9 @@ def cli(ctx, project_dir, board, ide, # pylint: disable=R0913 click.secho( "Warning! You have initialised project with more than 1 board" " for the specified IDE.\n" - "However, the IDE features (code autocompletion, syntax lint)" - " have been configured for the first board '%s' from your list" - " '%s'." % (board[0], ", ".join(board)), + "However, the IDE features (code autocompletion, syntax " + "linter) have been configured for the first board '%s' from " + "your list '%s'." % (board[0], ", ".join(board)), fg="yellow" ) pg = ProjectGenerator( @@ -115,7 +120,7 @@ def cli(ctx, project_dir, board, ide, # pylint: disable=R0913 def init_base_project(project_dir): platformio_ini = join(project_dir, "platformio.ini") if not isfile(platformio_ini): - copyfile(join(get_source_dir(), "projectconftpl.ini"), + copyfile(join(util.get_source_dir(), "projectconftpl.ini"), platformio_ini) lib_dir = join(project_dir, "lib") @@ -246,7 +251,7 @@ def init_ci_conf(project_dir): # - pip install -U platformio # # script: -# - platformio ci --lib="." --board=TYPE_1 --board=TYPE_2 --board=TYPE_N +# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N """) @@ -258,9 +263,9 @@ def init_cvs_ignore(project_dir): def fill_project_envs( # pylint: disable=too-many-arguments,too-many-locals - ctx, platformio_ini, board_types, enable_auto_uploading, + ctx, platformio_ini, board_ids, enable_auto_uploading, env_prefix, force_download): - builtin_boards = get_boards() + installed_boards = PlatformManager().get_installed_boards() content = [] used_boards = [] used_platforms = [] @@ -272,23 +277,30 @@ def fill_project_envs( # pylint: disable=too-many-arguments,too-many-locals continue used_boards.append(config.get(section, "board")) - for type_ in board_types: - data = builtin_boards[type_] - used_platforms.append(data['platform']) + for id_ in board_ids: + manifest = None + for boards in ( + installed_boards, PlatformManager.get_registered_boards()): + for b in boards: + if b['id'] == id_: + manifest = b + break + assert manifest is not None - if type_ in used_boards: + used_platforms.append(manifest['platform']) + if id_ in used_boards: continue content.append("") - content.append("[env:%s%s]" % (env_prefix, type_)) - content.append("platform = %s" % data['platform']) + content.append("[env:%s%s]" % (env_prefix, id_)) + content.append("platform = %s" % manifest['platform']) # find default framework for board - frameworks = data.get("frameworks") + frameworks = manifest.get("frameworks") if frameworks: content.append("framework = %s" % frameworks[0]) - content.append("board = %s" % type_) + content.append("board = %s" % id_) if enable_auto_uploading: content.append("targets = upload") @@ -304,10 +316,11 @@ def fill_project_envs( # pylint: disable=too-many-arguments,too-many-locals def _install_dependent_platforms(ctx, platforms): - installed_platforms = PlatformFactory.get_platforms(installed=True).keys() + installed_platforms = [ + p['name'] for p in PlatformManager().get_installed()] if set(platforms) <= set(installed_platforms): return ctx.invoke( - cli_platforms_install, + cli_platform_install, platforms=list(set(platforms) - set(installed_platforms)) ) diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index 70af83b3..2a159f02 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,31 +13,76 @@ # limitations under the License. import json -from datetime import datetime import click -from platformio import app -from platformio.exception import PlatformNotInstalledYet -from platformio.pkgmanager import PackageManager -from platformio.platforms.base import PlatformFactory +from platformio import app, exception, util +from platformio.managers.platform import PlatformFactory, PlatformManager -@click.group(short_help="Platforms and Packages Manager") +@click.group(short_help="Platform Manager") def cli(): pass +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("=" * (3 + len(platform['name'] + platform['title']))) + click.echo(platform['description']) + click.echo() + click.echo("Home: %s" % + "http://platformio.org/platforms/" + platform['name']) + if platform['packages']: + click.echo("Packages: %s" % ", ".join(platform['packages'])) + if "version" in platform: + click.echo("Version: " + platform['version']) + click.echo() + + +@cli.command("search", short_help="Search for development platforms") +@click.argument("query", required=False) +@click.option("--json-output", is_flag=True) +def platform_search(query, json_output): + platforms = [] + for platform in util.get_api_result("/platforms"): + if query == "all": + query = "" + + search_data = json.dumps(platform) + if query and query.lower() not in search_data.lower(): + continue + + # @TODO update API with NAME/TITLE + platforms.append({ + "name": platform['type'], + "title": platform['name'], + "description": platform['description'], + "packages": platform['packages'] + }) + + if json_output: + click.echo(json.dumps(platforms)) + else: + _print_platforms(platforms) + + @cli.command("install", short_help="Install new platforms") @click.argument("platforms", nargs=-1, required=True) @click.option("--with-package", multiple=True, metavar="") @click.option("--without-package", multiple=True, metavar="") @click.option("--skip-default-package", is_flag=True) -def platforms_install(platforms, with_package, without_package, - skip_default_package): +def platform_install(platforms, with_package, without_package, + skip_default_package): for platform in platforms: - p = PlatformFactory.newPlatform(platform) - if p.install(with_package, without_package, skip_default_package): + _platform = platform + _version = None + if "@" in platform: + _platform, _version = platform.rsplit("@", 1) + if PlatformManager().install(_platform, _version, with_package, + without_package, skip_default_package): click.secho( "The platform '%s' has been successfully installed!\n" "The rest of packages will be installed automatically " @@ -47,123 +92,96 @@ def platforms_install(platforms, with_package, without_package, @cli.command("list", short_help="List installed platforms") @click.option("--json-output", is_flag=True) -def platforms_list(json_output): - - installed_platforms = PlatformFactory.get_platforms( - installed=True).keys() - installed_platforms.sort() - - data = [] - for platform in installed_platforms: - p = PlatformFactory.newPlatform(platform) - data.append({ - "name": platform, - "packages": p.get_installed_packages() +def platform_list(json_output): + platforms = [] + for manifest in PlatformManager().get_installed(): + p = PlatformFactory.newPlatform(manifest['_manifest_path']) + platforms.append({ + "name": p.get_name(), + "title": p.get_title(), + "description": p.get_description(), + "version": p.get_version(), + "packages": p.get_installed_packages().keys() }) if json_output: - click.echo(json.dumps(data)) + click.echo(json.dumps(platforms)) else: - for item in data: - click.echo("{name:<20} with packages: {pkgs}".format( - name=click.style(item['name'], fg="cyan"), - pkgs=", ".join(item['packages']) - )) + _print_platforms(platforms) -@cli.command("search", short_help="Search for development platforms") -@click.argument("query", required=False) -@click.option("--json-output", is_flag=True) -def platforms_search(query, json_output): - - data = [] - platforms = PlatformFactory.get_platforms().keys() - platforms.sort() - for platform in platforms: - p = PlatformFactory.newPlatform(platform) - type_ = p.get_type() - description = p.get_description() - - if query == "all": - query = "" - - search_data = "%s %s %s" % (type_, description, p.get_packages()) - if query and query.lower() not in search_data.lower(): - continue - - data.append({ - "type": type_, - "description": description, - "packages": p.get_packages() - }) - - if json_output: - click.echo(json.dumps(data)) - else: - terminal_width, _ = click.get_terminal_size() - for item in data: - click.secho(item['type'], fg="cyan", nl=False) - click.echo(" (available packages: %s)" % ", ".join( - item.get("packages").keys())) - click.echo("-" * terminal_width) - click.echo(item['description']) - click.echo() - - -@cli.command("show", short_help="Show details about installed platform") +@cli.command("show", short_help="Show details about installed Platform") @click.argument("platform") @click.pass_context -def platforms_show(ctx, platform): - - installed_platforms = PlatformFactory.get_platforms( - installed=True).keys() - - if platform not in installed_platforms: +def platform_show(ctx, platform): + try: + p = PlatformFactory.newPlatform(platform) + except exception.UnknownPlatform: if (not app.get_setting("enable_prompts") or click.confirm("The platform '%s' has not been installed yet. " "Would you like to install it now?" % platform)): - ctx.invoke(platforms_install, platforms=[platform]) + ctx.invoke(platform_install, platforms=[platform]) else: - raise PlatformNotInstalledYet(platform) + raise exception.PlatformNotInstalledYet(platform) - p = PlatformFactory.newPlatform(platform) - click.echo("{name:<20} - {description} [ {url} ]".format( - name=click.style(p.get_type(), fg="cyan"), - description=p.get_description(), url=p.get_vendor_url())) + click.echo("{name} ~ {title}".format( + name=click.style(p.get_name(), fg="cyan"), title=p.get_title())) + click.echo("=" * (3 + len(p.get_name() + p.get_title()))) + click.echo(p.get_manifest().get("description")) + click.echo() + click.echo("Version: %s" % p.get_version()) + if "homepage" in p.get_manifest(): + click.echo("Home: %s" % p.get_manifest().get("homepage")) + if "license" in p.get_manifest(): + click.echo("License: %s" % p.get_manifest().get("license").get("type")) + if "frameworks" in p.get_manifest(): + click.echo("Frameworks: %s" % + ", ".join(p.get_manifest().get("frameworks").keys())) - installed_packages = PackageManager.get_installed() - for name in p.get_installed_packages(): - data = installed_packages[name] - pkgalias = p.get_package_alias(name) - click.echo("----------") - click.echo("Package: %s" % click.style(name, fg="yellow")) - if pkgalias: - click.echo("Alias: %s" % pkgalias) - click.echo("Version: %d" % int(data['version'])) - click.echo("Installed: %s" % datetime.fromtimestamp( - data['time']).strftime("%Y-%m-%d %H:%M:%S")) + if not p.get_packages(): + return + + installed_pkgs = p.get_installed_packages() + for name, opts in p.get_packages().items(): + click.echo() + click.echo("Package %s" % click.style(name, fg="yellow")) + click.echo("-" * (8 + len(name))) + if p.get_package_type(name): + click.echo("Type: %s" % p.get_package_type(name)) + click.echo("Requirements: %s" % opts.get("version")) + click.echo("Installed: %s" % ( + "Yes" if name in installed_pkgs else "No (optional)")) + if name in installed_pkgs: + for key, value in installed_pkgs[name].items(): + if key in ("url", "version", "description"): + click.echo("%s: %s" % (key.title(), value)) @cli.command("uninstall", short_help="Uninstall platforms") @click.argument("platforms", nargs=-1, required=True) -def platforms_uninstall(platforms): - +def platform_uninstall(platforms): for platform in platforms: - p = PlatformFactory.newPlatform(platform) - if p.uninstall(): + _platform = platform + _version = None + if "@" in platform: + _platform, _version = platform.rsplit("@", 1) + if PlatformManager().uninstall(_platform, _version): click.secho("The platform '%s' has been successfully " "uninstalled!" % platform, fg="green") -@cli.command("update", short_help="Update installed Platforms and Packages") -def platforms_update(): - - installed_platforms = PlatformFactory.get_platforms( - installed=True).keys() - installed_platforms.sort() - - for platform in installed_platforms: - click.echo("\nPlatform %s" % click.style(platform, fg="cyan")) +@cli.command("update", short_help="Update installed Platforms") +@click.option("--only-packages", is_flag=True) +def platform_update(only_packages): + for manifest in PlatformManager().get_installed(): + click.echo("Platform %s @ %s" % ( + click.style(manifest['name'], fg="cyan"), manifest['version'])) click.echo("--------") - p = PlatformFactory.newPlatform(platform) - p.update() + if only_packages: + status = PlatformFactory.newPlatform( + manifest['name'], manifest['version']).update_packages() + if status is None: + click.secho("Packages are up-to-date", fg="green") + else: + PlatformManager().update(manifest['name'], manifest['version']) + click.echo() diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 0834edf0..e32654ef 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import click from platformio import app, exception, telemetry, util from platformio.commands.lib import lib_install as cmd_lib_install from platformio.libmanager import LibraryManager -from platformio.platforms.base import PlatformFactory +from platformio.managers.platform import PlatformFactory @click.command("run", short_help="Process project environments") diff --git a/platformio/commands/update.py b/platformio/commands/update.py index 52627a7a..42830dc2 100644 --- a/platformio/commands/update.py +++ b/platformio/commands/update.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,14 +15,13 @@ import click from platformio.commands.lib import lib_update as cmd_lib_update -from platformio.commands.platforms import \ - platforms_update as cmd_platforms_update +from platformio.commands.platform import platform_update as cmd_platform_update @click.command("update", short_help="Update installed Platforms, Packages and Libraries") @click.pass_context def cli(ctx): - ctx.invoke(cmd_platforms_update) + ctx.invoke(cmd_platform_update) click.echo() ctx.invoke(cmd_lib_update) diff --git a/platformio/exception.py b/platformio/exception.py index 78059eb2..ce3d7cc6 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -57,7 +57,7 @@ class BoardNotDefined(PlatformioException): class UnknownBoard(PlatformioException): - MESSAGE = "Unknown board type '{0}'" + MESSAGE = "Unknown board ID '{0}'" class UnknownFramework(PlatformioException): @@ -70,9 +70,16 @@ class UnknownPackage(PlatformioException): MESSAGE = "Detected unknown package '{0}'" -class InvalidPackageVersion(PlatformioException): +class UndefinedPackageVersion(PlatformioException): - MESSAGE = "The package '{0}' with version '{1:d}' does not exist" + MESSAGE = "Can not find package '{0}' with version requirements '{1}'"\ + " for your system '{2}'" + + +class PackageInstallError(PlatformioException): + + MESSAGE = "Can not install package '{0}' with version requirements '{1}' "\ + "for your system '{2}'" class NonSystemPackage(PlatformioException): diff --git a/platformio/maintenance.py b/platformio/maintenance.py index 34395604..0e82bb58 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,23 +14,19 @@ import re import struct -from os import getenv, remove -from os.path import isdir, isfile, join -from shutil import rmtree +from os import getenv from time import time import click from platformio import __version__, app, exception, telemetry, util from platformio.commands.lib import lib_update as cmd_libraries_update -from platformio.commands.platforms import \ - platforms_install as cmd_platforms_install -from platformio.commands.platforms import \ - platforms_update as cmd_platforms_update +from platformio.commands.platform import \ + platform_install as cmd_platform_install +from platformio.commands.platform import platform_update as cmd_platform_update from platformio.commands.upgrade import get_latest_version from platformio.libmanager import LibraryManager -from platformio.platforms.base import PlatformFactory -from platformio.util import get_home_dir +from platformio.managers.platform import PlatformManager def in_silence(ctx): @@ -72,10 +68,9 @@ class Upgrader(object): self.from_version = self.version_to_int(from_version) self.to_version = self.version_to_int(to_version) - self._upgraders = ( - (self.version_to_int("0.9.0"), self._upgrade_to_0_9_0), - (self.version_to_int("1.0.0"), self._upgrade_to_1_0_0) - ) + self._upgraders = [ + (self.version_to_int("3.0.0"), self._upgrade_to_3_0_0) + ] @staticmethod def version_to_int(version): @@ -91,38 +86,16 @@ class Upgrader(object): result = [True] for item in self._upgraders: - if self.from_version >= item[0]: + if self.from_version >= item[0] or self.to_version < item[0]: continue result.append(item[1](ctx)) return all(result) - def _upgrade_to_0_9_0(self, ctx): # pylint: disable=R0201 - prev_platforms = [] - - # remove platform's folder (obsolete package structure) - for name in PlatformFactory.get_platforms().keys(): - pdir = join(get_home_dir(), name) - if not isdir(pdir): - continue - prev_platforms.append(name) - rmtree(pdir) - - # remove unused files - for fname in (".pioupgrade", "installed.json"): - if isfile(join(get_home_dir(), fname)): - remove(join(get_home_dir(), fname)) - - if prev_platforms: - ctx.invoke(cmd_platforms_install, platforms=prev_platforms) - - return True - - def _upgrade_to_1_0_0(self, ctx): # pylint: disable=R0201 - installed_platforms = PlatformFactory.get_platforms( - installed=True).keys() + def _upgrade_to_3_0_0(self, ctx): # pylint: disable=R0201 + installed_platforms = app.get_state_item("installed_platforms", []) if installed_platforms: - ctx.invoke(cmd_platforms_install, platforms=installed_platforms) + ctx.invoke(cmd_platform_install, platforms=installed_platforms) return True @@ -131,10 +104,28 @@ def after_upgrade(ctx): if last_version == __version__: return - terminal_width, _ = click.get_terminal_size() + if last_version == "0.0.0": + app.set_state_item("last_version", __version__) + else: + click.secho("Please wait while upgrading PlatformIO ...", + fg="yellow") - # promotion - click.echo("") + u = Upgrader(last_version, __version__) + if u.run(ctx): + app.set_state_item("last_version", __version__) + ctx.invoke(cmd_platform_update, only_packages=True) + + click.secho("PlatformIO has been successfully upgraded to %s!\n" % + __version__, fg="green") + + telemetry.on_event(category="Auto", action="Upgrade", + label="%s > %s" % (last_version, __version__)) + else: + raise exception.UpgradeError("Auto upgrading...") + click.echo("") + + # PlatformIO banner + terminal_width, _ = click.get_terminal_size() click.echo("*" * terminal_width) click.echo("If you like %s, please:" % ( click.style("PlatformIO", fg="cyan") @@ -163,27 +154,6 @@ def after_upgrade(ctx): click.echo("*" * terminal_width) click.echo("") - if last_version == "0.0.0": - app.set_state_item("last_version", __version__) - return - - click.secho("Please wait while upgrading PlatformIO ...", - fg="yellow") - - u = Upgrader(last_version, __version__) - if u.run(ctx): - app.set_state_item("last_version", __version__) - ctx.invoke(cmd_platforms_update) - - click.secho("PlatformIO has been successfully upgraded to %s!\n" % - __version__, fg="green") - - telemetry.on_event(category="Auto", action="Upgrade", - label="%s > %s" % (last_version, __version__)) - else: - raise exception.UpgradeError("Auto upgrading...") - click.echo("") - def check_platformio_upgrade(): last_check = app.get_state_item("last_check", {}) @@ -234,10 +204,11 @@ def check_internal_updates(ctx, what): outdated_items = [] if what == "platforms": - for platform in PlatformFactory.get_platforms(installed=True).keys(): - p = PlatformFactory.newPlatform(platform) - if p.is_outdated(): - outdated_items.append(platform) + pm = PlatformManager() + for manifest in pm.get_installed(): + if pm.is_outdated(manifest['name'], manifest['version']): + outdated_items.append( + "%s@%s" % (manifest['name'], manifest['version'])) elif what == "libraries": lm = LibraryManager() outdated_items = lm.get_outdated() @@ -255,13 +226,13 @@ def check_internal_updates(ctx, what): if not app.get_setting("auto_update_" + what): click.secho("Please update them via ", fg="yellow", nl=False) click.secho("`platformio %s update`" % - ("lib" if what == "libraries" else "platforms"), + ("lib" if what == "libraries" else "platform"), fg="cyan", nl=False) click.secho(" command.", fg="yellow") else: click.secho("Please wait while updating %s ..." % what, fg="yellow") if what == "platforms": - ctx.invoke(cmd_platforms_update) + ctx.invoke(cmd_platform_update) elif what == "libraries": ctx.invoke(cmd_libraries_update) click.echo() diff --git a/platformio/managers/__init__.py b/platformio/managers/__init__.py new file mode 100644 index 00000000..5466a0e8 --- /dev/null +++ b/platformio/managers/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2014-present Ivan Kravets +# +# 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. diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 33f74bb7..7654109f 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,38 +12,41 @@ # See the License for the specific language governing permissions and # limitations under the License. -from os import makedirs, remove -from os.path import basename, isdir, isfile, join +import os +from os.path import dirname, isdir, isfile, join from shutil import rmtree -from time import time import click import requests +import semantic_version from platformio import exception, telemetry, util -from platformio.app import get_state_item, set_state_item from platformio.downloader import FileDownloader from platformio.unpacker import FileUnpacker class PackageManager(object): - def __init__(self): - self._package_dir = join(util.get_home_dir(), "packages") - if not isdir(self._package_dir): - makedirs(self._package_dir) - assert isdir(self._package_dir) + _INSTALLED_CACHE = {} - @classmethod - @util.memoized - def get_manifest(cls): - return util.get_api_result("/packages/manifest") + def __init__(self, package_dir=None, repositories=None): + self._INSTALLED_CACHE = {} + self.repositories = repositories + self.package_dir = package_dir or join(util.get_home_dir(), "packages") + if not isdir(self.package_dir): + os.makedirs(self.package_dir) + assert isdir(self.package_dir) + + @staticmethod + def reset_cache(): + PackageManager._INSTALLED_CACHE = {} @staticmethod def download(url, dest_dir, sha1=None): fd = FileDownloader(url, dest_dir) fd.start() - fd.verify(sha1) + if sha1: + fd.verify(sha1) return fd.get_filepath() @staticmethod @@ -52,98 +55,180 @@ class PackageManager(object): return fu.start() @staticmethod - def get_installed(): - return get_state_item("installed_packages", {}) + def get_manifest_name(): + return "package.json" - def get_outdated(self): - outdated = [] - for name, data in self.get_installed().items(): - if data['version'] != self.get_info(name)['version']: - outdated.append(name) - return outdated - - def is_installed(self, name): - return name in self.get_installed() - - def get_info(self, name, version=None): - manifest = self.get_manifest() - if name not in manifest: - raise exception.UnknownPackage(name) - - # check system platform + @staticmethod + def max_satisfying_version(versions, requirements=None): + item = None systype = util.get_systype() - builds = ([b for b in manifest[name] if b['system'] == "all" or systype - in b['system']]) - if not builds: - raise exception.NonSystemPackage(name, systype) + if requirements is not None: + requirements = str(requirements) + for v in versions: + if isinstance(v['version'], int): + continue + if v['system'] not in ("all", "*") and systype not in v['system']: + continue + if requirements and not semantic_version.match( + requirements, v['version']): + continue + if item is None or semantic_version.compare( + v['version'], item['version']) == 1: + item = v + return item - if version: - for b in builds: - if b['version'] == version: - return b - raise exception.InvalidPackageVersion(name, version) - else: - return sorted(builds, key=lambda s: s['version'])[-1] + def get_installed(self): + if self.package_dir in PackageManager._INSTALLED_CACHE: + return PackageManager._INSTALLED_CACHE[self.package_dir] + items = [] + for p in sorted(os.listdir(self.package_dir)): + manifest_path = join(self.package_dir, p, self.get_manifest_name()) + if not isfile(manifest_path): + continue + manifest = util.load_json(manifest_path) + manifest['_manifest_path'] = manifest_path + assert set(["name", "version"]) <= set(manifest.keys()) + items.append(manifest) + PackageManager._INSTALLED_CACHE[self.package_dir] = items + return items - def install(self, name): - click.echo("Installing %s package:" % click.style(name, fg="cyan")) + def is_installed(self, name, requirements=None): + installed = self.get_installed() + if requirements is None: + return any([p['name'] == name for p in installed]) - if self.is_installed(name): - click.secho("Already installed", fg="yellow") - return False + for p in installed: + if p['name'] != name: + continue + elif semantic_version.match(requirements, p['version']): + return True + return None - info = self.get_info(name) - pkg_dir = join(self._package_dir, name) - if not isdir(pkg_dir): - makedirs(pkg_dir) + def get_latest_version(self, name, requirements): + for versions in PackageRepoIterator(name, self.repositories): + pkgdata = self.max_satisfying_version(versions, requirements) + if pkgdata: + return pkgdata['version'] + return None - dlpath = None - try: - dlpath = self.download(info['url'], pkg_dir, info['sha1']) - except (requests.exceptions.ConnectionError, - requests.exceptions.ChunkedEncodingError, - requests.exceptions.SSLError, - exception.FDUnrecognizedStatusCode, StopIteration): - if not info['url'].startswith("http://dl.platformio.org"): + def install(self, name, requirements, silent=False, trigger_event=True): + installed = self.is_installed(name, requirements) + if not installed or not silent: + click.echo("Installing package %s @ %s:" % ( + click.style(name, fg="cyan"), + requirements if requirements else "latest")) + if installed: + if not silent: + click.secho("Already installed", fg="yellow") + return + + if not self._install_from_piorepo(name, requirements): + raise exception.PackageInstallError( + name, requirements, util.get_systype()) + + self.reset_cache() + if trigger_event: + telemetry.on_event( + category="PackageManager", action="Install", label=name) + + def _install_from_piorepo(self, name, requirements): + pkg_dir = None + success = False + pkgdata = None + versions = None + for versions in PackageRepoIterator(name, self.repositories): + dlpath = None + pkgdata = self.max_satisfying_version(versions, requirements) + if not pkgdata: + continue + + pkg_dir = join(self.package_dir, name) + if isfile(join(pkg_dir, self.get_manifest_name())): + pkg_dir = join( + self.package_dir, "%s@%s" % (name, pkgdata['version'])) + + # remove previous/not-satisfied package + if isdir(pkg_dir): + rmtree(pkg_dir) + os.makedirs(pkg_dir) + + try: dlpath = self.download( - "http://dl.platformio.org/packages/%s" % - basename(info['url']), pkg_dir, info['sha1']) + pkgdata['url'], pkg_dir, pkgdata.get("sha1")) + assert isfile(dlpath) + self.unpack(dlpath, pkg_dir) + success = True + break + except Exception as e: # pylint: disable=broad-except + click.secho("Warning! Package Mirror: %s" % e, fg="yellow") + click.secho("Looking for other Package Mirror...", fg="yellow") + finally: + if dlpath and isfile(dlpath): + os.remove(dlpath) - assert isfile(dlpath) + if versions is None: + raise exception.UnknownPackage(name) + elif not pkgdata: + raise exception.UndefinedPackageVersion( + name, requirements, util.get_systype()) - if self.unpack(dlpath, pkg_dir): - self._register(name, info['version']) - # remove archive - remove(dlpath) + return success - telemetry.on_event( - category="PackageManager", action="Install", label=name) + def uninstall(self, name, requirements=None, trigger_event=True): + click.echo("Uninstalling package %s @ %s: \t" % ( + click.style(name, fg="cyan"), + requirements if requirements else "latest"), nl=False) + found = False + for manifest in self.get_installed(): + if manifest['name'] != name: + continue + if (requirements and not semantic_version.match( + requirements, manifest['version'])): + continue + found = True + if isfile(manifest['_manifest_path']): + rmtree(dirname(manifest['_manifest_path'])) - def uninstall(self, name): - click.echo("Uninstalling %s package: \t" % - click.style(name, fg="cyan"), nl=False) - - if not self.is_installed(name): + if not found: click.secho("Not installed", fg="yellow") return False + else: + click.echo("[%s]" % click.style("OK", fg="green")) - if isdir(join(self._package_dir, name)): - rmtree(join(self._package_dir, name)) - self._unregister(name) - click.echo("[%s]" % click.style("OK", fg="green")) + self.reset_cache() + if trigger_event: + telemetry.on_event( + category="PackageManager", action="Uninstall", label=name) - # report usage - telemetry.on_event( - category="PackageManager", action="Uninstall", label=name) + def update(self, name, requirements=None, keep_versions=None): + click.echo("Updating package %s @ %s:" % ( + click.style(name, fg="yellow"), + requirements if requirements else "latest")) - def update(self, name): - click.echo("Updating %s package:" % click.style(name, fg="yellow")) + latest_version = self.get_latest_version(name, requirements) + if latest_version is None: + click.secho("Ignored! '%s' is not listed in " + "Package Repository" % name, fg="yellow") + return - installed = self.get_installed() - current_version = installed[name]['version'] - latest_version = self.get_info(name)['version'] + current = None + other_versions = [] + for manifest in self.get_installed(): + if manifest['name'] != name: + continue + other_versions.append(manifest['version']) + if (requirements and not semantic_version.match( + requirements, manifest['version'])): + continue + if (not current or semantic_version.compare( + manifest['version'], current['version']) == 1): + current = manifest - click.echo("Versions: Current=%d, Latest=%d \t " % + if current is None: + return + + current_version = current['version'] + click.echo("Versions: Current=%s, Latest=%s \t " % (current_version, latest_version), nl=False) if current_version == latest_version: @@ -152,21 +237,52 @@ class PackageManager(object): else: click.echo("[%s]" % (click.style("Out-of-date", fg="red"))) - self.uninstall(name) - self.install(name) + for v in other_versions: + if not keep_versions or v not in keep_versions: + self.uninstall(name, v, trigger_event=False) + self.install(name, latest_version, trigger_event=False) telemetry.on_event( category="PackageManager", action="Update", label=name) + return True - def _register(self, name, version): - data = self.get_installed() - data[name] = { - "version": version, - "time": int(time()) - } - set_state_item("installed_packages", data) - def _unregister(self, name): - data = self.get_installed() - del data[name] - set_state_item("installed_packages", data) +class PackageRepoIterator(object): + + _MANIFEST_CACHE = {} + + def __init__(self, package, repositories): + assert isinstance(repositories, list) + self.package = package + self.repositories = iter(repositories) + + def __iter__(self): + return self + + def __next__(self): + return self.next() + + def next(self): + manifest = {} + repo = next(self.repositories) + if isinstance(repo, dict): + manifest = repo + elif repo in PackageRepoIterator._MANIFEST_CACHE: + manifest = PackageRepoIterator._MANIFEST_CACHE[repo] + else: + r = None + try: + r = requests.get(repo, headers=util.get_request_defheaders()) + r.raise_for_status() + manifest = r.json() + except: # pylint: disable=bare-except + pass + finally: + if r: + r.close() + PackageRepoIterator._MANIFEST_CACHE[repo] = manifest + + if self.package in manifest: + return manifest[self.package] + else: + return self.next() diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 8486967d..2526ad29 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,251 +18,234 @@ import re import sys from imp import load_source from multiprocessing import cpu_count -from os.path import isdir, isfile, join +from os.path import basename, dirname, isdir, isfile, join import click +import semantic_version -from platformio import app, exception, util -from platformio.app import get_state_item, set_state_item -from platformio.pkgmanager import PackageManager - -PLATFORM_PACKAGES = { - - "framework-arduinoavr": [ - ("Arduino Wiring-based Framework (AVR Core, 1.6)", - "http://arduino.cc/en/Reference/HomePage") - ], - "framework-arduinosam": [ - ("Arduino Wiring-based Framework (SAM Core, 1.6)", - "http://arduino.cc/en/Reference/HomePage") - ], - "framework-arduinoteensy": [ - ("Arduino Wiring-based Framework", - "http://arduino.cc/en/Reference/HomePage") - ], - "framework-arduinomsp430": [ - ("Arduino Wiring-based Framework (MSP430 Core)", - "http://arduino.cc/en/Reference/HomePage") - ], - "framework-arduinoespressif": [ - ("Arduino Wiring-based Framework (ESP8266 Core)", - "https://github.com/esp8266/Arduino") - ], - "framework-arduinomicrochippic32": [ - ("Arduino Wiring-based Framework (PIC32 Core)", - "https://github.com/chipKIT32/chipKIT-core") - ], - "framework-arduinointel": [ - ("Arduino Wiring-based Framework (Intel ARC Core)", - "https://github.com/01org/corelibs-arduino101") - ], - "framework-arduinonordicnrf51": [ - ("Arduino Wiring-based Framework (RFduino Core)", - "https://github.com/RFduino/RFduino") - ], - "framework-energiamsp430": [ - ("Energia Wiring-based Framework (MSP430 Core)", - "http://energia.nu/reference/") - ], - "framework-energiativa": [ - ("Energia Wiring-based Framework (LM4F Core)", - "http://energia.nu/reference/") - ], - "framework-cmsis": [ - ("Vendor-independent hardware abstraction layer for the Cortex-M " - "processor series", - "http://www.arm.com/products/processors/" - "cortex-m/cortex-microcontroller-software-interface-standard.php") - ], - "framework-spl": [ - ("Standard Peripheral Library for STM32 MCUs", - "http://www.st.com" - "/web/catalog/tools/FM147/CL1794/SC961/SS1743/PF257890") - ], - "framework-libopencm3": [ - ("libOpenCM3 Framework", "http://www.libopencm3.org/") - ], - "framework-mbed": [ - ("mbed Framework", "http://mbed.org") - ], - "framework-wiringpi": [ - ("GPIO Interface library for the Raspberry Pi", "http://wiringpi.com") - ], - "framework-simba": [ - ("Simba Framework", "https://github.com/eerimoq/simba") - ], - "sdk-esp8266": [ - ("ESP8266 SDK", "http://bbs.espressif.com") - ], - "ldscripts": [ - ("Linker Scripts", - "https://sourceware.org/binutils/docs/ld/Scripts.html") - ], - "toolchain-atmelavr": [ - ("avr-gcc", "https://gcc.gnu.org/wiki/avr-gcc"), - ("GDB", "http://www.gnu.org/software/gdb/"), - ("AVaRICE", "http://avarice.sourceforge.net/"), - ("SimulAVR", "http://www.nongnu.org/simulavr/") - ], - "toolchain-gccarmnoneeabi": [ - ("gcc-arm-embedded", "https://launchpad.net/gcc-arm-embedded"), - ("GDB", "http://www.gnu.org/software/gdb/") - ], - "toolchain-gccarmlinuxgnueabi": [ - ("GCC for Linux ARM GNU EABI", "https://gcc.gnu.org"), - ("GDB", "http://www.gnu.org/software/gdb/") - ], - "toolchain-gccmingw32": [ - ("MinGW", "http://www.mingw.org") - ], - "toolchain-gcclinux32": [ - ("GCC for Linux i686", "https://gcc.gnu.org") - ], - "toolchain-gcclinux64": [ - ("GCC for Linux x86_64", "https://gcc.gnu.org") - ], - "toolchain-xtensa": [ - ("xtensa-gcc", "https://github.com/jcmvbkbc/gcc-xtensa"), - ("GDB", "http://www.gnu.org/software/gdb/") - ], - "toolchain-timsp430": [ - ("msp-gcc", "http://sourceforge.net/projects/mspgcc/"), - ("GDB", "http://www.gnu.org/software/gdb/") - ], - "toolchain-icestorm": [ - ("GCC for FPGA IceStorm", "http://www.clifford.at/icestorm/") - ], - "toolchain-microchippic32": [ - ("GCC for Microchip PIC32", "https://github.com/chipKIT32/chipKIT-cxx") - ], - "toolchain-intelarc32": [ - ("GCC for Intel ARC", - "https://github.com/foss-for-synopsys-dwc-arc-processors/toolchain") - ], - "tool-scons": [ - ("SCons software construction tool", "http://www.scons.org") - ], - "tool-avrdude": [ - ("AVRDUDE", "http://www.nongnu.org/avrdude/") - ], - "tool-micronucleus": [ - ("Micronucleus", "https://github.com/micronucleus/micronucleus") - ], - "tool-bossac": [ - ("BOSSA CLI", "https://sourceforge.net/projects/b-o-s-s-a/") - ], - "tool-openocd": [ - ("OpenOCD", "http://openocd.org") - ], - "tool-stlink": [ - ("ST-Link", "https://github.com/texane/stlink") - ], - "tool-teensy": [ - ("Teensy Loader", "https://www.pjrc.com/teensy/loader.html") - ], - "tool-lm4flash": [ - ("Flash Programmer", "http://www.ti.com/tool/lmflashprogrammer") - ], - "tool-mspdebug": [ - ("MSPDebug", "http://mspdebug.sourceforge.net/") - ], - "tool-esptool": [ - ("esptool-ck", "https://github.com/igrr/esptool-ck") - ], - "tool-rfdloader": [ - ("rfdloader", "https://github.com/RFduino/RFduino") - ], - "tool-mkspiffs": [ - ("Tool to build and unpack SPIFFS images", - "https://github.com/igrr/mkspiffs") - ], - "tool-pic32prog": [ - ("pic32prog", "https://github.com/sergev/pic32prog") - ], - "tool-arduino101load": [ - ("Genuino101 uploader", "https://github.com/01org/intel-arduino-tools") - ] -} +from platformio import exception, util +from platformio.managers.package import PackageManager -def get_packages(): - return PLATFORM_PACKAGES +class PlatformManager(PackageManager): + + def __init__(self): + PackageManager.__init__( + self, + join(util.get_home_dir(), "platforms"), + ["http://dl.platformio.org/misc/platforms_manifest.json"] + ) + + @staticmethod + def get_manifest_name(): + return "platform.json" + + def find_best_platform(self, name, requirements=None): + best = None + for manifest in self.get_installed(): + if manifest['name'] != name: + continue + elif requirements and not semantic_version.match( + requirements, manifest['version']): + continue + elif (not best or semantic_version.compare( + manifest['version'], best['version']) == 1): + best = manifest + return best + + def install(self, # pylint: disable=too-many-arguments,arguments-differ + name, requirements=None, with_packages=None, + without_packages=None, skip_default_packages=False): + PackageManager.install(self, name, requirements) + return PlatformFactory.newPlatform( + name, requirements).install_packages( + with_packages, without_packages, skip_default_packages) + + def uninstall(self, # pylint: disable=arguments-differ + name, requirements=None): + if PlatformFactory.newPlatform( + name, requirements).uninstall_packages(): + return PackageManager.uninstall(self, name, requirements) + return False + + def update(self, name, version): + raise NotImplementedError() + + def is_outdated(self, name, version): + raise NotImplementedError() + + def get_installed_boards(self): + boards = [] + for manifest in self.get_installed(): + p = PlatformFactory.newPlatform(manifest['_manifest_path']) + for id_, config in p.get_boards().items(): + manifest = config.get_manifest().copy() + manifest['id'] = id_ + manifest['platform'] = p.get_name() + boards.append(manifest) + return boards + + @staticmethod + @util.memoized + def get_registered_boards(): + boards = util.get_api_result("/boards") + for item in boards: + # @TODO remove type from API + item['id'] = item['type'] + del item['type'] + return boards class PlatformFactory(object): @staticmethod - def get_clsname(type_): - return "%s%sPlatform" % (type_.upper()[0], type_.lower()[1:]) + def get_clsname(name): + return "%s%sPlatform" % (name.upper()[0], name.lower()[1:]) @staticmethod - def load_module(type_, path): + def load_module(name, path): module = None try: module = load_source( - "platformio.platforms.%s" % type_, path) + "platformio.managers.platform.%s" % name, path) except ImportError: - raise exception.UnknownPlatform(type_) + raise exception.UnknownPlatform(name) return module @classmethod - @util.memoized - def _lookup_platforms(cls): - platforms = {} - for d in (util.get_home_dir(), util.get_source_dir()): - pdir = join(d, "platforms") - if not isdir(pdir): - continue - for p in sorted(os.listdir(pdir)): - if (p in ("__init__.py", "base.py") or not - p.endswith(".py")): - continue - type_ = p[:-3] - path = join(pdir, p) - try: - isplatform = hasattr( - cls.load_module(type_, path), - cls.get_clsname(type_) - ) - if isplatform: - platforms[type_] = path - except exception.UnknownPlatform: - pass - return platforms + def newPlatform(cls, name, requirements=None): + platform_dir = None + if name.endswith("platform.json") and isfile(name): + platform_dir = dirname(name) + name = util.load_json(name)['name'] + else: + _manifest = PlatformManager().find_best_platform( + name, requirements) + if _manifest: + platform_dir = dirname(_manifest['_manifest_path']) + if not platform_dir: + raise exception.UnknownPlatform( + name if not requirements else "%s@%s" % (name, requirements)) - @classmethod - def get_platforms(cls, installed=False): - platforms = cls._lookup_platforms() + platform_cls = None + if isfile(join(platform_dir, "platform.py")): + platform_cls = getattr( + cls.load_module(name, join(platform_dir, "platform.py")), + cls.get_clsname(name) + ) + else: + platform_cls = type( + str(cls.get_clsname(name)), (BasePlatform,), {}) - if not installed: - return platforms - - installed_platforms = {} - for type_ in get_state_item("installed_platforms", []): - if type_ in platforms: - installed_platforms[type_] = platforms[type_] - return installed_platforms - - @classmethod - def newPlatform(cls, type_): - platforms = cls.get_platforms() - if type_ not in platforms: - raise exception.UnknownPlatform(type_) - - _instance = getattr( - cls.load_module(type_, platforms[type_]), - cls.get_clsname(type_) - )() + _instance = platform_cls(join(platform_dir, "platform.json")) assert isinstance(_instance, BasePlatform) return _instance -class BasePlatform(object): +class PlatformPackagesMixin(object): + + def get_installed_packages(self): + items = {} + installed = self.pm.get_installed() + for name, opts in self.get_packages().items(): + manifest = None + for p in installed: + if (p['name'] != name or not semantic_version.match( + opts['version'], p['version'])): + continue + elif (not manifest or semantic_version.compare( + p['version'], manifest['version']) == 1): + manifest = p + if manifest: + items[name] = manifest + return items + + def install_packages(self, with_packages=None, without_packages=None, + skip_default_packages=False, silent=False): + with_packages = set( + self.pkg_types_to_names(with_packages or [])) + without_packages = set( + self.pkg_types_to_names(without_packages or [])) + + upkgs = with_packages | without_packages + ppkgs = set(self.get_packages().keys()) + if not upkgs.issubset(ppkgs): + raise exception.UnknownPackage(", ".join(upkgs - ppkgs)) + + for name, opts in self.get_packages().items(): + if name in without_packages: + continue + elif (name in with_packages or + not (skip_default_packages or opts.get("optional", False))): + self.pm.install(name, opts.get("version"), silent=silent) + + return True + + def uninstall_packages(self): + deppkgs = set() + for manifest in PlatformManager().get_installed(): + if manifest['name'] == self.get_name(): + continue + p = PlatformFactory.newPlatform( + manifest['name'], manifest['version']) + for pkgname, pkgmanifest in p.get_installed_packages().items(): + deppkgs.add((pkgname, pkgmanifest['version'])) + + for manifest in self.pm.get_installed(): + if manifest['name'] not in self.get_packages().keys(): + continue + if (manifest['name'], manifest['version']) not in deppkgs: + self.pm.uninstall(manifest['name'], manifest['version']) + return True + + def update_packages(self): + outdated = None + for pkgname, pkgmanifest in self.get_installed_packages().items(): + requirements = self.get_packages()[pkgname]['version'] + latest_version = self.pm.get_latest_version( + pkgname, requirements) + if (not latest_version or + pkgmanifest['version'] == latest_version): + continue + + # check other platforms + keep_versions = set([latest_version]) + for pfmanifest in PlatformManager().get_installed(): + if pfmanifest['name'] == self.get_name(): + continue + p = PlatformFactory.newPlatform( + pfmanifest['name'], pfmanifest['version']) + if pkgname not in p.get_packages(): + continue + keep_versions.add(p.pm.get_latest_version( + pkgname, p.get_packages()[pkgname]['version'])) + + outdated = self.pm.update( + pkgname, requirements, keep_versions) + return outdated + + def are_outdated_packages(self): + for name, opts in self.get_installed_packages().items(): + if (opts['version'] != self.pm.get_latest_version( + name, self.get_packages()[name].get("version"))): + return True + return False + + +class BasePlatform(PlatformPackagesMixin): + + _BOARDS_CACHE = {} - PACKAGES = {} LINE_ERROR_RE = re.compile(r"(\s+error|error[:\s]+)", re.I) - def __init__(self): + def __init__(self, manifest_path): + self._BOARDS_CACHE = {} + self.manifest_path = manifest_path + self.manifest = util.load_json(manifest_path) + + self.pm = PackageManager( + repositories=self.manifest.get("packageRepositories")) + self._found_error = False self._last_echo_line = None @@ -271,182 +254,125 @@ class BasePlatform(object): # 3 = 2 + others self._verbose_level = 3 - def get_type(self): - return self.__class__.__name__[:-8].lower() - def get_name(self): - return self.get_type().title() + return self.manifest['name'] - def get_build_script(self): - builtin = join(util.get_source_dir(), "builder", "scripts", "%s.py" % - self.get_type()) - if isfile(builtin): - return builtin - raise NotImplementedError() + def get_title(self): + return self.manifest['title'] def get_description(self): - if self.__doc__: - doclines = [l.strip() for l in self.__doc__.splitlines() if - l.strip()] - return " ".join(doclines[:-1]).strip() - else: - raise NotImplementedError() + return self.manifest['description'] - def get_vendor_url(self): - if self.__doc__ and "http" in self.__doc__: - return self.__doc__[self.__doc__.index("http"):].strip() - else: - raise NotImplementedError() + def get_version(self): + return self.manifest['version'] + + def get_manifest(self): + return self.manifest + + def get_dir(self): + return dirname(self.manifest_path) + + def get_build_script(self): + main_script = join(self.get_dir(), "builder", "main.py") + if isfile(main_script): + return main_script + raise NotImplementedError() def is_embedded(self): - for name, opts in self.get_packages().items(): - if name == "framework-mbed" or opts.get("alias") == "uploader": + for opts in self.get_packages().values(): + if opts.get("type") == "uploader": return True return False + def get_boards(self, id_=None): + if id_ is None: + boards_dir = join(self.get_dir(), "boards") + if not isdir(boards_dir): + return {} + for item in sorted(os.listdir(boards_dir)): + _id = item[:-5] + if _id in self._BOARDS_CACHE: + continue + self._BOARDS_CACHE[_id] = PlatformBoardConfig( + join(self.get_dir(), "boards", item) + ) + else: + if id_ not in self._BOARDS_CACHE: + self._BOARDS_CACHE[id_] = PlatformBoardConfig( + join(self.get_dir(), "boards", "%s.json" % id_) + ) + return self._BOARDS_CACHE[id_] if id_ else self._BOARDS_CACHE + + def board_config(self, id_): + return self.get_boards(id_) + def get_packages(self): - return self.PACKAGES + return self.manifest.get("packages", {}) - def get_package_alias(self, pkgname): - return self.PACKAGES[pkgname].get("alias") + def get_frameworks(self): + return self.get_manifest().get("frameworks") - def pkg_aliases_to_names(self, aliases): + def get_package_dir(self, name): + packages = self.get_installed_packages() + if name not in packages: + return None + return dirname(packages[name]['_manifest_path']) + + def get_package_version(self, name): + packages = self.get_installed_packages() + if name not in packages: + return None + return packages[name]['version'] + + def get_package_type(self, name): + return self.get_packages()[name].get("type") + + def pkg_types_to_names(self, types): names = [] - for alias in aliases: - name = alias - # lookup by package aliases + for type_ in types: + name = type_ + # lookup by package types for _name, _opts in self.get_packages().items(): - if _opts.get("alias") == alias: + if _opts.get("type") == type_: name = None names.append(_name) - # if alias is the right name + # if type is the right name if name: names.append(name) return names - def get_default_packages(self): - return [k for k, v in self.get_packages().items() - if v.get("default", False)] - - def get_installed_packages(self): - pm = PackageManager() - return [n for n in self.get_packages().keys() if pm.is_installed(n)] - - def install(self, with_packages=None, without_packages=None, - skip_default_packages=False): - with_packages = set( - self.pkg_aliases_to_names(with_packages or [])) - without_packages = set( - self.pkg_aliases_to_names(without_packages or [])) - - upkgs = with_packages | without_packages - ppkgs = set(self.get_packages().keys()) - if not upkgs.issubset(ppkgs): - raise exception.UnknownPackage(", ".join(upkgs - ppkgs)) - - requirements = [] - for name, opts in self.get_packages().items(): - if name in without_packages: - continue - elif (name in with_packages or (not skip_default_packages and - opts.get("default"))): - requirements.append(name) - - pm = PackageManager() - for name in requirements: - pm.install(name) - - # register installed platform - data = get_state_item("installed_platforms", []) - if self.get_type() not in data: - data.append(self.get_type()) - set_state_item("installed_platforms", data) - - return len(requirements) - - def uninstall(self): - platform = self.get_type() - installed_platforms = PlatformFactory.get_platforms( - installed=True).keys() - - if platform not in installed_platforms: - raise exception.PlatformNotInstalledYet(platform) - - deppkgs = set() - for item in installed_platforms: - if item == platform: - continue - p = PlatformFactory.newPlatform(item) - deppkgs = deppkgs.union(set(p.get_packages().keys())) - - pm = PackageManager() - for name in self.get_packages().keys(): - if not pm.is_installed(name) or name in deppkgs: - continue - pm.uninstall(name) - - # unregister installed platform - installed_platforms.remove(platform) - set_state_item("installed_platforms", installed_platforms) - - return True - - def update(self): - pm = PackageManager() - for name in self.get_installed_packages(): - pm.update(name) - - def is_outdated(self): - pm = PackageManager() - obsolated = pm.get_outdated() - return not set(self.get_packages().keys()).isdisjoint(set(obsolated)) - def configure_default_packages(self, variables, targets): # enbale used frameworks - for pkg_name in self.pkg_aliases_to_names(["framework"]): - for framework in variables.get("framework", "").split(","): - framework = framework.lower().strip() - if not framework: - continue - if framework in pkg_name: - self.PACKAGES[pkg_name]['default'] = True + frameworks = self.get_frameworks() + for framework in variables.get("framework", "").split(","): + framework = framework.lower().strip() + if not framework or framework not in frameworks: + continue + _pkg_name = frameworks[framework]['package'] + self.get_packages()[_pkg_name]['optional'] = False # append SCons tool - self.PACKAGES['tool-scons'] = {"default": True} + self.get_packages()['tool-scons'] = { + "version": self.manifest.get("engines", {}).get( + "scons", ">=2.3.0,<2.5.0"), + "optional": False + } # enable upload tools for upload targets if any(["upload" in t for t in targets] + ["program" in targets]): - for _name, _opts in self.PACKAGES.iteritems(): - if _opts.get("alias") == "uploader": - self.PACKAGES[_name]['default'] = True + for _name, _opts in self.get_packages().iteritems(): + if _opts.get("type") == "uploader": + self.get_packages()[_name]['optional'] = False elif "uploadlazy" in targets: # skip all packages, allow only upload tools - self.PACKAGES[_name]['default'] = False - - def _install_default_packages(self): - installed_platforms = PlatformFactory.get_platforms( - installed=True).keys() - - if (self.get_type() in installed_platforms and - set(self.get_default_packages()) <= - set(self.get_installed_packages())): - return True - - if (not app.get_setting("enable_prompts") or - self.get_type() in installed_platforms or - click.confirm( - "The platform '%s' has not been installed yet. " - "Would you like to install it now?" % self.get_type())): - return self.install() - else: - raise exception.PlatformNotInstalledYet(self.get_type()) + self.get_packages()[_name]['optional'] = True def run(self, variables, targets, verbose): assert isinstance(variables, dict) assert isinstance(targets, list) self.configure_default_packages(variables, targets) - self._install_default_packages() + self.install_packages(silent=True) self._verbose_level = int(verbose) @@ -454,18 +380,13 @@ class BasePlatform(object): targets.remove("clean") targets.append("-c") + variables['platform_manifest'] = self.manifest_path + if "build_script" not in variables: variables['build_script'] = self.get_build_script() if not isfile(variables['build_script']): raise exception.BuildScriptNotFound(variables['build_script']) - # append aliases of the installed packages - installed_packages = PackageManager.get_installed() - for name, options in self.get_packages().items(): - if "alias" not in options or name not in installed_packages: - continue - variables['piopackage_%s' % options['alias']] = name - self._found_error = False result = self._run_scons(variables, targets) assert "returncode" in result @@ -542,3 +463,34 @@ class BasePlatform(object): return cpu_count() except NotImplementedError: return 1 + + +class PlatformBoardConfig(object): + + def __init__(self, manifest_path): + if not isfile(manifest_path): + raise exception.UnknownBoard(basename(manifest_path[:-5])) + self.manifest_path = manifest_path + self.manifest = util.load_json(manifest_path) + + def get(self, path, default=None): + try: + value = self.manifest + for k in path.split("."): + value = value[k] + return value + except KeyError: + if default is not None: + return default + else: + raise KeyError("Invalid board option '%s'" % path) + + def __contains__(self, key): + try: + self.get(key) + return True + except KeyError: + return False + + def get_manifest(self): + return self.manifest diff --git a/platformio/util.py b/platformio/util.py index 6dc1bd5e..dd6026e9 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -375,32 +375,6 @@ def get_api_result(path, params=None, data=None, skipdns=False): return result -@memoized -def _lookup_boards(): - boards = {} - bdirs = [join(get_source_dir(), "boards")] - if isdir(join(get_home_dir(), "boards")): - bdirs.append(join(get_home_dir(), "boards")) - - for bdir in bdirs: - for json_file in sorted(os.listdir(bdir)): - if not json_file.endswith(".json"): - continue - boards.update(load_json(join(bdir, json_file))) - return boards - - -def get_boards(type_=None): - boards = _lookup_boards() - - if type_ is None: - return boards - else: - if type_ not in boards: - raise exception.UnknownBoard(type_) - return boards[type_] - - @memoized def _lookup_frameworks(): frameworks = {} diff --git a/setup.py b/setup.py index 83d9acb9..d228de9c 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ install_requires = [ "click>=3.2,<6", "lockfile>=0.9.1,<0.13", "requests>=2.4.0,<3", + "semantic_version>=2.5.0", "colorama", "pyserial<4" ] @@ -45,7 +46,6 @@ setup( package_data={ "platformio": [ "projectconftpl.ini", - "boards/*.json", "ide/tpls/*/.*.tpl", "ide/tpls/*/*.tpl", "ide/tpls/*/*/*.tpl", From 9a1f1ddb8bcf831c07b5bde3e121a2da0072b47a Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 26 May 2016 22:33:17 +0300 Subject: [PATCH 003/284] Allow to install development platform from local directory // Issue #479 --- docs/userguide/platforms/cmd_install.rst | 7 +- platformio/downloader.py | 5 +- platformio/exception.py | 5 + platformio/managers/package.py | 112 +++++++++++++++++------ platformio/managers/platform.py | 4 +- 5 files changed, 101 insertions(+), 32 deletions(-) diff --git a/docs/userguide/platforms/cmd_install.rst b/docs/userguide/platforms/cmd_install.rst index b3753537..86b678af 100644 --- a/docs/userguide/platforms/cmd_install.rst +++ b/docs/userguide/platforms/cmd_install.rst @@ -21,14 +21,17 @@ Usage .. code-block:: bash + # install platform by name platformio platform install [OPTIONS] [PLATFORMS] + # install platform from local directory + platformio platform install [OPTIONS] [file:///local/path/to/platform/dir] + Description ----------- -Install pre-built development :ref:`platforms` with related -packages. +Install development :ref:`platforms` and dependent packages. There are several predefined aliases for packages, such as: diff --git a/platformio/downloader.py b/platformio/downloader.py index bbb90e07..891e7bf5 100644 --- a/platformio/downloader.py +++ b/platformio/downloader.py @@ -53,7 +53,7 @@ class FileDownloader(object): return self._destination def get_lmtime(self): - return self._request.headers['last-modified'] + return self._request.headers.get("last-modified") def get_size(self): if "content-length" not in self._request.headers: @@ -77,7 +77,8 @@ class FileDownloader(object): f.close() self._request.close() - self._preserve_filemtime(self.get_lmtime()) + if self.get_lmtime(): + self._preserve_filemtime(self.get_lmtime()) def verify(self, sha1=None): _dlsize = getsize(self._destination) diff --git a/platformio/exception.py b/platformio/exception.py index ce3d7cc6..39630594 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -70,6 +70,11 @@ class UnknownPackage(PlatformioException): MESSAGE = "Detected unknown package '{0}'" +class InvalidLocalPackage(PlatformioException): + + MESSAGE = "Invalid local package '{0}'. Can not find manifest '{1}'" + + class UndefinedPackageVersion(PlatformioException): MESSAGE = "Can not find package '{0}' with version requirements '{1}'"\ diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 7654109f..c1e94f1c 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -14,7 +14,7 @@ import os from os.path import dirname, isdir, isfile, join -from shutil import rmtree +from shutil import copyfile, copytree, rmtree import click import requests @@ -41,6 +41,10 @@ class PackageManager(object): def reset_cache(): PackageManager._INSTALLED_CACHE = {} + @staticmethod + def get_manifest_name(): + return "package.json" + @staticmethod def download(url, dest_dir, sha1=None): fd = FileDownloader(url, dest_dir) @@ -50,13 +54,56 @@ class PackageManager(object): return fd.get_filepath() @staticmethod - def unpack(pkgpath, dest_dir): - fu = FileUnpacker(pkgpath, dest_dir) + def unpack(source_path, dest_dir): + fu = FileUnpacker(source_path, dest_dir) return fu.start() - @staticmethod - def get_manifest_name(): - return "package.json" + def check_structure(self, pkg_dir): + if isfile(join(pkg_dir, self.get_manifest_name())): + return True + + for root, _, files in os.walk(pkg_dir): + if self.get_manifest_name() not in files: + continue + # copy contents to the root of package directory + for item in os.listdir(root): + item_path = join(root, item) + if isfile(item_path): + copyfile(item_path, join(pkg_dir, item)) + elif isdir(item_path): + copytree(item_path, join(pkg_dir, item), symlinks=True) + # remove not used contents + while True: + rmtree(root) + root = dirname(root) + if root == pkg_dir: + break + break + + if isfile(join(pkg_dir, self.get_manifest_name())): + return True + + raise exception.PlatformioException( + "Could not find '%s' manifest file in the package" % + self.get_manifest_name()) + + def make_pkg_dir(self, name, version): + pkg_dir = join(self.package_dir, name) + if isfile(join(pkg_dir, self.get_manifest_name())): + _manifest = util.load_json( + join(pkg_dir, self.get_manifest_name())) + if (_manifest['name'] == name and + _manifest['version'] != version): + pkg_dir = join( + self.package_dir, "%s@%s" % (name, version)) + + # remove previous/not-satisfied package + if isdir(pkg_dir): + rmtree(pkg_dir) + os.makedirs(pkg_dir) + assert isdir(pkg_dir) + + return pkg_dir @staticmethod def max_satisfying_version(versions, requirements=None): @@ -114,7 +161,8 @@ class PackageManager(object): def install(self, name, requirements, silent=False, trigger_event=True): installed = self.is_installed(name, requirements) if not installed or not silent: - click.echo("Installing package %s @ %s:" % ( + click.echo("Installing %s %s @ %s:" % ( + self.get_manifest_name().split(".")[0], click.style(name, fg="cyan"), requirements if requirements else "latest")) if installed: @@ -122,18 +170,24 @@ class PackageManager(object): click.secho("Already installed", fg="yellow") return - if not self._install_from_piorepo(name, requirements): + manifest_path = None + if name.startswith("file://"): + manifest_path = self._install_from_local_dir(name[7:]) + else: + manifest_path = self._install_from_piorepo(name, requirements) + if not isfile(manifest_path): raise exception.PackageInstallError( - name, requirements, util.get_systype()) + name, requirements or "latest", util.get_systype()) self.reset_cache() if trigger_event: telemetry.on_event( category="PackageManager", action="Install", label=name) + return manifest_path + def _install_from_piorepo(self, name, requirements): pkg_dir = None - success = False pkgdata = None versions = None for versions in PackageRepoIterator(name, self.repositories): @@ -142,26 +196,17 @@ class PackageManager(object): if not pkgdata: continue - pkg_dir = join(self.package_dir, name) - if isfile(join(pkg_dir, self.get_manifest_name())): - pkg_dir = join( - self.package_dir, "%s@%s" % (name, pkgdata['version'])) - - # remove previous/not-satisfied package - if isdir(pkg_dir): - rmtree(pkg_dir) - os.makedirs(pkg_dir) - + pkg_dir = self.make_pkg_dir(name, pkgdata['version']) try: dlpath = self.download( pkgdata['url'], pkg_dir, pkgdata.get("sha1")) assert isfile(dlpath) self.unpack(dlpath, pkg_dir) - success = True + self.check_structure(pkg_dir) break except Exception as e: # pylint: disable=broad-except click.secho("Warning! Package Mirror: %s" % e, fg="yellow") - click.secho("Looking for other Package Mirror...", fg="yellow") + click.secho("Looking for another mirror...", fg="yellow") finally: if dlpath and isfile(dlpath): os.remove(dlpath) @@ -170,12 +215,26 @@ class PackageManager(object): raise exception.UnknownPackage(name) elif not pkgdata: raise exception.UndefinedPackageVersion( - name, requirements, util.get_systype()) + name, requirements or "latest", util.get_systype()) - return success + return join(pkg_dir, self.get_manifest_name()) + + def _install_from_local_dir(self, local_dir): + if not isfile(join(local_dir, self.get_manifest_name())): + raise exception.InvalidLocalPackage( + local_dir, self.get_manifest_name()) + + manifest = util.load_json(join(local_dir, self.get_manifest_name())) + assert set(["name", "version"]) <= set(manifest.keys()) + pkg_dir = self.make_pkg_dir(manifest['name'], manifest['version']) + rmtree(pkg_dir) + copytree(local_dir, pkg_dir, symlinks=True) + + return join(pkg_dir, self.get_manifest_name()) def uninstall(self, name, requirements=None, trigger_event=True): - click.echo("Uninstalling package %s @ %s: \t" % ( + click.echo("Uninstalling %s %s @ %s: \t" % ( + self.get_manifest_name().split(".")[0], click.style(name, fg="cyan"), requirements if requirements else "latest"), nl=False) found = False @@ -201,7 +260,8 @@ class PackageManager(object): category="PackageManager", action="Uninstall", label=name) def update(self, name, requirements=None, keep_versions=None): - click.echo("Updating package %s @ %s:" % ( + click.echo("Updating %s %s @ %s:" % ( + self.get_manifest_name().split(".")[0], click.style(name, fg="yellow"), requirements if requirements else "latest")) diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 2526ad29..f903b6bb 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -56,9 +56,9 @@ class PlatformManager(PackageManager): def install(self, # pylint: disable=too-many-arguments,arguments-differ name, requirements=None, with_packages=None, without_packages=None, skip_default_packages=False): - PackageManager.install(self, name, requirements) + manifest_path = PackageManager.install(self, name, requirements) return PlatformFactory.newPlatform( - name, requirements).install_packages( + manifest_path, requirements).install_packages( with_packages, without_packages, skip_default_packages) def uninstall(self, # pylint: disable=arguments-differ From 567f9c06cc7a038b80cd50140352c38a9d9bc777 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 27 May 2016 12:35:20 +0300 Subject: [PATCH 004/284] Disable platform auto-update (temporary) --- platformio/managers/platform.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index f903b6bb..608fa34b 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -72,6 +72,8 @@ class PlatformManager(PackageManager): raise NotImplementedError() def is_outdated(self, name, version): + # @TODO disable auto-update temporary + return False raise NotImplementedError() def get_installed_boards(self): From 46893e2f04212982995f48b10548ecbe7bd3751e Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 27 May 2016 12:48:10 +0300 Subject: [PATCH 005/284] Stop build process when framework is used and board is not specified --- platformio/builder/tools/platformio.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 10c93f6b..1be9a2c0 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -207,9 +207,12 @@ def BuildFrameworks(env, frameworks): if not frameworks or "uploadlazy" in COMMAND_LINE_TARGETS: return - board_frameworks = [] - if "BOARD" in env: - board_frameworks = env.BoardConfig().get("frameworks", []) + if "BOARD" not in env: + env.Exit( + "Please specify `board` in `platformio.ini` to use " + "with '%s' framework" % ", ".join(frameworks)) + + board_frameworks = env.BoardConfig().get("frameworks", []) if frameworks == ["platformio"]: if board_frameworks: frameworks.insert(0, board_frameworks[0]) From 825c60e2bd3d6eda466f570cdbd5180d9e3815d9 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 27 May 2016 14:47:22 +0300 Subject: [PATCH 006/284] Automatically add SCons to the packages list if it is missed in platform manifest // Issue #479 --- platformio/managers/platform.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 608fa34b..778896e4 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -309,7 +309,14 @@ class BasePlatform(PlatformPackagesMixin): return self.get_boards(id_) def get_packages(self): - return self.manifest.get("packages", {}) + packages = self.manifest.get("packages", {}) + if "tool-scons" not in packages: + packages['tool-scons'] = { + "version": self.manifest.get("engines", {}).get( + "scons", ">=2.3.0,<2.6.0"), + "optional": False + } + return packages def get_frameworks(self): return self.get_manifest().get("frameworks") @@ -353,13 +360,6 @@ class BasePlatform(PlatformPackagesMixin): _pkg_name = frameworks[framework]['package'] self.get_packages()[_pkg_name]['optional'] = False - # append SCons tool - self.get_packages()['tool-scons'] = { - "version": self.manifest.get("engines", {}).get( - "scons", ">=2.3.0,<2.5.0"), - "optional": False - } - # enable upload tools for upload targets if any(["upload" in t for t in targets] + ["program" in targets]): for _name, _opts in self.get_packages().iteritems(): @@ -413,8 +413,7 @@ class BasePlatform(PlatformPackagesMixin): cmd = [ os.path.normpath(sys.executable), - join(util.get_home_dir(), "packages", "tool-scons", - "script", "scons"), + join(self.get_package_dir("tool-scons"), "script", "scons"), "-Q", "-j %d" % self.get_job_nums(), "--warn=no-no-parallel-support", From 426389b2550ab4e8d789abae58a7525a002c72bc Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 27 May 2016 15:50:57 +0300 Subject: [PATCH 007/284] Fix package removing when it is symbolically linked --- platformio/managers/package.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/platformio/managers/package.py b/platformio/managers/package.py index c1e94f1c..d34e4ab4 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -13,7 +13,7 @@ # limitations under the License. import os -from os.path import dirname, isdir, isfile, join +from os.path import dirname, isdir, isfile, islink, join from shutil import copyfile, copytree, rmtree import click @@ -246,7 +246,11 @@ class PackageManager(object): continue found = True if isfile(manifest['_manifest_path']): - rmtree(dirname(manifest['_manifest_path'])) + pkg_dir = dirname(manifest['_manifest_path']) + if islink(pkg_dir): + os.unlink(pkg_dir) + else: + rmtree(pkg_dir) if not found: click.secho("Not installed", fg="yellow") From 23ef51a4e8d4af4f39425345d5c6569fc16cc2ab Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 28 May 2016 22:51:33 +0300 Subject: [PATCH 008/284] Update tests according new development platforms architecture // Issue #479 --- platformio/commands/boards.py | 1 + platformio/commands/run.py | 15 +++++++++++++-- platformio/managers/platform.py | 1 + tests/commands/test_boards.py | 26 +++++++++++++++----------- tests/commands/test_init.py | 11 ++++++++--- tests/commands/test_platforms.py | 18 +++++++++--------- 6 files changed, 47 insertions(+), 25 deletions(-) diff --git a/platformio/commands/boards.py b/platformio/commands/boards.py index 585ff84b..1a5c258d 100644 --- a/platformio/commands/boards.py +++ b/platformio/commands/boards.py @@ -92,6 +92,7 @@ def _get_boards(installed=False): boards = _new_boards return boards + def _ouput_boards_json(query, installed=False): result = [] for board in _get_boards(installed): diff --git a/platformio/commands/run.py b/platformio/commands/run.py index e32654ef..6e350a27 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -23,6 +23,8 @@ import click from platformio import app, exception, telemetry, util from platformio.commands.lib import lib_install as cmd_lib_install +from platformio.commands.platform import \ + platform_install as cmd_platform_install from platformio.libmanager import LibraryManager from platformio.managers.platform import PlatformFactory @@ -186,7 +188,6 @@ class EnvironmentProcessor(object): if "platform" not in self.options: raise exception.UndefinedEnvPlatform(self.name) - platform = self.options['platform'] build_vars = self._get_build_variables() build_targets = self._get_build_targets() @@ -196,7 +197,17 @@ class EnvironmentProcessor(object): if "lib_install" in self.options: _autoinstall_libs(self.cmd_ctx, self.options['lib_install']) - p = PlatformFactory.newPlatform(platform) + platform = self.options['platform'] + version = None + if "@" in platform: + platform, version = platform.rsplit("@", 1) + + try: + p = PlatformFactory.newPlatform(platform) + except exception.UnknownPlatform: + self.cmd_ctx.invoke(cmd_platform_install, platforms=[platform]) + p = PlatformFactory.newPlatform(platform) + return p.run(build_vars, build_targets, self.verbose_level) diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 778896e4..d2bad516 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -125,6 +125,7 @@ class PlatformFactory(object): name, requirements) if _manifest: platform_dir = dirname(_manifest['_manifest_path']) + if not platform_dir: raise exception.UnknownPlatform( name if not requirements else "%s@%s" % (name, requirements)) diff --git a/tests/commands/test_boards.py b/tests/commands/test_boards.py index f137096c..1a2539fd 100644 --- a/tests/commands/test_boards.py +++ b/tests/commands/test_boards.py @@ -16,16 +16,16 @@ import json from platformio import util from platformio.commands.boards import cli as cmd_boards -from platformio.commands.platforms import \ - platforms_search as cmd_platforms_search +from platformio.commands.platform import \ + platform_search as cmd_platform_search def test_board_json_output(platformio_setup, clirunner, validate_cliresult): - result = clirunner.invoke(cmd_boards, ["cortex", "--json-output"]) + result = clirunner.invoke(cmd_boards, ["mbed", "--json-output"]) validate_cliresult(result) boards = json.loads(result.output) - assert isinstance(boards, dict) - assert "teensy30" in boards + assert isinstance(boards, list) + assert any(["mbed" in b['frameworks'] for b in boards]) def test_board_raw_output(platformio_setup, clirunner, validate_cliresult): @@ -36,16 +36,20 @@ def test_board_raw_output(platformio_setup, clirunner, validate_cliresult): def test_board_options(platformio_setup, clirunner, validate_cliresult): required_opts = set( - ["build", "platform", "upload", "name"]) + ["fcpu", "frameworks", "id", "mcu", "name", "platform"]) # fetch available platforms - result = clirunner.invoke(cmd_platforms_search, ["--json-output"]) + result = clirunner.invoke(cmd_platform_search, ["--json-output"]) validate_cliresult(result) search_result = json.loads(result.output) assert isinstance(search_result, list) assert len(search_result) - platforms = [item['type'] for item in search_result] + platforms = [item['name'] for item in search_result] - for _, opts in util.get_boards().iteritems(): - assert required_opts.issubset(set(opts)) - assert opts['platform'] in platforms + result = clirunner.invoke(cmd_boards, ["mbed", "--json-output"]) + validate_cliresult(result) + boards = json.loads(result.output) + + for board in boards: + assert required_opts.issubset(set(board)) + assert board['platform'] in platforms diff --git a/tests/commands/test_init.py b/tests/commands/test_init.py index 93b47053..3cea718a 100644 --- a/tests/commands/test_init.py +++ b/tests/commands/test_init.py @@ -12,10 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +import json from os import makedirs, getcwd from os.path import getsize, isdir, isfile, join from platformio.commands.init import cli +from platformio.commands.boards import cli as cmd_boards from platformio import util @@ -48,11 +50,14 @@ def test_init_special_board(platformio_setup, clirunner, validate_cliresult): validate_cliresult(result) validate_pioproject(getcwd()) - uno = util.get_boards("uno") + result = clirunner.invoke(cmd_boards, ["Arduino Uno", "--json-output"]) + validate_cliresult(result) + boards = json.loads(result.output) + config = util.get_project_config() expected_result = [ - ("platform", str(uno['platform'])), - ("framework", str(uno['frameworks'][0])), + ("platform", str(boards[0]['platform'])), + ("framework", str(boards[0]['frameworks'][0])), ("board", "uno") ] diff --git a/tests/commands/test_platforms.py b/tests/commands/test_platforms.py index 0d0251d1..db4d735e 100644 --- a/tests/commands/test_platforms.py +++ b/tests/commands/test_platforms.py @@ -14,14 +14,14 @@ import json -from platformio.commands.platforms import \ - platforms_list as cmd_platforms_list -from platformio.commands.platforms import \ - platforms_search as cmd_platforms_search +from platformio.commands.platform import \ + platform_list as cmd_platform_list +from platformio.commands.platform import \ + platform_search as cmd_platform_search def test_list_json_output(clirunner, validate_cliresult): - result = clirunner.invoke(cmd_platforms_list, ["--json-output"]) + result = clirunner.invoke(cmd_platform_list, ["--json-output"]) validate_cliresult(result) list_result = json.loads(result.output) assert isinstance(list_result, list) @@ -31,23 +31,23 @@ def test_list_json_output(clirunner, validate_cliresult): def test_list_raw_output(clirunner, validate_cliresult): - result = clirunner.invoke(cmd_platforms_list) + result = clirunner.invoke(cmd_platform_list) validate_cliresult(result) assert "teensy" in result.output def test_search_json_output(clirunner, validate_cliresult): - result = clirunner.invoke(cmd_platforms_search, + result = clirunner.invoke(cmd_platform_search, ["arduino", "--json-output"]) validate_cliresult(result) search_result = json.loads(result.output) assert isinstance(search_result, list) assert len(search_result) - platforms = [item['type'] for item in search_result] + platforms = [item['name'] for item in search_result] assert "atmelsam" in platforms def test_search_raw_output(clirunner, validate_cliresult): - result = clirunner.invoke(cmd_platforms_search, ["arduino"]) + result = clirunner.invoke(cmd_platform_search, ["arduino"]) validate_cliresult(result) assert "teensy" in result.output From 420c93aaa3838d9d97f2a88748624e0ac302f924 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 29 May 2016 00:50:05 +0300 Subject: [PATCH 009/284] Automatically install missed development platform for run command --- platformio/commands/run.py | 4 +- platformio/managers/package.py | 2 +- platformio/managers/platform.py | 206 ++++++++++++++++---------------- 3 files changed, 108 insertions(+), 104 deletions(-) diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 6e350a27..8b80d26d 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -203,10 +203,10 @@ class EnvironmentProcessor(object): platform, version = platform.rsplit("@", 1) try: - p = PlatformFactory.newPlatform(platform) + p = PlatformFactory.newPlatform(platform, version) except exception.UnknownPlatform: self.cmd_ctx.invoke(cmd_platform_install, platforms=[platform]) - p = PlatformFactory.newPlatform(platform) + p = PlatformFactory.newPlatform(platform, version) return p.run(build_vars, build_targets, self.verbose_level) diff --git a/platformio/managers/package.py b/platformio/managers/package.py index d34e4ab4..93053d08 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -286,7 +286,7 @@ class PackageManager(object): continue if (not current or semantic_version.compare( manifest['version'], current['version']) == 1): - current = manifest + current = manifest if current is None: return diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index d2bad516..ab39c45f 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -33,7 +33,7 @@ class PlatformManager(PackageManager): PackageManager.__init__( self, join(util.get_home_dir(), "platforms"), - ["http://dl.platformio.org/misc/platforms_manifest.json"] + ["http://dl.platformio.org/platforms/manifest.json"] ) @staticmethod @@ -68,7 +68,8 @@ class PlatformManager(PackageManager): return PackageManager.uninstall(self, name, requirements) return False - def update(self, name, version): + def update(self, # pylint: disable=arguments-differ + name, version): raise NotImplementedError() def is_outdated(self, name, version): @@ -235,12 +236,111 @@ class PlatformPackagesMixin(object): return False -class BasePlatform(PlatformPackagesMixin): - - _BOARDS_CACHE = {} +class PlatformRunMixin(object): LINE_ERROR_RE = re.compile(r"(\s+error|error[:\s]+)", re.I) + def run(self, variables, targets, verbose): + assert isinstance(variables, dict) + assert isinstance(targets, list) + + self.configure_default_packages(variables, targets) + self.install_packages(silent=True) + + self._verbose_level = int(verbose) + + if "clean" in targets: + targets.remove("clean") + targets.append("-c") + + variables['platform_manifest'] = self.manifest_path + + if "build_script" not in variables: + variables['build_script'] = self.get_build_script() + if not isfile(variables['build_script']): + raise exception.BuildScriptNotFound(variables['build_script']) + + self._found_error = False + result = self._run_scons(variables, targets) + assert "returncode" in result + # if self._found_error: + # result['returncode'] = 1 + + if self._last_echo_line == ".": + click.echo("") + + return result + + def _run_scons(self, variables, targets): + # pass current PYTHONPATH to SCons + if "PYTHONPATH" in os.environ: + _PYTHONPATH = os.environ.get("PYTHONPATH").split(os.pathsep) + else: + _PYTHONPATH = [] + for p in os.sys.path: + if p not in _PYTHONPATH: + _PYTHONPATH.append(p) + os.environ['PYTHONPATH'] = os.pathsep.join(_PYTHONPATH) + + cmd = [ + os.path.normpath(sys.executable), + join(self.get_package_dir("tool-scons"), "script", "scons"), + "-Q", + "-j %d" % self.get_job_nums(), + "--warn=no-no-parallel-support", + "-f", join(util.get_source_dir(), "builder", "main.py") + ] + targets + + # encode and append variables + for key, value in variables.items(): + cmd.append("%s=%s" % (key.upper(), base64.b64encode(value))) + + result = util.exec_command( + cmd, + stdout=util.AsyncPipe(self.on_run_out), + stderr=util.AsyncPipe(self.on_run_err) + ) + return result + + def on_run_out(self, line): + self._echo_line(line, level=3) + + def on_run_err(self, line): + is_error = self.LINE_ERROR_RE.search(line) is not None + if is_error: + self._found_error = True + self._echo_line(line, level=1 if is_error else 2) + + def _echo_line(self, line, level): + assert 1 <= level <= 3 + + fg = ("red", "yellow", None)[level - 1] + if level == 3 and "is up to date" in line: + fg = "green" + + if level > self._verbose_level: + click.secho(".", fg=fg, err=level < 3, nl=False) + self._last_echo_line = "." + return + + if self._last_echo_line == ".": + click.echo("") + self._last_echo_line = line + + click.secho(line, fg=fg, err=level < 3) + + @staticmethod + def get_job_nums(): + try: + return cpu_count() + except NotImplementedError: + return 1 + + +class BasePlatform(PlatformPackagesMixin, PlatformRunMixin): + + _BOARDS_CACHE = {} + def __init__(self, manifest_path): self._BOARDS_CACHE = {} self.manifest_path = manifest_path @@ -370,102 +470,6 @@ class BasePlatform(PlatformPackagesMixin): # skip all packages, allow only upload tools self.get_packages()[_name]['optional'] = True - def run(self, variables, targets, verbose): - assert isinstance(variables, dict) - assert isinstance(targets, list) - - self.configure_default_packages(variables, targets) - self.install_packages(silent=True) - - self._verbose_level = int(verbose) - - if "clean" in targets: - targets.remove("clean") - targets.append("-c") - - variables['platform_manifest'] = self.manifest_path - - if "build_script" not in variables: - variables['build_script'] = self.get_build_script() - if not isfile(variables['build_script']): - raise exception.BuildScriptNotFound(variables['build_script']) - - self._found_error = False - result = self._run_scons(variables, targets) - assert "returncode" in result - # if self._found_error: - # result['returncode'] = 1 - - if self._last_echo_line == ".": - click.echo("") - - return result - - def _run_scons(self, variables, targets): - # pass current PYTHONPATH to SCons - if "PYTHONPATH" in os.environ: - _PYTHONPATH = os.environ.get("PYTHONPATH").split(os.pathsep) - else: - _PYTHONPATH = [] - for p in os.sys.path: - if p not in _PYTHONPATH: - _PYTHONPATH.append(p) - os.environ['PYTHONPATH'] = os.pathsep.join(_PYTHONPATH) - - cmd = [ - os.path.normpath(sys.executable), - join(self.get_package_dir("tool-scons"), "script", "scons"), - "-Q", - "-j %d" % self.get_job_nums(), - "--warn=no-no-parallel-support", - "-f", join(util.get_source_dir(), "builder", "main.py") - ] + targets - - # encode and append variables - for key, value in variables.items(): - cmd.append("%s=%s" % (key.upper(), base64.b64encode(value))) - - result = util.exec_command( - cmd, - stdout=util.AsyncPipe(self.on_run_out), - stderr=util.AsyncPipe(self.on_run_err) - ) - return result - - def on_run_out(self, line): - self._echo_line(line, level=3) - - def on_run_err(self, line): - is_error = self.LINE_ERROR_RE.search(line) is not None - if is_error: - self._found_error = True - self._echo_line(line, level=1 if is_error else 2) - - def _echo_line(self, line, level): - assert 1 <= level <= 3 - - fg = ("red", "yellow", None)[level - 1] - if level == 3 and "is up to date" in line: - fg = "green" - - if level > self._verbose_level: - click.secho(".", fg=fg, err=level < 3, nl=False) - self._last_echo_line = "." - return - - if self._last_echo_line == ".": - click.echo("") - self._last_echo_line = line - - click.secho(line, fg=fg, err=level < 3) - - @staticmethod - def get_job_nums(): - try: - return cpu_count() - except NotImplementedError: - return 1 - class PlatformBoardConfig(object): From 806f6cd2abff59ea66916885c0c377f380fce826 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 29 May 2016 17:59:08 +0300 Subject: [PATCH 010/284] Fix platform installer if platform is already installed --- platformio/managers/package.py | 22 ++++++++++++++++++---- platformio/managers/platform.py | 15 +-------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 93053d08..ec569f2f 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -106,7 +106,7 @@ class PackageManager(object): return pkg_dir @staticmethod - def max_satisfying_version(versions, requirements=None): + def max_satisfying_repo_version(versions, requirements=None): item = None systype = util.get_systype() if requirements is not None: @@ -124,6 +124,19 @@ class PackageManager(object): item = v return item + def max_satisfying_version(self, name, requirements=None): + best = None + for manifest in self.get_installed(): + if manifest['name'] != name: + continue + elif requirements and not semantic_version.match( + requirements, manifest['version']): + continue + elif (not best or semantic_version.compare( + manifest['version'], best['version']) == 1): + best = manifest + return best + def get_installed(self): if self.package_dir in PackageManager._INSTALLED_CACHE: return PackageManager._INSTALLED_CACHE[self.package_dir] @@ -153,7 +166,7 @@ class PackageManager(object): def get_latest_version(self, name, requirements): for versions in PackageRepoIterator(name, self.repositories): - pkgdata = self.max_satisfying_version(versions, requirements) + pkgdata = self.max_satisfying_repo_version(versions, requirements) if pkgdata: return pkgdata['version'] return None @@ -168,7 +181,8 @@ class PackageManager(object): if installed: if not silent: click.secho("Already installed", fg="yellow") - return + return self.max_satisfying_version( + name, requirements).get("_manifest_path") manifest_path = None if name.startswith("file://"): @@ -192,7 +206,7 @@ class PackageManager(object): versions = None for versions in PackageRepoIterator(name, self.repositories): dlpath = None - pkgdata = self.max_satisfying_version(versions, requirements) + pkgdata = self.max_satisfying_repo_version(versions, requirements) if not pkgdata: continue diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index ab39c45f..b0430b8e 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -40,19 +40,6 @@ class PlatformManager(PackageManager): def get_manifest_name(): return "platform.json" - def find_best_platform(self, name, requirements=None): - best = None - for manifest in self.get_installed(): - if manifest['name'] != name: - continue - elif requirements and not semantic_version.match( - requirements, manifest['version']): - continue - elif (not best or semantic_version.compare( - manifest['version'], best['version']) == 1): - best = manifest - return best - def install(self, # pylint: disable=too-many-arguments,arguments-differ name, requirements=None, with_packages=None, without_packages=None, skip_default_packages=False): @@ -122,7 +109,7 @@ class PlatformFactory(object): platform_dir = dirname(name) name = util.load_json(name)['name'] else: - _manifest = PlatformManager().find_best_platform( + _manifest = PlatformManager().max_satisfying_version( name, requirements) if _manifest: platform_dir = dirname(_manifest['_manifest_path']) From 2ecc007615c6901bfdd259ffea8171c98323ba87 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 29 May 2016 23:28:50 +0300 Subject: [PATCH 011/284] Implement packages updating; other improvements to Package Manager // Issue #479 --- platformio/builder/tools/devplatform.py | 5 +- platformio/commands/platform.py | 45 +++--- platformio/exception.py | 5 + platformio/managers/package.py | 83 +++++----- platformio/managers/platform.py | 199 ++++++++++++------------ 5 files changed, 175 insertions(+), 162 deletions(-) diff --git a/platformio/builder/tools/devplatform.py b/platformio/builder/tools/devplatform.py index ac5cda6d..4c78a6d5 100644 --- a/platformio/builder/tools/devplatform.py +++ b/platformio/builder/tools/devplatform.py @@ -49,9 +49,8 @@ def BoardConfig(env, board=None): def GetFrameworkScript(env, framework): p = env.DevPlatform() - frameworks = p.get_frameworks() - assert frameworks and framework in frameworks - script_path = env.subst(frameworks[framework]['script']) + assert p.frameworks and framework in p.frameworks + script_path = env.subst(p.frameworks[framework]['script']) if not isfile(script_path): script_path = join(p.get_dir(), script_path) return script_path diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index 2a159f02..5a703fdd 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -97,10 +97,10 @@ def platform_list(json_output): for manifest in PlatformManager().get_installed(): p = PlatformFactory.newPlatform(manifest['_manifest_path']) platforms.append({ - "name": p.get_name(), - "title": p.get_title(), - "description": p.get_description(), - "version": p.get_version(), + "name": p.name, + "title": p.title, + "description": p.description, + "version": p.version, "packages": p.get_installed_packages().keys() }) @@ -125,24 +125,23 @@ def platform_show(ctx, platform): raise exception.PlatformNotInstalledYet(platform) click.echo("{name} ~ {title}".format( - name=click.style(p.get_name(), fg="cyan"), title=p.get_title())) - click.echo("=" * (3 + len(p.get_name() + p.get_title()))) - click.echo(p.get_manifest().get("description")) + name=click.style(p.name, fg="cyan"), title=p.title)) + click.echo("=" * (3 + len(p.name + p.title))) + click.echo(p.description) click.echo() - click.echo("Version: %s" % p.get_version()) - if "homepage" in p.get_manifest(): - click.echo("Home: %s" % p.get_manifest().get("homepage")) - if "license" in p.get_manifest(): - click.echo("License: %s" % p.get_manifest().get("license").get("type")) - if "frameworks" in p.get_manifest(): - click.echo("Frameworks: %s" % - ", ".join(p.get_manifest().get("frameworks").keys())) + click.echo("Version: %s" % p.version) + if p.homepage: + click.echo("Home: %s" % p.homepage) + if p.license: + click.echo("License: %s" % p.license.get("type")) + if p.frameworks: + click.echo("Frameworks: %s" % ", ".join(p.frameworks.keys())) - if not p.get_packages(): + if not p.packages: return installed_pkgs = p.get_installed_packages() - for name, opts in p.get_packages().items(): + for name, opts in p.packages.items(): click.echo() click.echo("Package %s" % click.style(name, fg="yellow")) click.echo("-" * (8 + len(name))) @@ -173,15 +172,11 @@ def platform_uninstall(platforms): @cli.command("update", short_help="Update installed Platforms") @click.option("--only-packages", is_flag=True) def platform_update(only_packages): - for manifest in PlatformManager().get_installed(): + pm = PlatformManager() + for manifest in pm.get_installed(): click.echo("Platform %s @ %s" % ( click.style(manifest['name'], fg="cyan"), manifest['version'])) click.echo("--------") - if only_packages: - status = PlatformFactory.newPlatform( - manifest['name'], manifest['version']).update_packages() - if status is None: - click.secho("Packages are up-to-date", fg="green") - else: - PlatformManager().update(manifest['name'], manifest['version']) + pm.update(manifest['name'], manifest['version'], + only_packages=only_packages) click.echo() diff --git a/platformio/exception.py b/platformio/exception.py index 39630594..a375b587 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -81,6 +81,11 @@ class UndefinedPackageVersion(PlatformioException): " for your system '{2}'" +class UndefinedPlatformVersion(PlatformioException): + + MESSAGE = "Can not find platform '{0}' with version requirements '{1}'" + + class PackageInstallError(PlatformioException): MESSAGE = "Can not install package '{0}' with version requirements '{1}' "\ diff --git a/platformio/managers/package.py b/platformio/managers/package.py index ec569f2f..8b37520b 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -41,8 +41,8 @@ class PackageManager(object): def reset_cache(): PackageManager._INSTALLED_CACHE = {} - @staticmethod - def get_manifest_name(): + @property + def manifest_name(self): return "package.json" @staticmethod @@ -59,11 +59,11 @@ class PackageManager(object): return fu.start() def check_structure(self, pkg_dir): - if isfile(join(pkg_dir, self.get_manifest_name())): + if isfile(join(pkg_dir, self.manifest_name)): return True for root, _, files in os.walk(pkg_dir): - if self.get_manifest_name() not in files: + if self.manifest_name not in files: continue # copy contents to the root of package directory for item in os.listdir(root): @@ -80,20 +80,27 @@ class PackageManager(object): break break - if isfile(join(pkg_dir, self.get_manifest_name())): + if isfile(join(pkg_dir, self.manifest_name)): return True raise exception.PlatformioException( "Could not find '%s' manifest file in the package" % - self.get_manifest_name()) + self.manifest_name) def make_pkg_dir(self, name, version): pkg_dir = join(self.package_dir, name) - if isfile(join(pkg_dir, self.get_manifest_name())): - _manifest = util.load_json( - join(pkg_dir, self.get_manifest_name())) - if (_manifest['name'] == name and - _manifest['version'] != version): + if isfile(join(pkg_dir, self.manifest_name)): + manifest = util.load_json( + join(pkg_dir, self.manifest_name)) + + cmp_result = semantic_version.compare(version, manifest['version']) + if cmp_result == 1: + # if main package version < new package, backup it + print pkg_dir, join( + self.package_dir, "%s@%s" % (name, manifest['version'])) + os.rename(pkg_dir, join( + self.package_dir, "%s@%s" % (name, manifest['version']))) + elif cmp_result == -1: pkg_dir = join( self.package_dir, "%s@%s" % (name, version)) @@ -103,6 +110,7 @@ class PackageManager(object): os.makedirs(pkg_dir) assert isdir(pkg_dir) + self.reset_cache() return pkg_dir @staticmethod @@ -124,6 +132,17 @@ class PackageManager(object): item = v return item + def get_latest_repo_version(self, name, requirements): + version = None + for versions in PackageRepoIterator(name, self.repositories): + pkgdata = self.max_satisfying_repo_version(versions, requirements) + if not pkgdata: + continue + if (not version or semantic_version.compare( + pkgdata['version'], version) == 1): + version = pkgdata['version'] + return version + def max_satisfying_version(self, name, requirements=None): best = None for manifest in self.get_installed(): @@ -142,7 +161,7 @@ class PackageManager(object): return PackageManager._INSTALLED_CACHE[self.package_dir] items = [] for p in sorted(os.listdir(self.package_dir)): - manifest_path = join(self.package_dir, p, self.get_manifest_name()) + manifest_path = join(self.package_dir, p, self.manifest_name) if not isfile(manifest_path): continue manifest = util.load_json(manifest_path) @@ -164,18 +183,11 @@ class PackageManager(object): return True return None - def get_latest_version(self, name, requirements): - for versions in PackageRepoIterator(name, self.repositories): - pkgdata = self.max_satisfying_repo_version(versions, requirements) - if pkgdata: - return pkgdata['version'] - return None - def install(self, name, requirements, silent=False, trigger_event=True): installed = self.is_installed(name, requirements) if not installed or not silent: click.echo("Installing %s %s @ %s:" % ( - self.get_manifest_name().split(".")[0], + self.manifest_name.split(".")[0], click.style(name, fg="cyan"), requirements if requirements else "latest")) if installed: @@ -228,27 +240,31 @@ class PackageManager(object): if versions is None: raise exception.UnknownPackage(name) elif not pkgdata: - raise exception.UndefinedPackageVersion( - name, requirements or "latest", util.get_systype()) + if "platform" in self.manifest_name: + raise exception.UndefinedPlatformVersion( + name, requirements or "latest") + else: + raise exception.UndefinedPackageVersion( + name, requirements or "latest", util.get_systype()) - return join(pkg_dir, self.get_manifest_name()) + return join(pkg_dir, self.manifest_name) def _install_from_local_dir(self, local_dir): - if not isfile(join(local_dir, self.get_manifest_name())): + if not isfile(join(local_dir, self.manifest_name)): raise exception.InvalidLocalPackage( - local_dir, self.get_manifest_name()) + local_dir, self.manifest_name) - manifest = util.load_json(join(local_dir, self.get_manifest_name())) + manifest = util.load_json(join(local_dir, self.manifest_name)) assert set(["name", "version"]) <= set(manifest.keys()) pkg_dir = self.make_pkg_dir(manifest['name'], manifest['version']) rmtree(pkg_dir) copytree(local_dir, pkg_dir, symlinks=True) - return join(pkg_dir, self.get_manifest_name()) + return join(pkg_dir, self.manifest_name) def uninstall(self, name, requirements=None, trigger_event=True): click.echo("Uninstalling %s %s @ %s: \t" % ( - self.get_manifest_name().split(".")[0], + self.manifest_name.split(".")[0], click.style(name, fg="cyan"), requirements if requirements else "latest"), nl=False) found = False @@ -277,24 +293,22 @@ class PackageManager(object): telemetry.on_event( category="PackageManager", action="Uninstall", label=name) - def update(self, name, requirements=None, keep_versions=None): + def update(self, name, requirements=None): click.echo("Updating %s %s @ %s:" % ( - self.get_manifest_name().split(".")[0], + self.manifest_name.split(".")[0], click.style(name, fg="yellow"), requirements if requirements else "latest")) - latest_version = self.get_latest_version(name, requirements) + latest_version = self.get_latest_repo_version(name, requirements) if latest_version is None: click.secho("Ignored! '%s' is not listed in " "Package Repository" % name, fg="yellow") return current = None - other_versions = [] for manifest in self.get_installed(): if manifest['name'] != name: continue - other_versions.append(manifest['version']) if (requirements and not semantic_version.match( requirements, manifest['version'])): continue @@ -315,9 +329,6 @@ class PackageManager(object): else: click.echo("[%s]" % (click.style("Out-of-date", fg="red"))) - for v in other_versions: - if not keep_versions or v not in keep_versions: - self.uninstall(name, v, trigger_event=False) self.install(name, latest_version, trigger_event=False) telemetry.on_event( diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index b0430b8e..611933f1 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -36,33 +36,61 @@ class PlatformManager(PackageManager): ["http://dl.platformio.org/platforms/manifest.json"] ) - @staticmethod - def get_manifest_name(): + @property + def manifest_name(self): return "platform.json" def install(self, # pylint: disable=too-many-arguments,arguments-differ name, requirements=None, with_packages=None, without_packages=None, skip_default_packages=False): manifest_path = PackageManager.install(self, name, requirements) - return PlatformFactory.newPlatform( + PlatformFactory.newPlatform( manifest_path, requirements).install_packages( with_packages, without_packages, skip_default_packages) + self.cleanup_packages() + return True def uninstall(self, # pylint: disable=arguments-differ name, requirements=None): - if PlatformFactory.newPlatform( - name, requirements).uninstall_packages(): - return PackageManager.uninstall(self, name, requirements) - return False + PackageManager.uninstall(self, name, requirements) + self.cleanup_packages() + return True def update(self, # pylint: disable=arguments-differ - name, version): - raise NotImplementedError() + name, requirements=None, only_packages=False): + if not only_packages: + PackageManager.update(self, name) + PlatformFactory.newPlatform( + name, requirements).update_packages() + self.cleanup_packages() + return True - def is_outdated(self, name, version): - # @TODO disable auto-update temporary - return False - raise NotImplementedError() + def is_outdated(self, name, requirements=None): + p = PlatformFactory.newPlatform(name, requirements) + return (p.are_outdated_packages() or + p.version != self.get_latest_repo_version(name, requirements)) + + def cleanup_packages(self): + self.reset_cache() + deppkgs = {} + for manifest in PlatformManager().get_installed(): + p = PlatformFactory.newPlatform( + manifest['name'], manifest['version']) + for pkgname, pkgmanifest in p.get_installed_packages().items(): + if pkgname not in deppkgs: + deppkgs[pkgname] = set() + deppkgs[pkgname].add(pkgmanifest['version']) + + pm = PackageManager() + for manifest in pm.get_installed(): + if manifest['name'] not in deppkgs: + continue + if manifest['version'] not in deppkgs[manifest['name']]: + pm.uninstall( + manifest['name'], manifest['version'], trigger_event=False) + + self.reset_cache() + return True def get_installed_boards(self): boards = [] @@ -71,7 +99,7 @@ class PlatformManager(PackageManager): for id_, config in p.get_boards().items(): manifest = config.get_manifest().copy() manifest['id'] = id_ - manifest['platform'] = p.get_name() + manifest['platform'] = p.name boards.append(manifest) return boards @@ -138,7 +166,7 @@ class PlatformPackagesMixin(object): def get_installed_packages(self): items = {} installed = self.pm.get_installed() - for name, opts in self.get_packages().items(): + for name, opts in self.packages.items(): manifest = None for p in installed: if (p['name'] != name or not semantic_version.match( @@ -159,11 +187,11 @@ class PlatformPackagesMixin(object): self.pkg_types_to_names(without_packages or [])) upkgs = with_packages | without_packages - ppkgs = set(self.get_packages().keys()) + ppkgs = set(self.packages.keys()) if not upkgs.issubset(ppkgs): raise exception.UnknownPackage(", ".join(upkgs - ppkgs)) - for name, opts in self.get_packages().items(): + for name, opts in self.packages.items(): if name in without_packages: continue elif (name in with_packages or @@ -172,53 +200,14 @@ class PlatformPackagesMixin(object): return True - def uninstall_packages(self): - deppkgs = set() - for manifest in PlatformManager().get_installed(): - if manifest['name'] == self.get_name(): - continue - p = PlatformFactory.newPlatform( - manifest['name'], manifest['version']) - for pkgname, pkgmanifest in p.get_installed_packages().items(): - deppkgs.add((pkgname, pkgmanifest['version'])) - - for manifest in self.pm.get_installed(): - if manifest['name'] not in self.get_packages().keys(): - continue - if (manifest['name'], manifest['version']) not in deppkgs: - self.pm.uninstall(manifest['name'], manifest['version']) - return True - def update_packages(self): - outdated = None - for pkgname, pkgmanifest in self.get_installed_packages().items(): - requirements = self.get_packages()[pkgname]['version'] - latest_version = self.pm.get_latest_version( - pkgname, requirements) - if (not latest_version or - pkgmanifest['version'] == latest_version): - continue - - # check other platforms - keep_versions = set([latest_version]) - for pfmanifest in PlatformManager().get_installed(): - if pfmanifest['name'] == self.get_name(): - continue - p = PlatformFactory.newPlatform( - pfmanifest['name'], pfmanifest['version']) - if pkgname not in p.get_packages(): - continue - keep_versions.add(p.pm.get_latest_version( - pkgname, p.get_packages()[pkgname]['version'])) - - outdated = self.pm.update( - pkgname, requirements, keep_versions) - return outdated + for name in self.get_installed_packages().keys(): + self.pm.update(name, self.packages[name]['version']) def are_outdated_packages(self): for name, opts in self.get_installed_packages().items(): - if (opts['version'] != self.pm.get_latest_version( - name, self.get_packages()[name].get("version"))): + if (opts['version'] != self.pm.get_latest_repo_version( + name, self.packages[name].get("version"))): return True return False @@ -331,10 +320,10 @@ class BasePlatform(PlatformPackagesMixin, PlatformRunMixin): def __init__(self, manifest_path): self._BOARDS_CACHE = {} self.manifest_path = manifest_path - self.manifest = util.load_json(manifest_path) + self._manifest = util.load_json(manifest_path) self.pm = PackageManager( - repositories=self.manifest.get("packageRepositories")) + repositories=self._manifest.get("packageRepositories")) self._found_error = False self._last_echo_line = None @@ -344,20 +333,48 @@ class BasePlatform(PlatformPackagesMixin, PlatformRunMixin): # 3 = 2 + others self._verbose_level = 3 - def get_name(self): - return self.manifest['name'] + @property + def name(self): + return self._manifest['name'] - def get_title(self): - return self.manifest['title'] + @property + def title(self): + return self._manifest['title'] - def get_description(self): - return self.manifest['description'] + @property + def description(self): + return self._manifest['description'] - def get_version(self): - return self.manifest['version'] + @property + def version(self): + return self._manifest['version'] - def get_manifest(self): - return self.manifest + @property + def homepage(self): + return self._manifest.get("homepage") + + @property + def license(self): + return self._manifest.get("license") + + @property + def frameworks(self): + return self._manifest.get("frameworks") + + @property + def manifest(self): + return self._manifest + + @property + def packages(self): + packages = self._manifest.get("packages", {}) + if "tool-scons" not in packages: + packages['tool-scons'] = { + "version": self._manifest.get("engines", {}).get( + "scons", ">=2.3.0,<2.6.0"), + "optional": False + } + return packages def get_dir(self): return dirname(self.manifest_path) @@ -369,7 +386,7 @@ class BasePlatform(PlatformPackagesMixin, PlatformRunMixin): raise NotImplementedError() def is_embedded(self): - for opts in self.get_packages().values(): + for opts in self.packages.values(): if opts.get("type") == "uploader": return True return False @@ -396,19 +413,6 @@ class BasePlatform(PlatformPackagesMixin, PlatformRunMixin): def board_config(self, id_): return self.get_boards(id_) - def get_packages(self): - packages = self.manifest.get("packages", {}) - if "tool-scons" not in packages: - packages['tool-scons'] = { - "version": self.manifest.get("engines", {}).get( - "scons", ">=2.3.0,<2.6.0"), - "optional": False - } - return packages - - def get_frameworks(self): - return self.get_manifest().get("frameworks") - def get_package_dir(self, name): packages = self.get_installed_packages() if name not in packages: @@ -422,14 +426,14 @@ class BasePlatform(PlatformPackagesMixin, PlatformRunMixin): return packages[name]['version'] def get_package_type(self, name): - return self.get_packages()[name].get("type") + return self.packages[name].get("type") def pkg_types_to_names(self, types): names = [] for type_ in types: name = type_ # lookup by package types - for _name, _opts in self.get_packages().items(): + for _name, _opts in self.packages.items(): if _opts.get("type") == type_: name = None names.append(_name) @@ -440,22 +444,21 @@ class BasePlatform(PlatformPackagesMixin, PlatformRunMixin): def configure_default_packages(self, variables, targets): # enbale used frameworks - frameworks = self.get_frameworks() for framework in variables.get("framework", "").split(","): framework = framework.lower().strip() - if not framework or framework not in frameworks: + if not framework or framework not in self.frameworks: continue - _pkg_name = frameworks[framework]['package'] - self.get_packages()[_pkg_name]['optional'] = False + _pkg_name = self.frameworks[framework]['package'] + self.packages[_pkg_name]['optional'] = False # enable upload tools for upload targets if any(["upload" in t for t in targets] + ["program" in targets]): - for _name, _opts in self.get_packages().iteritems(): + for _name, _opts in self.packages.iteritems(): if _opts.get("type") == "uploader": - self.get_packages()[_name]['optional'] = False + self.packages[_name]['optional'] = False elif "uploadlazy" in targets: # skip all packages, allow only upload tools - self.get_packages()[_name]['optional'] = True + self.packages[_name]['optional'] = True class PlatformBoardConfig(object): @@ -464,11 +467,11 @@ class PlatformBoardConfig(object): if not isfile(manifest_path): raise exception.UnknownBoard(basename(manifest_path[:-5])) self.manifest_path = manifest_path - self.manifest = util.load_json(manifest_path) + self._manifest = util.load_json(manifest_path) def get(self, path, default=None): try: - value = self.manifest + value = self._manifest for k in path.split("."): value = value[k] return value @@ -486,4 +489,4 @@ class PlatformBoardConfig(object): return False def get_manifest(self): - return self.manifest + return self._manifest From bf149c075d57fb9335dff862ee9c504bef8abb6e Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 30 May 2016 14:31:58 +0300 Subject: [PATCH 012/284] Auto install too-unity for hardware unit testing --- platformio/managers/platform.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 611933f1..4697dc61 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -154,10 +154,10 @@ class PlatformFactory(object): ) else: platform_cls = type( - str(cls.get_clsname(name)), (BasePlatform,), {}) + str(cls.get_clsname(name)), (PlatformBase,), {}) _instance = platform_cls(join(platform_dir, "platform.json")) - assert isinstance(_instance, BasePlatform) + assert isinstance(_instance, PlatformBase) return _instance @@ -313,7 +313,7 @@ class PlatformRunMixin(object): return 1 -class BasePlatform(PlatformPackagesMixin, PlatformRunMixin): +class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): _BOARDS_CACHE = {} @@ -460,6 +460,12 @@ class BasePlatform(PlatformPackagesMixin, PlatformRunMixin): # skip all packages, allow only upload tools self.packages[_name]['optional'] = True + if "test" in targets and "tool-unity" not in self.packages: + self.packages['tool-unity'] = { + "version": "~1.20302.0", + "optional": False + } + class PlatformBoardConfig(object): From bfd66deb37ccbae8f431ccad9704c568a2de9e1a Mon Sep 17 00:00:00 2001 From: Valeriy Koval Date: Mon, 30 May 2016 17:50:37 +0300 Subject: [PATCH 013/284] Initial support for unit testing // Issue #408 --- platformio/builder/main.py | 4 +- platformio/builder/tools/piotest.py | 146 +++++++++++++++++++++++++ platformio/builder/tools/platformio.py | 3 + platformio/util.py | 7 ++ 4 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 platformio/builder/tools/piotest.py diff --git a/platformio/builder/main.py b/platformio/builder/main.py index b4f00241..faaa1e1a 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -62,7 +62,7 @@ commonvars.AddVariables( DefaultEnvironment( tools=[ "gcc", "g++", "as", "ar", "gnulink", - "platformio", "devplatform", "pioupload", "pioar", "piomisc" + "platformio", "devplatform", "piotest", "pioupload", "pioar", "piomisc" ], toolpath=[join(util.get_source_dir(), "builder", "tools")], variables=commonvars, @@ -77,11 +77,13 @@ DefaultEnvironment( PROJECT_DIR=util.get_project_dir(), PROJECTLIB_DIR=util.get_projectlib_dir(), PROJECTSRC_DIR=util.get_projectsrc_dir(), + PROJECTTEST_DIR=util.get_projecttest_dir(), PROJECTDATA_DIR=util.get_projectdata_dir(), PIOENVS_DIR=util.get_pioenvs_dir(), BUILD_DIR=join("$PIOENVS_DIR", "$PIOENV"), BUILDSRC_DIR=join("$BUILD_DIR", "src"), + BUILDTEST_DIR=join("$BUILD_DIR", "test"), LIBSOURCE_DIRS=[ "$PROJECTLIB_DIR", util.get_lib_dir() diff --git a/platformio/builder/tools/piotest.py b/platformio/builder/tools/piotest.py new file mode 100644 index 00000000..c8044d93 --- /dev/null +++ b/platformio/builder/tools/piotest.py @@ -0,0 +1,146 @@ +# Copyright 2014-2016 Ivan Kravets +# +# 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 atexit +from os import remove +from os.path import isdir, isfile, join +from string import Template + +FRAMEWORKS_PARAMETERS = { + "arduino": { + "framework": "Arduino.h", + "serial_obj": "", + "serial_putc": "Serial.write(a)", + "serial_flush": "Serial.flush()", + "serial_begin": "Serial.begin(9600)", + "serial_end": "Serial.end()" + }, + + "mbed": { + "framework": "mbed.h", + "serial_obj": "Serial pc(USBTX, USBRX);", + "serial_putc": "pc.putc(a)", + "serial_flush": "", + "serial_begin": "pc.baud(9600)", + "serial_end": "" + }, + + "energia": { + "framework": "Energia.h", + "serial_obj": "", + "serial_putc": "Serial.write(a)", + "serial_flush": "Serial.flush()", + "serial_begin": "Serial.begin(9600)", + "serial_end": "Serial.end()" + } +} + + +def ProcessTest(env): + + test_dir = env.subst("$PROJECTTEST_DIR") + + env.Append( + CPPDEFINES=[ + "UNIT_TEST", + "UNITY_INCLUDE_CONFIG_H" + ], + + CPPPATH=[ + join("$BUILD_DIR", "UnityTestLib") + ] + ) + + unitylib = env.BuildLibrary( + join("$BUILD_DIR", "UnityTestLib"), + env.DevPlatform().get_package_dir("tool-unity") + + ) + + env.Prepend(LIBS=[unitylib]) + + env.GenerateOutputReplacement(test_dir) + + return env.LookupSources( + "$BUILDTEST_DIR", test_dir, duplicate=False) + + +def GenerateOutputReplacement(env, destination_dir): + + if not isdir(env.subst(destination_dir)): + env.Exit( + "Error: Test folder doesn't exist. Please put your test suite " + 'to \"test\" folder in project\'s root directory.') + + TEMPLATECPP = """ +# include <$framework> +# include + +$serial_obj + +void output_char(int a) +{ + $serial_putc; +} + +void output_flush(void) +{ + $serial_flush; +} + +void output_start(unsigned int baudrate) +{ + $serial_begin; +} + +void output_complete(void) +{ + $serial_end; +} + +""" + + def delete_tmptest_file(file_): + try: + remove(file_) + except: # pylint: disable=bare-except + if isfile(file_): + print("Warning: Could not remove temporary file '%s'. " + "Please remove it manually." % file_) + + framework = env.subst("$FRAMEWORK").lower() + if framework not in FRAMEWORKS_PARAMETERS.keys(): + env.Exit( + "Error: %s framework doesn't support testing feature!" % framework) + else: + data = Template(TEMPLATECPP).substitute( + FRAMEWORKS_PARAMETERS[framework]) + + tmp_file = join(destination_dir, "output_export.cpp") + with open(tmp_file, "w") as f: + f.write(data) + + atexit.register(delete_tmptest_file, tmp_file) + + +def exists(_): + return True + + +def generate(env): + env.AddMethod(ProcessTest) + env.AddMethod(GenerateOutputReplacement) + return env diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index f7c88fd5..9599dbd6 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -88,6 +88,9 @@ def BuildProgram(env): "$BUILDSRC_DIR", "$PROJECTSRC_DIR", duplicate=False, src_filter=env.get("SRC_FILTER")) + if "test" in COMMAND_LINE_TARGETS: + sources.extend(env.ProcessTest()) + if not sources and not COMMAND_LINE_TARGETS: env.Exit( "Error: Nothing to build. Please put your source code files " diff --git a/platformio/util.py b/platformio/util.py index dd6026e9..394b3201 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -207,6 +207,13 @@ def get_projectsrc_dir(): ) +def get_projecttest_dir(): + return _get_projconf_option_dir( + "test_dir", + join(get_project_dir(), "test") + ) + + def get_projectlib_dir(): return join(get_project_dir(), "lib") From d6b6fa2baf69741fad8d45bdbe45e08ce9722953 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 31 May 2016 00:22:25 +0300 Subject: [PATCH 014/284] Install development platform from local dir and VCS(git, hg, svn) // Issue #479 --- docs/projectconf.rst | 25 ++++ docs/userguide/platforms/cmd_install.rst | 138 ++++++++++++++++++--- docs/userguide/platforms/cmd_uninstall.rst | 13 +- docs/userguide/platforms/cmd_update.rst | 110 +++++++--------- platformio/commands/run.py | 3 +- platformio/exception.py | 5 - platformio/managers/package.py | 117 +++++++++-------- platformio/managers/platform.py | 24 ++-- platformio/vcsclient.py | 97 +++++++++++++++ 9 files changed, 374 insertions(+), 158 deletions(-) create mode 100644 platformio/vcsclient.py diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 3ddf6ea5..13c1b3ca 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -196,6 +196,31 @@ General options :ref:`platforms` name. +PlatformIO allows to use specific platform versions using +`Semantic Versioning `_ (X.Y.Z=MAJOR.MINOR.PATCH). +Version specifications can take any of the following forms: + +* ``0.1.2``: an exact version number. Use only this exact version +* ``^0.1.2``: any compatible version (exact version for ``0.x.x`` versions +* ``~0.1.2``: any version with the same major and minor versions, and an + equal or greater patch version +* ``>0.1.2``: any version greater than ``0.1.2``. ``>=``, ``<``, and ``<=`` + are also possible +* ``>0.1.0,!=0.2.0,<0.3.0``: any version greater than ``0.1.0``, not equal to + ``0.2.0`` and less than ``0.3.0`` + +Examples: + +.. code-block:: ini + + [env:the_latest_version] + platform = atmelavr + + [env:specific_major_version] + platform = atmelavr@^0.1.2 + + [env:specific_major_and_minor_version] + platform = atmelavr@~0.1.2 .. _projectconf_env_framework: diff --git a/docs/userguide/platforms/cmd_install.rst b/docs/userguide/platforms/cmd_install.rst index 86b678af..64298e01 100644 --- a/docs/userguide/platforms/cmd_install.rst +++ b/docs/userguide/platforms/cmd_install.rst @@ -22,22 +22,90 @@ Usage .. code-block:: bash # install platform by name - platformio platform install [OPTIONS] [PLATFORMS] + platformio platform install [OPTIONS] PLATFORM - # install platform from local directory - platformio platform install [OPTIONS] [file:///local/path/to/platform/dir] + # install specific platform version using Semantic Versioning + platformio platform install [OPTIONS] PLATFORM@X.Y.Z + + # install platform using URL + platformio platform install [OPTIONS] URL Description ----------- -Install development :ref:`platforms` and dependent packages. +Install :ref:`platforms` and dependent packages. There are several predefined aliases for packages, such as: +* ``framework`` * ``toolchain`` * ``uploader`` +Local +~~~~~ + +PlatformIO supports installing development platform from local directory. Here +is supported form: + +* file:///local/path/to/the/platform/dir + +VCS +~~~ + +PlatformIO supports installing from Git, Mercurial and Subversion, and detects +the type of VCS using url prefixes: "git+", "hg+", or "svn+". + +PlatformIO requires a working VCS command on your path: git, hg or svn. + +Git +^^^ + +The supported schemes are: ``git``, ``git+https`` and ``git+ssh``. Here are +the supported forms: + +* https://github.com/platformio/platform-NAME.git +* git+git://git.server.org/my-platform +* git+https://git.server.org/my-platform +* git+ssh://git.server.org/my-platform + +Passing branch names, a commit hash or a tag name is possible like so: + +* https://github.com/platformio/platform-name.git#master +* git+git://git.server.org/my-platform#master +* git+https://git.server.org/my-platform#v1.0 +* git+ssh://git.server.org/my-platform#7846d8ad52f983f2f2887bdc0f073fe9755a806d + +Mercurial +^^^^^^^^^ + +The supported schemes are: ``hg+http``, ``hg+https`` and ``hg+ssh``. Here are +the supported forms: + +* hg+hg://hg.server.org/my-platform +* hg+https://hg.server.org/my-platform +* hg+ssh://hg.server.org/my-platform + +Passing branch names, a commit hash or a tag name is possible like so: + +* hg+hg://hg.server.org/my-platform#master +* hg+https://hg.server.org/my-platform#v1.0 +* hg+ssh://hg.server.org/my-platform#4cfe2fa00668 + +Subversion +^^^^^^^^^^ + +The supported schemes are: ``svn``, ``svn+svn``, ``svn+http``, ``svn+https`` +and ``svn+ssh``. Here are the supported forms: + +* svn+svn://svn.server.org/my-platform +* svn+https://svn.server.org/my-platform +* svn+ssh://svn.server.org/my-platform + +You can also give specific revisions to an SVN URL, like so: + +* svn+svn://svn.server.org/my-platform#13 + Options ------- @@ -62,30 +130,68 @@ Skip default packages Examples -------- -1. Install :ref:`platform_timsp430` with default packages +1. Install :ref:`platform_atmelavr` with default packages .. code-block:: bash - $ platformio platform install timsp430 - Installing toolchain-timsp430 package: + $ platformio platform install atmelavr + Installing platform atmelavr @ latest: + Downloading... + Unpacking [####################################] 100% + Installing package tool-scons @ >=2.3.0,<2.6.0: Downloading [####################################] 100% Unpacking [####################################] 100% - Installing tool-mspdebug package: + Installing package toolchain-atmelavr @ ~1.40801.0: Downloading [####################################] 100% Unpacking [####################################] 100% - Installing framework-energiamsp430 package: - Downloading [####################################] 100% - Unpacking [####################################] 100% - The platform 'timsp430' has been successfully installed! + The platform 'atmelavr' has been successfully installed! + The rest of packages will be installed automatically depending on your build environment. -2. Install :ref:`platform_timsp430` with ``uploader`` utility only and skip +2. Install :ref:`platform_atmelavr` with ``uploader`` utility only and skip default packages .. code-block:: bash - $ platformio platform install timsp430 --skip-default-package --with-package=uploader - Installing tool-mspdebug package: + $ platformio platform install atmelavr --skip-default-package --with-package=uploader + Installing platform atmelavr @ latest: Downloading [####################################] 100% Unpacking [####################################] 100% - The platform 'timsp430' has been successfully installed! + Installing package tool-micronucleus @ ~1.200.0: + Downloading [####################################] 100% + Unpacking [####################################] 100% + Installing package tool-avrdude @ >=1.60001.0,<1.60101.0: + Downloading [####################################] 100% + Unpacking [####################################] 100% + The platform 'atmelavr' has been successfully installed! + The rest of packages will be installed automatically depending on your build environment. + +3. Install the latest development :ref:`platform_atmelavr` from Git repository + +.. code-block:: bash + + $ platformio platform install https://github.com/platformio/platform-atmelavr.git + Installing platform https://github.com/platformio/platform-atmelavr.git @ latest: + git version 2.7.4 (Apple Git-66) + Cloning into '/Users/ikravets/.platformio/platforms/installing-XMIsAE-package'... + remote: Counting objects: 172, done. + remote: Compressing objects: 100% (51/51), done. + remote: Total 172 (delta 109), reused 168 (delta 109), pack-reused 0 + Receiving objects: 100% (172/172), 38.18 KiB | 0 bytes/s, done. + Resolving deltas: 100% (109/109), done. + Checking connectivity... done. + Submodule 'examples/arduino-external-libs/lib/OneWire' (https://github.com/PaulStoffregen/OneWire.git) registered for path 'examples/arduino-external-libs/lib/OneWire' + Cloning into 'examples/arduino-external-libs/lib/OneWire'... + remote: Counting objects: 87, done. + remote: Total 87 (delta 0), reused 0 (delta 0), pack-reused 87 + Unpacking objects: 100% (87/87), done. + Checking connectivity... done. + Submodule path 'examples/arduino-external-libs/lib/OneWire': checked out '57c18c6de80c13429275f70875c7c341f1719201' + Installing package tool-scons @ >=2.3.0,<2.6.0: + Downloading [####################################] 100% + Unpacking [####################################] 100% + Installing package toolchain-atmelavr @ ~1.40801.0: + Downloading [####################################] 100% + Unpacking [####################################] 100% + The platform 'https://github.com/platformio/platform-atmelavr.git' has been successfully installed! + The rest of packages will be installed automatically depending on your build environment. diff --git a/docs/userguide/platforms/cmd_uninstall.rst b/docs/userguide/platforms/cmd_uninstall.rst index 67cc273a..f1375d5e 100644 --- a/docs/userguide/platforms/cmd_uninstall.rst +++ b/docs/userguide/platforms/cmd_uninstall.rst @@ -23,6 +23,9 @@ Usage platformio platform uninstall PLATFORM + # uninstall specific platform version using Semantic Versioning + platformio platform uninstall PLATFORM@X.Y.Z + Description ----------- @@ -35,8 +38,8 @@ Examples .. code-block:: bash - $ platformio platform uninstall timsp430 - Uninstalling toolchain-timsp430 package: [OK] - Uninstalling tool-mspdebug package: [OK] - Uninstalling framework-energiamsp430 package: [OK] - The platform 'timsp430' has been successfully uninstalled! + $ platformio platform uninstall atmelavr + Uninstalling platform atmelavr @ latest: [OK] + Uninstalling package tool-scons @ 2.5.0: [OK] + Uninstalling package toolchain-atmelavr @ 1.40801.0: [OK] + The platform 'atmelavr' has been successfully uninstalled! diff --git a/docs/userguide/platforms/cmd_update.rst b/docs/userguide/platforms/cmd_update.rst index 8e4fec64..918aca8a 100644 --- a/docs/userguide/platforms/cmd_update.rst +++ b/docs/userguide/platforms/cmd_update.rst @@ -46,75 +46,53 @@ Examples .. code-block:: bash $ platformio platform update - - Platform atmelavr + Platform atmelavr @ 0.0.0 -------- - Updating toolchain-atmelavr package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating tool-avrdude package: - Versions: Current=2, Latest=2 [Up-to-date] - Updating framework-arduinoavr package: - Versions: Current=12, Latest=12 [Up-to-date] - Updating tool-micronucleus package: - Versions: Current=1, Latest=1 [Up-to-date] + Updating platform atmelavr @ latest: + Versions: Current=0.0.0, Latest=0.0.0 [Up-to-date] + Updating package framework-arduinoavr @ ~1.10608.0: + Versions: Current=1.10608.0, Latest=1.10608.0 [Up-to-date] + Updating package toolchain-atmelavr @ ~1.40801.0: + Versions: Current=1.40801.0, Latest=1.40801.0 [Up-to-date] + Updating package framework-simba @ ~1.500.0: + Versions: Current=1.500.0, Latest=1.500.0 [Up-to-date] + Updating package tool-scons @ >=2.3.0,<2.6.0: + Versions: Current=2.5.0, Latest=2.5.0 [Up-to-date] - Platform atmelsam + Platform atmelsam @ 0.0.0 -------- - Updating framework-arduinosam package: - Versions: Current=3, Latest=3 [Up-to-date] - Updating ldscripts package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating toolchain-gccarmnoneeabi package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating tool-bossac package: - Versions: Current=1, Latest=1 [Up-to-date] + Updating platform atmelsam @ latest: + Versions: Current=0.0.0, Latest=0.0.0 [Up-to-date] + Updating package toolchain-gccarmnoneeabi @ >=1.40803.0,<1.40805.0: + Versions: Current=1.40804.0, Latest=1.40804.0 [Up-to-date] + Updating package framework-arduinosam @ ~1.10607.0: + Versions: Current=1.10607.0, Latest=1.10607.0 [Up-to-date] + Updating package framework-simba @ ~1.500.0: + Versions: Current=1.500.0, Latest=1.500.0 [Up-to-date] + Updating package framework-mbed @ ~1.117.0: + Versions: Current=1.117.0, Latest=1.117.0 [Up-to-date] + Updating package tool-scons @ >=2.3.0,<2.6.0: + Versions: Current=2.5.0, Latest=2.5.0 [Up-to-date] + Updating package tool-bossac @ ~1.10500.0: + Versions: Current=1.10500.0, Latest=1.10500.0 [Up-to-date] - Platform stm32 + Platform espressif @ 0.0.0 -------- - Updating toolchain-gccarmnoneeabi package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating tool-stlink package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating framework-spl package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating framework-cmsis package: - Versions: Current=2, Latest=2 [Up-to-date] - Updating framework-opencm3 package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating ldscripts package: - Versions: Current=1, Latest=1 [Up-to-date] + Updating platform espressif @ latest: + Versions: Current=0.0.0, Latest=0.0.0 [Up-to-date] + Updating package tool-scons @ >=2.3.0,<2.6.0: + Versions: Current=2.5.0, Latest=2.5.0 [Up-to-date] + Updating package toolchain-xtensa @ ~1.40802.0: + Versions: Current=1.40802.0, Latest=1.40802.0 [Up-to-date] + Updating package framework-simba @ ~1.500.0: + Versions: Current=1.500.0, Latest=1.500.0 [Up-to-date] + Updating package tool-esptool @ ~1.408.0: + Versions: Current=1.408.0, Latest=1.408.0 [Up-to-date] + Updating package tool-mkspiffs @ ~1.102.0: + Versions: Current=1.102.0, Latest=1.102.0 [Up-to-date] + Updating package framework-arduinoespressif @ ~1.20200.0: + Versions: Current=1.20200.0, Latest=1.20200.0 [Up-to-date] + Updating package sdk-esp8266 @ ~1.10502.0: + Versions: Current=1.10502.0, Latest=1.10502.0 [Up-to-date] - Platform teensy - -------- - Updating toolchain-atmelavr package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating ldscripts package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating framework-arduinoteensy package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating toolchain-gccarmnoneeabi package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating tool-teensy package: - Versions: Current=1, Latest=1 [Up-to-date] - - Platform timsp430 - -------- - Updating toolchain-timsp430 package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating tool-mspdebug package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating framework-energiamsp430 package: - Versions: Current=2, Latest=2 [Up-to-date] - - Platform titiva - -------- - Updating ldscripts package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating toolchain-gccarmnoneeabi package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating tool-lm4flash package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating framework-opencm3 package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating framework-energiativa package: - Versions: Current=4, Latest=4 [Up-to-date] + ... diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 8b80d26d..76f375a5 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -205,7 +205,8 @@ class EnvironmentProcessor(object): try: p = PlatformFactory.newPlatform(platform, version) except exception.UnknownPlatform: - self.cmd_ctx.invoke(cmd_platform_install, platforms=[platform]) + self.cmd_ctx.invoke( + cmd_platform_install, platforms=[self.options['platform']]) p = PlatformFactory.newPlatform(platform, version) return p.run(build_vars, build_targets, self.verbose_level) diff --git a/platformio/exception.py b/platformio/exception.py index a375b587..3fe366f2 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -70,11 +70,6 @@ class UnknownPackage(PlatformioException): MESSAGE = "Detected unknown package '{0}'" -class InvalidLocalPackage(PlatformioException): - - MESSAGE = "Invalid local package '{0}'. Can not find manifest '{1}'" - - class UndefinedPackageVersion(PlatformioException): MESSAGE = "Can not find package '{0}' with version requirements '{1}'"\ diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 8b37520b..5d0e0a63 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -15,6 +15,7 @@ import os from os.path import dirname, isdir, isfile, islink, join from shutil import copyfile, copytree, rmtree +from tempfile import mkdtemp import click import requests @@ -23,6 +24,7 @@ import semantic_version from platformio import exception, telemetry, util from platformio.downloader import FileDownloader from platformio.unpacker import FileUnpacker +from platformio.vcsclient import VCSClientFactory class PackageManager(object): @@ -87,32 +89,6 @@ class PackageManager(object): "Could not find '%s' manifest file in the package" % self.manifest_name) - def make_pkg_dir(self, name, version): - pkg_dir = join(self.package_dir, name) - if isfile(join(pkg_dir, self.manifest_name)): - manifest = util.load_json( - join(pkg_dir, self.manifest_name)) - - cmp_result = semantic_version.compare(version, manifest['version']) - if cmp_result == 1: - # if main package version < new package, backup it - print pkg_dir, join( - self.package_dir, "%s@%s" % (name, manifest['version'])) - os.rename(pkg_dir, join( - self.package_dir, "%s@%s" % (name, manifest['version']))) - elif cmp_result == -1: - pkg_dir = join( - self.package_dir, "%s@%s" % (name, version)) - - # remove previous/not-satisfied package - if isdir(pkg_dir): - rmtree(pkg_dir) - os.makedirs(pkg_dir) - assert isdir(pkg_dir) - - self.reset_cache() - return pkg_dir - @staticmethod def max_satisfying_repo_version(versions, requirements=None): item = None @@ -196,12 +172,11 @@ class PackageManager(object): return self.max_satisfying_version( name, requirements).get("_manifest_path") - manifest_path = None - if name.startswith("file://"): - manifest_path = self._install_from_local_dir(name[7:]) + if "://" in name: + pkg_dir = self._install_from_url(name, requirements) else: - manifest_path = self._install_from_piorepo(name, requirements) - if not isfile(manifest_path): + pkg_dir = self._install_from_piorepo(name, requirements) + if not pkg_dir or not isfile(join(pkg_dir, self.manifest_name)): raise exception.PackageInstallError( name, requirements or "latest", util.get_systype()) @@ -210,32 +185,23 @@ class PackageManager(object): telemetry.on_event( category="PackageManager", action="Install", label=name) - return manifest_path + return join(pkg_dir, self.manifest_name) def _install_from_piorepo(self, name, requirements): pkg_dir = None pkgdata = None versions = None for versions in PackageRepoIterator(name, self.repositories): - dlpath = None pkgdata = self.max_satisfying_repo_version(versions, requirements) if not pkgdata: continue - - pkg_dir = self.make_pkg_dir(name, pkgdata['version']) try: - dlpath = self.download( - pkgdata['url'], pkg_dir, pkgdata.get("sha1")) - assert isfile(dlpath) - self.unpack(dlpath, pkg_dir) - self.check_structure(pkg_dir) + pkg_dir = self._install_from_url( + pkgdata['url'], requirements, pkgdata.get("sha1")) break except Exception as e: # pylint: disable=broad-except click.secho("Warning! Package Mirror: %s" % e, fg="yellow") click.secho("Looking for another mirror...", fg="yellow") - finally: - if dlpath and isfile(dlpath): - os.remove(dlpath) if versions is None: raise exception.UnknownPackage(name) @@ -246,21 +212,64 @@ class PackageManager(object): else: raise exception.UndefinedPackageVersion( name, requirements or "latest", util.get_systype()) + return pkg_dir - return join(pkg_dir, self.manifest_name) + def _install_from_url(self, url, requirements=None, sha1=None): + pkg_dir = None + tmp_dir = mkdtemp("-package", "installing-", self.package_dir) - def _install_from_local_dir(self, local_dir): - if not isfile(join(local_dir, self.manifest_name)): - raise exception.InvalidLocalPackage( - local_dir, self.manifest_name) + # Handle GitHub URL (https://github.com/user/repo.git) + if url.endswith(".git") and not url.startswith("git"): + url = "git+" + url - manifest = util.load_json(join(local_dir, self.manifest_name)) - assert set(["name", "version"]) <= set(manifest.keys()) - pkg_dir = self.make_pkg_dir(manifest['name'], manifest['version']) - rmtree(pkg_dir) - copytree(local_dir, pkg_dir, symlinks=True) + try: + if url.startswith("file://"): + rmtree(tmp_dir) + copytree(url[7:], tmp_dir) + elif url.startswith(("http://", "https://", "ftp://")): + dlpath = self.download(url, tmp_dir, sha1) + assert isfile(dlpath) + self.unpack(dlpath, tmp_dir) + os.remove(dlpath) + else: + repo = VCSClientFactory.newClient(url) + repo.export(tmp_dir) - return join(pkg_dir, self.manifest_name) + self.check_structure(tmp_dir) + pkg_dir = self._install_from_tmp_dir(tmp_dir, requirements) + finally: + if isdir(tmp_dir): + rmtree(tmp_dir) + return pkg_dir + + def _install_from_tmp_dir(self, tmp_dir, requirements=None): + tmpmanifest = util.load_json(join(tmp_dir, self.manifest_name)) + assert set(["name", "version"]) <= set(tmpmanifest.keys()) + name = tmpmanifest['name'] + + # package should satisfy requirements + if requirements: + assert semantic_version.match(requirements, tmpmanifest['version']) + + pkg_dir = join(self.package_dir, name) + if isfile(join(pkg_dir, self.manifest_name)): + manifest = util.load_json(join(pkg_dir, self.manifest_name)) + cmp_result = semantic_version.compare( + tmpmanifest['version'], manifest['version']) + if cmp_result == 1: + # if main package version < new package, backup it + os.rename(pkg_dir, join( + self.package_dir, "%s@%s" % (name, manifest['version']))) + elif cmp_result == -1: + pkg_dir = join( + self.package_dir, "%s@%s" % (name, tmpmanifest['version'])) + + # remove previous/not-satisfied package + if isdir(pkg_dir): + rmtree(pkg_dir) + os.rename(tmp_dir, pkg_dir) + assert isdir(pkg_dir) + return pkg_dir def uninstall(self, name, requirements=None, trigger_event=True): click.echo("Uninstalling %s %s @ %s: \t" % ( diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 4697dc61..ed5140a8 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -44,25 +44,26 @@ class PlatformManager(PackageManager): name, requirements=None, with_packages=None, without_packages=None, skip_default_packages=False): manifest_path = PackageManager.install(self, name, requirements) - PlatformFactory.newPlatform( - manifest_path, requirements).install_packages( - with_packages, without_packages, skip_default_packages) - self.cleanup_packages() + p = PlatformFactory.newPlatform(manifest_path, requirements) + p.install_packages( + with_packages, without_packages, skip_default_packages) + self.cleanup_packages(p.packages.keys()) return True def uninstall(self, # pylint: disable=arguments-differ name, requirements=None): + p = PlatformFactory.newPlatform(name, requirements) PackageManager.uninstall(self, name, requirements) - self.cleanup_packages() + self.cleanup_packages(p.packages.keys()) return True def update(self, # pylint: disable=arguments-differ name, requirements=None, only_packages=False): if not only_packages: PackageManager.update(self, name) - PlatformFactory.newPlatform( - name, requirements).update_packages() - self.cleanup_packages() + p = PlatformFactory.newPlatform(name, requirements) + p.update_packages() + self.cleanup_packages(p.packages.keys()) return True def is_outdated(self, name, requirements=None): @@ -70,7 +71,7 @@ class PlatformManager(PackageManager): return (p.are_outdated_packages() or p.version != self.get_latest_repo_version(name, requirements)) - def cleanup_packages(self): + def cleanup_packages(self, names): self.reset_cache() deppkgs = {} for manifest in PlatformManager().get_installed(): @@ -83,9 +84,10 @@ class PlatformManager(PackageManager): pm = PackageManager() for manifest in pm.get_installed(): - if manifest['name'] not in deppkgs: + if manifest['name'] not in names: continue - if manifest['version'] not in deppkgs[manifest['name']]: + if (manifest['name'] not in deppkgs or + manifest['version'] not in deppkgs[manifest['name']]): pm.uninstall( manifest['name'], manifest['version'], trigger_event=False) diff --git a/platformio/vcsclient.py b/platformio/vcsclient.py new file mode 100644 index 00000000..612f287a --- /dev/null +++ b/platformio/vcsclient.py @@ -0,0 +1,97 @@ +# Copyright 2014-present Ivan Kravets +# +# 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 platform import system +from subprocess import check_call +from sys import modules +from urlparse import urlsplit, urlunsplit + +from platformio.exception import PlatformioException + + +class VCSClientFactory(object): + + @staticmethod + def newClient(url): + scheme, netloc, path, query, fragment = urlsplit(url) + type_ = scheme + if "+" in type_: + type_, scheme = type_.split("+", 1) + url = urlunsplit((scheme, netloc, path, query, None)) + clsname = "%sClient" % type_.title() + obj = getattr(modules[__name__], clsname)(url, fragment) + assert isinstance(obj, VCSClientBase) + return obj + + +class VCSClientBase(object): + + command = None + + def __init__(self, url, branch=None): + self.url = url + self.branch = branch + self.check_client() + + def check_client(self): + try: + assert self.command + assert self.run_cmd(["--version"]) == 0 + except (AssertionError, OSError): + raise PlatformioException( + "VCS: `%s` client is not installed in your system" % + self.command) + return True + + def export(self, dst_dir): + raise NotImplementedError + + def run_cmd(self, args): + return check_call([self.command] + args, shell=system() == "Windows") + + +class GitClient(VCSClientBase): + + command = "git" + + def export(self, dst_dir): + args = ["clone", "--recursive", "--depth", "1"] + if self.branch: + args.extend(["--branch", self.branch]) + args.extend([self.url, dst_dir]) + self.run_cmd(args) + + +class HgClient(VCSClientBase): + + command = "hg" + + def export(self, dst_dir): + args = ["clone"] + if self.branch: + args.extend(["--updaterev", self.branch]) + args.extend([self.url, dst_dir]) + self.run_cmd(args) + + +class SvnClient(VCSClientBase): + + command = "svn" + + def export(self, dst_dir): + args = ["export", "--force"] + if self.branch: + args.extend(["--revision", self.branch]) + args.extend([self.url, dst_dir]) + self.run_cmd(args) From ff7bc9092db8f6e45db09267cb5818362dfb0500 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 31 May 2016 23:43:27 +0300 Subject: [PATCH 015/284] Patch development platforms after upgrade process // Issue #479 --- platformio/maintenance.py | 6 +++++- platformio/managers/platform.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/platformio/maintenance.py b/platformio/maintenance.py index 0e82bb58..ac056bdf 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -113,7 +113,11 @@ def after_upgrade(ctx): u = Upgrader(last_version, __version__) if u.run(ctx): app.set_state_item("last_version", __version__) - ctx.invoke(cmd_platform_update, only_packages=True) + + # patch development platforms + pm = PlatformManager() + for manifest in pm.get_installed(): + pm.update(manifest['name'], "~" + manifest['version']) click.secho("PlatformIO has been successfully upgraded to %s!\n" % __version__, fg="green") diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index ed5140a8..4fab1720 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -60,7 +60,7 @@ class PlatformManager(PackageManager): def update(self, # pylint: disable=arguments-differ name, requirements=None, only_packages=False): if not only_packages: - PackageManager.update(self, name) + PackageManager.update(self, name, requirements) p = PlatformFactory.newPlatform(name, requirements) p.update_packages() self.cleanup_packages(p.packages.keys()) From 3a143270c24e2d299785ba8db7288194c5fc5f41 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 8 Jun 2016 13:34:49 +0300 Subject: [PATCH 016/284] Handle custom boards --- platformio/commands/boards.py | 25 ++++++------ platformio/maintenance.py | 42 +++++++++++-------- platformio/managers/platform.py | 72 ++++++++++++++++++++++++--------- 3 files changed, 91 insertions(+), 48 deletions(-) diff --git a/platformio/commands/boards.py b/platformio/commands/boards.py index 1a5c258d..07b800a0 100644 --- a/platformio/commands/boards.py +++ b/platformio/commands/boards.py @@ -16,6 +16,7 @@ import json import click +from platformio.exception import APIRequestError from platformio.managers.platform import PlatformManager @@ -78,24 +79,24 @@ def cli(query, installed, json_output): # pylint: disable=R0912 def _get_boards(installed=False): - boards = PlatformManager.get_registered_boards() - if installed: - _installed_boards = [ - "%s:%s" % (b['platform'], b['id']) - for b in PlatformManager().get_installed_boards() - ] - _new_boards = [] - for board in boards: + boards = PlatformManager().get_installed_boards() + if not installed: + know_boards = ["%s:%s" % (b['platform'], b['id']) for b in boards] + for board in PlatformManager().get_registered_boards(): key = "%s:%s" % (board['platform'], board['id']) - if key in _installed_boards: - _new_boards.append(board) - boards = _new_boards + if key not in know_boards: + boards.append(board) return boards def _ouput_boards_json(query, installed=False): result = [] - for board in _get_boards(installed): + try: + boards = _get_boards(installed) + except APIRequestError: + if not installed: + boards = _get_boards(True) + for board in boards: if query: search_data = "%s %s" % (board['id'], json.dumps(board).lower()) if query.lower() not in search_data.lower(): diff --git a/platformio/maintenance.py b/platformio/maintenance.py index ac056bdf..c91857dc 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -12,12 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -import re -import struct +import json +import os from os import getenv +from os.path import isdir, join from time import time import click +import semantic_version from platformio import __version__, app, exception, telemetry, util from platformio.commands.lib import lib_update as cmd_libraries_update @@ -65,21 +67,13 @@ def on_platformio_exception(e): class Upgrader(object): def __init__(self, from_version, to_version): - self.from_version = self.version_to_int(from_version) - self.to_version = self.version_to_int(to_version) + self.from_version = semantic_version.Version.coerce(from_version) + self.to_version = semantic_version.Version.coerce(to_version) self._upgraders = [ - (self.version_to_int("3.0.0"), self._upgrade_to_3_0_0) + (semantic_version.Version("3.0.0"), self._upgrade_to_3_0_0) ] - @staticmethod - def version_to_int(version): - match = re.match(r"(\d+)\.(\d+)\.(\d+)(\D+)?", version) - assert match is not None and len(match.groups()) is 4 - verchrs = [chr(int(match.group(i))) for i in range(1, 4)] - verchrs.append(chr(255 if match.group(4) is None else 0)) - return struct.unpack(">I", "".join(verchrs)) - def run(self, ctx): if self.from_version > self.to_version: return True @@ -93,9 +87,26 @@ class Upgrader(object): return all(result) def _upgrade_to_3_0_0(self, ctx): # pylint: disable=R0201 + # convert custom board configuration + boards_dir = join(util.get_home_dir(), "boards") + if isdir(boards_dir): + for item in os.listdir(boards_dir): + if not item.endswith(".json"): + continue + data = util.load_json(join(boards_dir, item)) + if set(["name", "url", "vendor"]) <= set(data.keys()): + continue + os.remove(join(boards_dir, item)) + for key, value in data.items(): + with open(join(boards_dir, "%s.json" % key), + "w") as f: + json.dump(value, f, sort_keys=True, indent=2) + + # re-install PlatformIO 2.0 development platforms installed_platforms = app.get_state_item("installed_platforms", []) if installed_platforms: ctx.invoke(cmd_platform_install, platforms=installed_platforms) + return True @@ -169,9 +180,8 @@ def check_platformio_upgrade(): app.set_state_item("last_check", last_check) latest_version = get_latest_version() - if (latest_version == __version__ or - Upgrader.version_to_int(latest_version) < - Upgrader.version_to_int(__version__)): + if (semantic_version.Version.coerce(latest_version) <= + semantic_version.Version.coerce(__version__)): return terminal_width, _ = click.get_terminal_size() diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 4fab1720..649166ef 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -98,11 +98,8 @@ class PlatformManager(PackageManager): boards = [] for manifest in self.get_installed(): p = PlatformFactory.newPlatform(manifest['_manifest_path']) - for id_, config in p.get_boards().items(): - manifest = config.get_manifest().copy() - manifest['id'] = id_ - manifest['platform'] = p.name - boards.append(manifest) + for config in p.get_boards().values(): + boards.append(config.get_brief_data()) return boards @staticmethod @@ -394,22 +391,37 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): return False def get_boards(self, id_=None): + + def _append_board(board_id, manifest_path): + config = PlatformBoardConfig(manifest_path) + if "platform" in config and config.get("platform") != self.name: + return + elif ("platforms" in config and + self.name not in config.get("platforms")): + return + config.manifest['platform'] = self.name + self._BOARDS_CACHE[board_id] = config + + bdirs = (join(util.get_home_dir(), "boards"), + join(self.get_dir(), "boards")) if id_ is None: - boards_dir = join(self.get_dir(), "boards") - if not isdir(boards_dir): - return {} - for item in sorted(os.listdir(boards_dir)): - _id = item[:-5] - if _id in self._BOARDS_CACHE: + for boards_dir in bdirs: + if not isdir(boards_dir): continue - self._BOARDS_CACHE[_id] = PlatformBoardConfig( - join(self.get_dir(), "boards", item) - ) + for item in sorted(os.listdir(boards_dir)): + _id = item[:-5] + if not item.endswith(".json") or _id in self._BOARDS_CACHE: + continue + _append_board(_id, join(boards_dir, item)) else: if id_ not in self._BOARDS_CACHE: - self._BOARDS_CACHE[id_] = PlatformBoardConfig( - join(self.get_dir(), "boards", "%s.json" % id_) - ) + for boards_dir in bdirs: + manifest_path = join(bdirs, "%s.json" % id_) + if not isfile(manifest_path): + continue + _append_board(id_, manifest_path) + if id_ not in self._BOARDS_CACHE: + raise exception.UnknownBoard(id_) return self._BOARDS_CACHE[id_] if id_ else self._BOARDS_CACHE def board_config(self, id_): @@ -472,10 +484,11 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): class PlatformBoardConfig(object): def __init__(self, manifest_path): - if not isfile(manifest_path): - raise exception.UnknownBoard(basename(manifest_path[:-5])) + self._id = basename(manifest_path)[:-5] + assert isfile(manifest_path) self.manifest_path = manifest_path self._manifest = util.load_json(manifest_path) + assert set(["name", "url", "vendor"]) <= set(self._manifest.keys()) def get(self, path, default=None): try: @@ -496,5 +509,24 @@ class PlatformBoardConfig(object): except KeyError: return False - def get_manifest(self): + @property + def id_(self): + return self._id + + @property + def manifest(self): return self._manifest + + def get_brief_data(self): + return { + "id": self.id_, + "name": self._manifest['name'], + "platform": self._manifest.get("platform"), + "mcu": self._manifest.get("build", {}).get("mcu", "").upper(), + "fcpu": int(self._manifest.get("build", {}).get("f_cpu", "")[:-1]), + "ram": self._manifest.get("upload", {}).get("maximum_ram_size", 0), + "rom": self._manifest.get("upload", {}).get("maximum_size", 0), + "frameworks": self._manifest.get("frameworks"), + "vendor": self._manifest['vendor'], + "url": self._manifest['url'] + } From e892473af7f522422386b97825484dec9843f8d3 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 8 Jun 2016 13:47:03 +0300 Subject: [PATCH 017/284] Refactor AutodetectUploadPort --- platformio/builder/tools/pioupload.py | 44 ++++++++++++++++----------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/platformio/builder/tools/pioupload.py b/platformio/builder/tools/pioupload.py index ebb13fb6..e3ca5ac9 100644 --- a/platformio/builder/tools/pioupload.py +++ b/platformio/builder/tools/pioupload.py @@ -79,17 +79,36 @@ def WaitForNewSerialPort(env, before): def AutodetectUploadPort(env): - if "UPLOAD_PORT" in env: - return - if env.subst("$FRAMEWORK") == "mbed": + def _look_for_mbed_disk(): msdlabels = ("mbed", "nucleo", "frdm") for item in get_logicaldisks(): if (not item['name'] or not any([l in item['name'].lower() for l in msdlabels])): continue - env.Replace(UPLOAD_PORT=item['disk']) - break + return item['disk'] + return None + + def _look_for_serial_port(): + port = None + board_hwids = [] + if "BOARD" in env and "build.hwids" in env.BoardConfig(): + board_hwids = env.BoardConfig().get("build.hwids") + for item in get_serialports(): + if "VID:PID" not in item['hwid']: + continue + 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 + return port + + if "UPLOAD_PORT" in env: + return + + if env.subst("$FRAMEWORK") == "mbed": + env.Replace(UPLOAD_PORT=_look_for_mbed_disk()) else: if (system() == "Linux" and not isfile("/etc/udev/99-platformio-udev.rules")): @@ -99,20 +118,9 @@ def AutodetectUploadPort(env): "\n https://raw.githubusercontent.com/platformio/platformio" "/develop/scripts/99-platformio-udev.rules\n" ) + env.Replace(UPLOAD_PORT=_look_for_serial_port()) - board_hwids = [] - if "BOARD" in env and "build.hwids" in env.BoardConfig(): - board_hwids = env.BoardConfig().get("build.hwids") - for item in get_serialports(): - if "VID:PID" not in item['hwid']: - continue - env.Replace(UPLOAD_PORT=item['port']) - for hwid in board_hwids: - hwid_str = ("%s:%s" % (hwid[0], hwid[1])).replace("0x", "") - if hwid_str in item['hwid']: - break - - if "UPLOAD_PORT" in env: + if env.subst("$UPLOAD_PORT"): print "Auto-detected UPLOAD_PORT/DISK: %s" % env['UPLOAD_PORT'] else: env.Exit("Error: Please specify `upload_port` for environment or use " From ff3e100b33c0bd6ac5468b3e3540a10ca15b62a3 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 8 Jun 2016 14:00:40 +0300 Subject: [PATCH 018/284] Minor fixes --- docs/userguide/platforms/cmd_install.rst | 2 +- platformio/managers/platform.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/userguide/platforms/cmd_install.rst b/docs/userguide/platforms/cmd_install.rst index 64298e01..c43c3123 100644 --- a/docs/userguide/platforms/cmd_install.rst +++ b/docs/userguide/platforms/cmd_install.rst @@ -48,7 +48,7 @@ Local PlatformIO supports installing development platform from local directory. Here is supported form: -* file:///local/path/to/the/platform/dir +* ``file:///local/path/to/the/platform/dir`` VCS ~~~ diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 649166ef..c27a66ec 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -416,7 +416,9 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): else: if id_ not in self._BOARDS_CACHE: for boards_dir in bdirs: - manifest_path = join(bdirs, "%s.json" % id_) + if not isdir(boards_dir): + continue + manifest_path = join(boards_dir, "%s.json" % id_) if not isfile(manifest_path): continue _append_board(id_, manifest_path) From 41617f5560d08680f960f51f7e93493045dbd914 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 11 Jun 2016 17:37:32 +0300 Subject: [PATCH 019/284] Update documentation for the new decentralised development platforms // Resolve #479 --- docs/platforms/creating_board.rst | 42 ++-- docs/platforms/creating_platform.rst | 283 ++++++++------------------- 2 files changed, 108 insertions(+), 217 deletions(-) diff --git a/docs/platforms/creating_board.rst b/docs/platforms/creating_board.rst index c55b1649..afe0fa78 100644 --- a/docs/platforms/creating_board.rst +++ b/docs/platforms/creating_board.rst @@ -35,29 +35,44 @@ The key fields: * ``build`` data will be used by :ref:`platforms` and :ref:`frameworks` builders * ``frameworks`` is the list with supported :ref:`frameworks` -* ``platform`` main type of :ref:`platforms` +* ``platform`` name of :ref:`platforms` * ``upload`` upload settings which depend on the ``platform`` .. code-block:: json { - "myboard": { - "build": {}, - "frameworks": ["%LIST_WITH_SUPPORTED_FRAMEWORKS%"], - "name": "My test board", - "platform": "%PLATFORM_TYPE_HERE%", - "upload": {}, - "url": "http://example.com", - "vendor": "My Company Ltd." - } + "build": { + "extra_flags": "-DHELLO_PLATFORMIO", + "f_cpu": "16000000L", + "hwids": [ + [ + "0x1234", + "0x0013" + ], + [ + "0x4567", + "0x0013" + ] + ], + "mcu": "%MCU_TYPE_HERE%" + }, + "frameworks": ["%LIST_WITH_SUPPORTED_FRAMEWORKS%"], + "name": "My Test Board", + "upload": { + "maximum_ram_size": 2048, + "maximum_size": 32256 + }, + "url": "http://example.com", + "vendor": "MyCompany" } + Installation ------------ 1. Create ``boards`` directory in :ref:`projectconf_pio_home_dir` if it doesn't exist. -2. Create ``my_own_boards.json`` file and put to ``boards`` directory. +2. Create ``myboard.json`` file and put to ``boards`` directory. 3. Search available boards via :ref:`cmd_boards` command. You should see ``myboard`` board. @@ -68,5 +83,6 @@ Now, you can use ``myboard`` for the :ref:`projectconf_env_board` option in Examples -------- -For the examples, please look into built-in ``*.json`` files with boards -settings: https://github.com/platformio/platformio/tree/develop/platformio/boards. +Please take a look at the source code of +`PlatformIO Development Platforms `_ +and navigate to ``boards`` folder of the repository. diff --git a/docs/platforms/creating_platform.rst b/docs/platforms/creating_platform.rst index df7e803c..316316bb 100644 --- a/docs/platforms/creating_platform.rst +++ b/docs/platforms/creating_platform.rst @@ -14,7 +14,7 @@ Custom Platform =============== -*PlatformIO* was developed like a tool which would build the same source code +*PlatformIO* was developed like a tool that may build the same source code for the different development platforms via single command :ref:`cmd_run` without any dependent software or requirements. @@ -32,7 +32,7 @@ different/own build scripts, uploader and etc. **Step-by-Step Manual** -1. Chose :ref:`platform_creating_packages` for platform +1. Choose :ref:`platform_creating_packages` for platform 2. Create :ref:`platform_creating_manifest_file` 3. Create :ref:`platform_creating_build_script` 4. Finish with the :ref:`platform_creating_installation`. @@ -184,89 +184,82 @@ Packages .. _platform_creating_manifest_file: -Manifest File -------------- +Manifest File ``platform.json`` +------------------------------- -A platform manifest file is a `Python `_ script with the -next requirements: +.. code-block:: json -1. The file should have ``.py`` extension -2. The **name of the file** is the **platform name** (lowercase) -3. The source code of this file should contain a ``class`` which describes your - own platform. The name of the ``class`` should start with your - **platform name** (the first letter should be capitalized) + ``Platform`` - ending. This ``class`` should be derived from *PlatformIO* ``BasePlatform`` - class. - -.. warning:: - If you are new to *Python* language, please read: - - * `Style Guide for Python Code `_. - * A hash sign (#) that is not inside a string literal begins a comment. - All characters after the # and up to the physical line end are part - of the comment and the *Python* interpreter ignores them. - -Example of the **test** platform (``test.py``): - -.. code-block:: python - - import os - - from platformio.platforms.base import BasePlatform - - class TestPlatform(BasePlatform): - # This is a description of your platform. - # Platformio uses it for the `platformio search / list` commands - """ - My Test platform - test.py - """ - - PACKAGES = { - - "toolchain-foo": { - - # alias is used for quick access to package. - # For example, - # `> platformio install test --without-package=toolchain` - "alias": "toolchain", - - # Flag which allows PlatformIO to install this package by - # default via `> platformio install test` command - "default": True - }, - - "tool-bar": { - "alias": "uploader", - "default": True - }, - - "framework-baz": { - "default": True + { + "name": "myplatform", + "title": "My Platform", + "description": "My custom development platform", + "url": "http://example.com", + "homepage": "http://platformio.org/platforms/myplatform", + "license": { + "type": "Apache-2.0", + "url": "http://opensource.org/licenses/apache2.0.php" + }, + "engines": { + "platformio": "~3.0.0", + "scons": ">=2.3.0,<2.6.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/platformio/platform-myplatform.git" + }, + "version": "0.0.0", + "packageRepositories": [ + "https://dl.bintray.com/platformio/dl-packages/manifest.json", + "https://sourceforge.net/projects/platformio-storage/files/packages/manifest.json/download", + "http://dl.platformio.org/packages/manifest.json", + { + "framework-%FRAMEWORK_NAME_1%": [ + { + "url": "http://dl.example.com/packages/framework-%FRAMEWORK_NAME_1%-1.10607.0.tar.gz", + "sha1": "adce2cd30a830d71cb6572575bf08461b7b73c07", + "version": "1.10607.0", + "system": "*" } + ] } - - def get_build_script(self): - """ Returns a path to build script """ - - # You can return static path - #return "/path/to/test-builder.py" - - # or detect dynamically if `test-builder.py` is located in the same - # folder with `test.py` - return os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "test-builder.py" - ) + ], + "frameworks": { + "%FRAMEWORK_NAME_1%": { + "package": "framework-%FRAMEWORK_NAME_1%", + "script": "builder/frameworks/%FRAMEWORK_NAME_1%.py" + }, + "%FRAMEWORK_NAME_N%": { + "package": "framework-%FRAMEWORK_NAME_N%", + "script": "builder/frameworks/%FRAMEWORK_NAME_N%.py" + } + }, + "packages": { + "toolchain-gccarmnoneeabi": { + "type": "toolchain", + "version": ">=1.40803.0,<1.40805.0" + }, + "framework-%FRAMEWORK_NAME_1%": { + "type": "framework", + "optional": true, + "version": "~1.10607.0" + }, + "framework-%FRAMEWORK_NAME_N%": { + "type": "framework", + "optional": true, + "version": "~1.117.0" + } + } + } .. _platform_creating_build_script: -Build Script ------------- +Build Script ``main.py`` +------------------------ Platform's build script is based on a next-generation build tool named `SCons `_. PlatformIO has own built-in firmware builder -``env.BuildProgram`` with the nested libraries search. Please look into a -base template of ``test-builder.py``. +``env.BuildProgram`` with the deep libraries search. Please look into a +base template of ``main.py``. .. code-block:: python @@ -344,15 +337,6 @@ base template of ``test-builder.py``. Default(target_bin) -Please look into the examples with built-in scripts for the popular -platforms: - -* `baseavr.py `_ -* `basearm.py `_ -* `atmelavr.py `_ -* `timsp430.py `_ -* `ststm32.py `_ - .. _platform_creating_installation: Installation @@ -360,126 +344,17 @@ Installation 1. Create ``platforms`` directory in :ref:`projectconf_pio_home_dir` if it doesn't exist. -2. Copy ``test.py`` and ``test-builder.py`` files to ``platforms`` directory. -3. Search available platforms via :ref:`cmd_platform_search` command. You should see - ``test`` platform. -4. Install ``test`` platform via :ref:`cmd_platform_install` command. +2. Create ``myplatform`` directory in ``platforms`` +3. Copy ``platform.json`` and ``builder/main.py`` files to ``myplatform`` directory. +4. Search available platforms via :ref:`cmd_platform_search` command. You + should see ``myplatform`` platform. +5. Install ``myplatform`` platform via :ref:`cmd_platform_install` command. -Now, you can use ``test`` for the :ref:`projectconf_env_platform` option in -:ref:`projectconf`. +Now, you can use ``myplatform`` for the :ref:`projectconf_env_platform` +option in :ref:`projectconf`. -Example -------- - -Let's use the real example which was requested by our user in `issue 175 `_. Need to add support for uploading firmware using GDB to -:ref:`platform_ststm32`. - -First of all, need to create new folder ``platforms`` in :ref:`projectconf_pio_home_dir` -and copy there two files: - -1. Platform manifest file ``ststm32gdb.py`` with the next content: - -.. code-block:: python - - import os - - from platformio.platforms.ststm32 import Ststm32Platform - - - class Ststm32gdbPlatform(Ststm32Platform): - - """ - ST STM32 using GDB as uploader - - http://www.st.com/web/en/catalog/mmc/FM141/SC1169?sc=stm32 - """ - - def get_build_script(self): - - return os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "ststm32gdb-builder.py" - ) - -2. Build script file ``ststm32gdb-builder.py`` with the next content: - -.. code-block:: python - - """ - Builder for ST STM32 Series ARM microcontrollers with GDB upload. - """ - - from os.path import join - - from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Default, - DefaultEnvironment, SConscript) - - - env = DefaultEnvironment() - - SConscript(env.subst(join("$PIOBUILDER_DIR", "scripts", "basearm.py"))) - - env.Replace( - UPLOADER=join( - "$PIOPACKAGES_DIR", "toolchain-gccarmnoneeabi", - "bin", "arm-none-eabi-gdb" - ), - UPLOADERFLAGS=[ - join("$BUILD_DIR", "firmware.elf"), - "-batch", - "-x", join("$PROJECT_DIR", "upload.gdb") - ], - - UPLOADCMD="$UPLOADER $UPLOADERFLAGS" - ) - - env.Append( - CPPDEFINES=[ - "${BOARD_OPTIONS['build']['variant'].upper()}" - ], - - LINKFLAGS=[ - "-nostartfiles", - "-nostdlib" - ] - ) - - # - # Target: Build executable and linkable firmware - # - - target_elf = env.BuildProgram() - - # - # Target: Build the .bin file - # - - if "uploadlazy" in COMMAND_LINE_TARGETS: - target_firm = join("$BUILD_DIR", "firmware.bin") - else: - target_firm = env.ElfToBin(join("$BUILD_DIR", "firmware"), target_elf) - - # - # Target: Print binary size - # - - target_size = env.Alias("size", target_elf, "$SIZEPRINTCMD") - AlwaysBuild(target_size) - - # - # Target: Upload by default .bin file - # - - upload = env.Alias( - ["upload", "uploadlazy"], target_firm, "$UPLOADCMD") - AlwaysBuild(upload) - - # - # Target: Define targets - # - - Default([target_firm, target_size]) - -Now, we should see ``ststm32gdb`` platform using :ref:`cmd_platform_search` command output -and can install it via :ref:`platformio platform install ststm32gdb ` command. +Examples +-------- +Please take a look at the source code of +`PlatformIO Development Platforms `_. From 4383f81c0fa0d95e65f4a3d62f07e9a24fb076cd Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 14 Jun 2016 20:47:25 +0300 Subject: [PATCH 020/284] Restore PIO macros if it was deleted by framework --- platformio/builder/tools/platformio.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index f43a0dc8..5745a51f 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -35,10 +35,13 @@ SRC_DEFAULT_FILTER = " ".join([ def BuildProgram(env): - env.Append( - CPPDEFINES=["PLATFORMIO={0:02d}{1:02d}{2:02d}".format( - *pioversion_to_intstr())], - ) + def _append_pio_macros(): + env.AppendUnique( + CPPDEFINES=["PLATFORMIO={0:02d}{1:02d}{2:02d}".format( + *pioversion_to_intstr())], + ) + + _append_pio_macros() # fix ASM handling under non-casitive OS if not case_sensitive_suffixes(".s", ".S"): @@ -59,6 +62,9 @@ def BuildProgram(env): env.BuildFrameworks([ f.lower().strip() for f in env.get("FRAMEWORK", "").split(",")]) + # restore PIO macros if it was deleted by framework + _append_pio_macros() + # build dependent libs deplibs = env.BuildDependentLibraries("$PROJECTSRC_DIR") From f5727af40e040eb30aff8b5dcfb567ffd08cef40 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 15 Jun 2016 13:25:35 +0300 Subject: [PATCH 021/284] Fix upload size checker --- platformio/builder/tools/pioupload.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/builder/tools/pioupload.py b/platformio/builder/tools/pioupload.py index e22a724f..5c7730ac 100644 --- a/platformio/builder/tools/pioupload.py +++ b/platformio/builder/tools/pioupload.py @@ -157,7 +157,7 @@ def CheckUploadSize(_, target, source, env): # pylint: disable=W0613,W0621 print "Check program size..." sysenv = environ.copy() sysenv['PATH'] = str(env['ENV']['PATH']) - cmd = [env.subst("$SIZETOOL"), "-B", str(source[0])] + cmd = [env.subst("$SIZETOOL"), "-B", str(target[0])] result = util.exec_command(cmd, env=sysenv) if result['returncode'] != 0: return From bb22a1297bc2e4c3131530f15a2b4b3914836560 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 15 Jun 2016 14:10:42 +0300 Subject: [PATCH 022/284] Unit Testing for Embedded // Resolve #408 --- HISTORY.rst | 3 +- docs/envvars.rst | 4 + docs/index.rst | 1 + docs/platforms/unit_testing.rst | 390 ++++++++++++++++++++++++++++ docs/projectconf.rst | 15 +- docs/quickstart.rst | 3 +- docs/userguide/cmd_run.rst | 4 +- docs/userguide/cmd_test.rst | 68 +++++ docs/userguide/index.rst | 1 + platformio/__init__.py | 2 +- platformio/builder/main.py | 1 + platformio/builder/tools/piotest.py | 21 +- platformio/commands/run.py | 54 ++-- platformio/commands/test.py | 188 ++++++++++++++ platformio/exception.py | 7 + 15 files changed, 725 insertions(+), 37 deletions(-) create mode 100644 docs/platforms/unit_testing.rst create mode 100644 docs/userguide/cmd_test.rst create mode 100644 platformio/commands/test.py diff --git a/HISTORY.rst b/HISTORY.rst index d9ae5b10..e9b1ff11 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -10,7 +10,8 @@ PlatformIO 3.0 * Decentralized architecture for development platforms: "platform.json", semantic versioning, package dependencies, embedded board configs, isolated build scripts - (`issue #479 `_) +* Unit Testing for Embedded (`docs `__) + (`issue #408 `_) PlatformIO 2.0 -------------- diff --git a/docs/envvars.rst b/docs/envvars.rst index e9316c64..d0165b05 100644 --- a/docs/envvars.rst +++ b/docs/envvars.rst @@ -69,6 +69,10 @@ Allows to override :ref:`projectconf` option :ref:`projectconf_pio_envs_dir`. Allows to override :ref:`projectconf` option :ref:`projectconf_pio_data_dir`. +.. envvar:: PLATFORMIO_TEST_DIR + +Allows to override :ref:`projectconf` option :ref:`projectconf_pio_test_dir`. + Building -------- diff --git a/docs/index.rst b/docs/index.rst index ce0d088c..2db1a873 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -111,6 +111,7 @@ Contents platforms/embedded_boards frameworks/index platforms/custom_platform_and_board + platforms/unit_testing .. toctree:: :caption: Library Manager diff --git a/docs/platforms/unit_testing.rst b/docs/platforms/unit_testing.rst new file mode 100644 index 00000000..86c8eb63 --- /dev/null +++ b/docs/platforms/unit_testing.rst @@ -0,0 +1,390 @@ +.. Copyright 2014-present Ivan Kravets + 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. + +.. _unit_testing: + +Unit Testing +============ + +`Unit Testing (wiki) `_ +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. + +PlatformIO Test System is very interesting for embedded development. +It allows you to write tests locally and run them directly on the target +device (hardware unit testing). Also, you will be able to run the same tests +on the different target devices (:ref:`embedded_boards`). + +PlatformIO Test System consists of: + +* Project builder +* Test builder +* Firmware uploader +* Test processor + +.. contents:: + +.. _unit_testing_design: + +Design +------ + +PlatformIO Test System design is based on a few isolated components: + +1. **Main program**. Contains the independent modules, procedures, + functions or methods that will be the target candidates (TC) for testing +2. **Unit test**. This a small independent program that is intended to + re-use TC from the main program and apply tests for them. +3. **Test processor**. The set of approaches and tools that will be used + to apply test for the environments from :ref:`projectconf`. + +Workflow +-------- + +1. Create PlatformIO project using :ref:`cmd_init` command +2. Place source code of main program to ``src`` directory +3. Wrap ``main()`` or ``setup()/loop()`` methods of main program in ``UNIT_TEST`` + guard: + + .. code-block:: c + + /** + * Arduino Wiring-based Framework + */ + #ifndef UNIT_TEST + void setup () { + // some code... + } + + void loop () { + // some code... + } + #endif + + /** + * Generic C/C++ + */ + #ifndef UNIT_TEST + int main() { + // setup code... + + while (1) { + // loop code... + } + } + #endif + +4. Create ``test`` directory in the root of project. See :ref:`projectconf_pio_test_dir` +5. Write test using :ref:`unit_testing_api`. The each test is a small + independent program with own ``main()`` or ``setup()/loop()`` methods. Also, + test should start from ``UNITY_BEGIN()`` and finish with ``UNITY_END()`` +6. Place test to ``test`` directory. If you have more than one test, split them + into sub-folders. For example, ``test/test_1/*.[c,cpp,h]``, + ``test_N/*.[c,cpp,h]``, etc. If no such directory in ``test`` folder, then + PlatformIO Test System will treat the source code of ``test`` folder + as SINGLE test. +7. Run tests using :ref:`cmd_test` command. + +.. _unit_testing_api: + +Test API +-------- + +The summary of `Unity Test API `_: + +* `Running Tests `_ + + - ``RUN_TEST(func, linenum)`` + +* `Ignoring Tests `_ + + - ``TEST_IGNORE()`` + - ``TEST_IGNORE_MESSAGE (message)`` + +* `Aborting Tests `_ + + - ``TEST_PROTECT()`` + - ``TEST_ABORT()`` + +* `Basic Validity Tests `_ + + - ``TEST_ASSERT_TRUE(condition)`` + - ``TEST_ASSERT_FALSE(condition)`` + - ``TEST_ASSERT(condition)`` + - ``TEST_ASSERT_UNLESS(condition)`` + - ``TEST_FAIL()`` + - ``TEST_FAIL_MESSAGE(message)`` + +* `Numerical Assertions: Integers `_ + + - ``TEST_ASSERT_EQUAL_INT(expected, actual)`` + - ``TEST_ASSERT_EQUAL_INT8(expected, actual)`` + - ``TEST_ASSERT_EQUAL_INT16(expected, actual)`` + - ``TEST_ASSERT_EQUAL_INT32(expected, actual)`` + - ``TEST_ASSERT_EQUAL_INT64(expected, actual)`` + + - ``TEST_ASSERT_EQUAL_UINT(expected, actual)`` + - ``TEST_ASSERT_EQUAL_UINT8(expected, actual)`` + - ``TEST_ASSERT_EQUAL_UINT16(expected, actual)`` + - ``TEST_ASSERT_EQUAL_UINT32(expected, actual)`` + - ``TEST_ASSERT_EQUAL_UINT64(expected, actual)`` + + - ``TEST_ASSERT_EQUAL_HEX(expected, actual)`` + - ``TEST_ASSERT_EQUAL_HEX8(expected, actual)`` + - ``TEST_ASSERT_EQUAL_HEX16(expected, actual)`` + - ``TEST_ASSERT_EQUAL_HEX32(expected, actual)`` + - ``TEST_ASSERT_EQUAL_HEX64(expected, actual)`` + - ``TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, elements)`` + + - ``TEST_ASSERT_EQUAL(expected, actual)`` + - ``TEST_ASSERT_INT_WITHIN(delta, expected, actual)`` + +* `Numerical Assertions: Bitwise `_ + + - ``TEST_ASSERT_BITS(mask, expected, actual)`` + - ``TEST_ASSERT_BITS_HIGH(mask, actual)`` + - ``TEST_ASSERT_BITS_LOW(mask, actual)`` + - ``TEST_ASSERT_BIT_HIGH(mask, actual)`` + - ``TEST_ASSERT_BIT_LOW(mask, actual)`` + +* `Numerical Assertions: Floats `_ + + - ``TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual)`` + - ``TEST_ASSERT_EQUAL_FLOAT(expected, actual)`` + - ``TEST_ASSERT_EQUAL_DOUBLE(expected, actual)`` + +* `String Assertions `_ + + - ``TEST_ASSERT_EQUAL_STRING(expected, actual)`` + - ``TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len)`` + - ``TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message)`` + - ``TEST_ASSERT_EQUAL_STRING_LEN_MESSAGE(expected, actual, len, message)`` + +* `Pointer Assertions `_ + + - ``TEST_ASSERT_NULL(pointer)`` + - ``TEST_ASSERT_NOT_NULL(pointer)`` + +* `Memory Assertions `_ + + - ``TEST_ASSERT_EQUAL_MEMORY(expected, actual, len)`` + +Example +------- + +1. Please follow to :ref:`quickstart` and create "Blink Project". According + to the Unit Testing :ref:`unit_testing_design` it is the **Main program** +2. Create ``test`` directory in that project (on the same level as ``src``) + and place ``test_main.cpp`` file to it (the source code is located below) +3. Wrap ``setup()`` and ``loop()`` methods of main program in ``UNIT_TEST`` + guard +4. Run tests using :ref:`cmd_test` command. + +Project structure +~~~~~~~~~~~~~~~~~ + +.. code-block:: bash + + project_dir + ├── lib + │   └── readme.txt + ├── platformio.ini + ├── src + │   └── main.cpp + └── test + └── test_main.cpp + +Source files +~~~~~~~~~~~~ + +* ``platformio.ini`` + + .. code-block:: ini + + ; Project Configuration File + ; Docs: http://docs.platformio.org/en/latest/projectconf.html + + [env:uno] + platform = atmelavr + framework = arduino + board = uno + + [env:nodemcu] + platform = espressif + framework = arduino + board = nodemcu + + [env:teensy31] + platform = teensy + framework = arduino + board = teensy31 + +* ``src/main.cpp`` + + .. code-block:: cpp + + /* + * Blink + * Turns on an LED on for one second, + * then off for one second, repeatedly. + */ + + #include "Arduino.h" + + #ifndef UNIT_TEST // IMPORTANT LINE! + + void setup() + { + // initialize LED digital pin as an output. + pinMode(LED_BUILTIN, OUTPUT); + } + + void loop() + { + // turn the LED on (HIGH is the voltage level) + digitalWrite(LED_BUILTIN, HIGH); + // wait for a second + delay(1000); + // turn the LED off by making the voltage LOW + digitalWrite(LED_BUILTIN, LOW); + // wait for a second + delay(1000); + } + + #endif // IMPORTANT LINE! + +* ``test/test_main.cpp`` + + .. code-block:: cpp + + #include + #include + + #ifdef UNIT_TEST + + // void setUp(void) { + // // set stuff up here + // } + + // void tearDown(void) { + // // clean stuff up here + // } + + void test_led_builtin_pin_number(void) { + TEST_ASSERT_EQUAL(LED_BUILTIN, 13); + } + + void test_led_state_high(void) { + digitalWrite(LED_BUILTIN, HIGH); + TEST_ASSERT_EQUAL(digitalRead(LED_BUILTIN), HIGH); + } + + void test_led_state_low(void) { + digitalWrite(LED_BUILTIN, LOW); + TEST_ASSERT_EQUAL(digitalRead(LED_BUILTIN), LOW); + } + + void setup() { + UNITY_BEGIN(); // IMPORTANT LINE! + RUN_TEST(test_led_builtin_pin_number); + + pinMode(LED_BUILTIN, OUTPUT); + } + + uint8_t i = 0; + uint8_t max_blinks = 5; + + void loop() { + if (i < max_blinks) + { + RUN_TEST(test_led_state_high); + delay(500); + RUN_TEST(test_led_state_low); + delay(500); + } + else if (i == max_blinks) { + UNITY_END(); // IMPORTANT LINE! + } + i++; + } + + #endif + +Test results +~~~~~~~~~~~~ + +.. code-block:: bash + + > platformio test --environment uno + Collected 1 items + + ========================= [test::*] Building... (1/3) ============================== + + [Wed Jun 15 00:27:42 2016] Processing uno (platform: atmelavr, board: uno, framework: arduino) + -------------------------------------------------------------------------------------------------------------------------------------------------------------------- + avr-g++ -o .pioenvs/uno/test/test_main.o -c -fno-exceptions -fno-threadsafe-statics -std=gnu++11 -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DPLATFORMIO=030000 -DARDUINO_ARCH_AVR -DARDUINO_AVR_UNO -DARDUINO=10608 -DUNIT_TEST -DUNITY_INCLUDE_CONFIG_H -I.pioenvs/uno/FrameworkArduino -I.pioenvs/uno/FrameworkArduinoVariant -Isrc -I.pioenvs/uno/UnityTestLib test/test_main.cpp + avr-g++ -o .pioenvs/uno/firmware.elf -Os -mmcu=atmega328p -Wl,--gc-sections,--relax .pioenvs/uno/src/main.o .pioenvs/uno/test/output_export.o .pioenvs/uno/test/test_main.o -L.pioenvs/uno -Wl,--start-group .pioenvs/uno/libUnityTestLib.a .pioenvs/uno/libFrameworkArduinoVariant.a .pioenvs/uno/libFrameworkArduino.a -lm -Wl,--end-group + avr-objcopy -O ihex -R .eeprom .pioenvs/uno/firmware.elf .pioenvs/uno/firmware.hex + avr-size --mcu=atmega328p -C -d .pioenvs/uno/firmware.elf + AVR Memory Usage + ---------------- + Device: atmega328p + + Program: 4702 bytes (14.3% Full) + (.text + .data + .bootloader) + + Data: 460 bytes (22.5% Full) + (.data + .bss + .noinit) + + + ========================= [test::*] Uploading... (2/3) ============================== + + [Wed Jun 15 00:27:43 2016] Processing uno (platform: atmelavr, board: uno, framework: arduino) + -------------------------------------------------------------------------------------------------------------------------------------------------------------------- + avr-g++ -o .pioenvs/uno/firmware.elf -Os -mmcu=atmega328p -Wl,--gc-sections,--relax .pioenvs/uno/src/main.o .pioenvs/uno/test/output_export.o .pioenvs/uno/test/test_main.o -L.pioenvs/uno -Wl,--start-group .pioenvs/uno/libUnityTestLib.a .pioenvs/uno/libFrameworkArduinoVariant.a .pioenvs/uno/libFrameworkArduino.a -lm -Wl,--end-group + MethodWrapper([".pioenvs/uno/firmware.elf"], [".pioenvs/uno/src/main.o", ".pioenvs/uno/test/output_export.o", ".pioenvs/uno/test/test_main.o"]) + Check program size... + text data bss dec hex filename + 4464 238 222 4924 133c .pioenvs/uno/firmware.elf + BeforeUpload(["upload"], [".pioenvs/uno/firmware.hex"]) + Looking for upload port/disk... + avr-size --mcu=atmega328p -C -d .pioenvs/uno/firmware.elf + + Auto-detected: /dev/cu.usbmodemFD131 + avrdude -v -p atmega328p -C "/Users/ikravets/.platformio/packages/tool-avrdude/avrdude.conf" -c arduino -b 115200 -P "/dev/cu.usbmodemFD131" -D -U flash:w:.pioenvs/uno/firmware.hex:i + + [...] + + avrdude done. Thank you. + + ========================= [test::*] Testing... (3/3) ========================= + + If you do not see any output for the first 10 secs, please reset board (press reset button) + + test/test_main.cpp:30:test_led_builtin_pin_number PASSED + test/test_main.cpp:41:test_led_state_high PASSED + test/test_main.cpp:43:test_led_state_low PASSED + test/test_main.cpp:41:test_led_state_high PASSED + test/test_main.cpp:43:test_led_state_low PASSED + test/test_main.cpp:41:test_led_state_high PASSED + test/test_main.cpp:43:test_led_state_low PASSED + test/test_main.cpp:41:test_led_state_high PASSED + test/test_main.cpp:43:test_led_state_low PASSED + test/test_main.cpp:41:test_led_state_high PASSED + test/test_main.cpp:43:test_led_state_low PASSED + ----------------------- + 11 Tests 0 Failures 0 Ignored + + ========================= [TEST SUMMARY] ===================================== + test:*/env:uno PASSED + ========================= [PASSED] Took 13.35 seconds ======================== diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 34685842..8572d229 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -113,7 +113,7 @@ This option can be overridden by global environment variable :envvar:`PLATFORMIO_ENVS_DIR`. .. note:: - If you have any problems with building your Project environmets which + If you have any problems with building your Project environments which are defined in :ref:`projectconf`, then **TRY TO DELETE** this folder. In this situation you will remove all cached files without any risk. @@ -130,6 +130,19 @@ project. This option can be overridden by global environment variable :envvar:`PLATFORMIO_DATA_DIR`. +.. _projectconf_pio_test_dir: + +``test_dir`` +^^^^^^^^^^^^ + +Directory for :ref:`unit_testing`. + +A default value is ``test`` which means that folder is located in the root of +project. + +This option can be overridden by global environment variable +:envvar:`PLATFORMIO_TEST_DIR`. + .. _projectconf_pio_env_default: ``env_default`` diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 3b2d0c24..0ed47471 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -82,11 +82,10 @@ According to the table above the ID/TYPE for Teensy 3.1 is ``teensy31``. Also, the ID for Arduino UNO is ``uno`` and for NodeMCU 1.0 (ESP-12E Module) is ``nodemcuv2``. - Initialize Project ------------------ -PlatformIO ecosystem contains huge database with pre-configured settings for the +PlatformIO ecosystem contains big database with pre-configured settings for the most popular embedded boards. It helps you to forget about installing toolchains, writing build scripts or configuring uploading process. Just tell PlatformIO the Board ID and you will receive full working project with diff --git a/docs/userguide/cmd_run.rst b/docs/userguide/cmd_run.rst index 6034cb04..383970c1 100644 --- a/docs/userguide/cmd_run.rst +++ b/docs/userguide/cmd_run.rst @@ -64,7 +64,9 @@ Pre-built targets: --upload-port Upload port of embedded board. To print all available ports use -:ref:`cmd_serialports` command +:ref:`cmd_serialports` command. + +If upload port is not specified, PlatformIO will try to detect it automatically. .. option:: -d, --project-dir diff --git a/docs/userguide/cmd_test.rst b/docs/userguide/cmd_test.rst new file mode 100644 index 00000000..8d163db8 --- /dev/null +++ b/docs/userguide/cmd_test.rst @@ -0,0 +1,68 @@ +.. Copyright 2014-2016 Ivan Kravets + 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. + +.. _cmd_test: + +platformio test +=============== + +.. contents:: + +Usage +----- + +.. code-block:: bash + + platformio test [OPTIONS] + +Description +----------- + +Run tests from PlatformIO based project. More details about PlatformIO +:ref:`unit_testing`. + +This command allows you to apply the tests for the environments specified +in :ref:`projectconf`. + +Options +------- + +.. program:: platformio test + +.. option:: + -e, --environment + +Process specified environments. More details :option:`platformio run --environment` + +.. option:: + --upload-port + +Upload port of embedded board. To print all available ports use +:ref:`cmd_serialports` command. + +If upload port is not specified, PlatformIO will try to detect it automatically. + +.. option:: + -d, --project-dir + +Specify the path to project directory. By default, ``--project-dir`` is equal +to current working directory (``CWD``). + +.. option:: + -v, --verbose + +Shows details about the results of processing environments. More details +:option:`platformio run --verbose` + +Examples +-------- + +For the examples please follow to :ref:`unit_testing` page. diff --git a/docs/userguide/index.rst b/docs/userguide/index.rst index 1d9851ab..856ebda2 100644 --- a/docs/userguide/index.rst +++ b/docs/userguide/index.rst @@ -66,5 +66,6 @@ Commands cmd_run cmd_serialports cmd_settings + cmd_test cmd_update cmd_upgrade diff --git a/platformio/__init__.py b/platformio/__init__.py index fe5bd51c..1e9074a2 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev0") +VERSION = (3, 0, "0.dev1") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/main.py b/platformio/builder/main.py index faaa1e1a..ab957d57 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -32,6 +32,7 @@ commonvars.AddVariables( ("BUILD_SCRIPT",), ("EXTRA_SCRIPT",), ("PIOENV",), + ("PIOTEST",), ("PLATFORM",), # options diff --git a/platformio/builder/tools/piotest.py b/platformio/builder/tools/piotest.py index c8044d93..8f97a9cc 100644 --- a/platformio/builder/tools/piotest.py +++ b/platformio/builder/tools/piotest.py @@ -16,10 +16,10 @@ from __future__ import absolute_import import atexit from os import remove -from os.path import isdir, isfile, join +from os.path import isdir, isfile, join, sep from string import Template -FRAMEWORKS_PARAMETERS = { +FRAMEWORK_PARAMETERS = { "arduino": { "framework": "Arduino.h", "serial_obj": "", @@ -50,9 +50,6 @@ FRAMEWORKS_PARAMETERS = { def ProcessTest(env): - - test_dir = env.subst("$PROJECTTEST_DIR") - env.Append( CPPDEFINES=[ "UNIT_TEST", @@ -63,19 +60,23 @@ def ProcessTest(env): join("$BUILD_DIR", "UnityTestLib") ] ) - unitylib = env.BuildLibrary( join("$BUILD_DIR", "UnityTestLib"), env.DevPlatform().get_package_dir("tool-unity") ) - env.Prepend(LIBS=[unitylib]) + test_dir = env.subst("$PROJECTTEST_DIR") env.GenerateOutputReplacement(test_dir) + src_filter = None + if "PIOTEST" in env: + src_filter = "+" + src_filter += " +<%s%s>" % (env['PIOTEST'], sep) return env.LookupSources( - "$BUILDTEST_DIR", test_dir, duplicate=False) + "$BUILDTEST_DIR", test_dir, duplicate=False, src_filter=src_filter + ) def GenerateOutputReplacement(env, destination_dir): @@ -122,12 +123,12 @@ void output_complete(void) "Please remove it manually." % file_) framework = env.subst("$FRAMEWORK").lower() - if framework not in FRAMEWORKS_PARAMETERS.keys(): + if framework not in FRAMEWORK_PARAMETERS.keys(): env.Exit( "Error: %s framework doesn't support testing feature!" % framework) else: data = Template(TEMPLATECPP).substitute( - FRAMEWORKS_PARAMETERS[framework]) + FRAMEWORK_PARAMETERS[framework]) tmp_file = join(destination_dir, "output_export.cpp") with open(tmp_file, "w") as f: diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 76f375a5..fca60880 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -41,19 +41,8 @@ from platformio.managers.platform import PlatformFactory @click.pass_context def cli(ctx, environment, target, upload_port, # pylint: disable=R0913,R0914 project_dir, verbose, disable_auto_clean): + assert check_project_envs(project_dir, environment) with util.cd(project_dir): - config = util.get_project_config() - - if not config.sections(): - raise exception.ProjectEnvsNotAvailable() - - known = set([s[4:] for s in config.sections() - if s.startswith("env:")]) - unknown = set(environment) - known - if unknown: - raise exception.UnknownEnvNames( - ", ".join(unknown), ", ".join(known)) - # clean obsolete .pioenvs dir if not disable_auto_clean: try: @@ -66,6 +55,7 @@ def cli(ctx, environment, target, upload_port, # pylint: disable=R0913,R0914 fg="yellow" ) + config = util.get_project_config() env_default = None if config.has_option("platformio", "env_default"): env_default = [ @@ -94,6 +84,8 @@ def cli(ctx, environment, target, upload_port, # pylint: disable=R0913,R0914 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, verbose) @@ -136,15 +128,12 @@ class EnvironmentProcessor(object): result = self._run() is_error = result['returncode'] != 0 - summary_text = " Took %.2f seconds " % (time() - start_time) - half_line = "=" * ((terminal_width - len(summary_text) - 10) / 2) - click.echo("%s [%s]%s%s" % ( - half_line, - (click.style(" ERROR ", fg="red", bold=True) - if is_error else click.style("SUCCESS", fg="green", bold=True)), - summary_text, - half_line - ), err=is_error) + 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 @@ -254,6 +243,29 @@ def _clean_pioenvs_dir(pioenvs_dir): 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 check_project_envs(project_dir, environments): + with util.cd(project_dir): + config = util.get_project_config() + + 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 = [] for d in (util.get_projectsrc_dir(), util.get_projectlib_dir()): diff --git a/platformio/commands/test.py b/platformio/commands/test.py new file mode 100644 index 00000000..62105c7a --- /dev/null +++ b/platformio/commands/test.py @@ -0,0 +1,188 @@ +# Copyright 2014-present Ivan Kravets +# +# 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 getcwd, listdir +from os.path import isdir, join +from time import sleep, time + +import click +import serial + +from platformio import exception, util +from platformio.commands.run import cli as cmd_run +from platformio.commands.run import check_project_envs, print_header +from platformio.managers.platform import PlatformFactory + + +@click.command("test", short_help="Unit Testing") +@click.option("--environment", "-e", multiple=True, metavar="") +@click.option("--upload-port", metavar="") +@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("--verbose", "-v", count=True, default=3) +@click.pass_context +def cli(ctx, environment, upload_port, # pylint: disable=R0913,R0914 + project_dir, verbose): + assert check_project_envs(project_dir, environment) + with util.cd(project_dir): + test_dir = util.get_projecttest_dir() + if not isdir(test_dir): + raise exception.TestDirEmpty(test_dir) + config = util.get_project_config() + env_names = set( + [s[4:] for s in config.sections() if s.startswith("env:")]) + + test_names = [] + for item in sorted(listdir(test_dir)): + if isdir(join(test_dir, item)): + test_names.append(item) + if not test_names: + test_names = ["*"] + click.echo("Collected %d items" % len(test_names)) + click.echo() + + start_time = time() + results = [] + for testname in test_names: + for envname in env_names: + if environment and envname not in environment: + continue + tp = TestProcessor(ctx, testname, envname, { + "project_config": config, + "project_dir": project_dir, + "upload_port": upload_port, + "verbose": verbose + }) + results.append((tp.process(), testname, envname)) + + click.echo() + print_header("[%s]" % click.style("TEST SUMMARY")) + + passed = True + for result in results: + if not result[0]: + passed = False + click.echo("test:%s/env:%s\t%s" % ( + click.style(result[1], fg="yellow"), + click.style(result[2], fg="cyan"), + click.style("PASSED" if passed else "FAILED", fg="green" + if passed else "red")), err=not passed) + + print_header("[%s] Took %.2f seconds" % ( + (click.style("PASSED", fg="green", bold=True) if passed + else click.style("FAILED", fg="red", bold=True)), + time() - start_time + ), is_error=not passed) + + if not passed: + raise exception.ReturnErrorCode() + + +class TestProcessor(object): + + SERIAL_TIMEOUT = 600 + SERIAL_BAUDRATE = 9600 + + def __init__(self, cmd_ctx, testname, envname, options): + self.cmd_ctx = cmd_ctx + self.cmd_ctx.meta['piotest_processor'] = True + self.test_name = testname + self.env_name = envname + self.options = options + + def process(self): + self._progress("Building... (1/3)") + self._build_or_upload(["test"]) + self._progress("Uploading... (2/3)") + self._build_or_upload(["test", "upload"]) + self._progress("Testing... (3/3)") + sleep(1.0) # wait while board is starting... + return self._run_hardware_test() + + def _progress(self, text, is_error=False): + print_header("[test::%s] %s" % ( + click.style(self.test_name, fg="yellow", bold=True), + text + ), is_error=is_error) + click.echo() + + def _build_or_upload(self, target): + if self.test_name != "*": + self.cmd_ctx.meta['piotest'] = self.test_name + return self.cmd_ctx.invoke( + cmd_run, project_dir=self.options['project_dir'], + upload_port=self.options['upload_port'], + verbose=self.options['verbose'], environment=[self.env_name], + target=target + ) + + def _run_hardware_test(self): + click.echo("If you don't see any output for the first 10 secs, " + "please reset board (press reset button)") + click.echo() + ser = serial.Serial(self.get_serial_port(), self.SERIAL_BAUDRATE, + timeout=self.SERIAL_TIMEOUT) + passed = True + while True: + line = ser.readline().strip() + if not line: + continue + if line.endswith(":PASS"): + click.echo("%s\t%s" % ( + line[:-5], click.style("PASSED", fg="green"))) + elif ":FAIL:" in line: + passed = False + click.secho(line, fg="red") + else: + click.echo(line) + if all([l in line for l in ("Tests", "Failures", "Ignored")]): + break + ser.close() + return passed + + def get_serial_port(self): + config = self.options['project_config'] + envdata = {} + for k, v in config.items("env:" + self.env_name): + envdata[k] = v + + # if upload port is specified manually + if self.options.get("upload_port", envdata.get("upload_port")): + return self.options.get("upload_port", envdata.get("upload_port")) + + platform = envdata['platform'] + version = None + if "@" in platform: + platform, version = platform.rsplit("@", 1) + p = PlatformFactory.newPlatform(platform, version) + bconfig = p.board_config(envdata['board']) + + port = None + board_hwids = [] + if "build.hwids" in bconfig: + board_hwids = bconfig.get("build.hwids") + for item in util.get_serialports(): + if "VID:PID" not in item['hwid']: + continue + 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 + if not port: + raise exception.PlatformioException( + "Please specify `upload_port` for environment or use " + "global `--upload-port` option.") + return port diff --git a/platformio/exception.py b/platformio/exception.py index 3fe366f2..9b117740 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -197,6 +197,13 @@ class CIBuildEnvsEmpty(PlatformioException): "predefined environments using `--project-conf` option" +class TestDirEmpty(PlatformioException): + + MESSAGE = "Test directory '{0}' is empty. More details about Unit "\ + "Testing:\n http://docs.platformio.org/en/latest/platforms/"\ + "unit_testing.html" + + class UpgradeError(PlatformioException): MESSAGE = """{0} From 4b553dd659c625d472d745b7f1fe1cd8b3fb51d0 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 15 Jun 2016 14:13:43 +0300 Subject: [PATCH 023/284] Revert link to the issue --- HISTORY.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.rst b/HISTORY.rst index e9b1ff11..3771ce8a 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -10,6 +10,7 @@ PlatformIO 3.0 * Decentralized architecture for development platforms: "platform.json", semantic versioning, package dependencies, embedded board configs, isolated build scripts + (`issue #479 `_) * Unit Testing for Embedded (`docs `__) (`issue #408 `_) From 1ac1e93bbf2621a7a28da342d944972d6466c0e2 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 15 Jun 2016 14:36:10 +0300 Subject: [PATCH 024/284] Add links to the main command and repo with examples --- docs/platforms/unit_testing.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/platforms/unit_testing.rst b/docs/platforms/unit_testing.rst index 86c8eb63..b37c68aa 100644 --- a/docs/platforms/unit_testing.rst +++ b/docs/platforms/unit_testing.rst @@ -32,6 +32,8 @@ PlatformIO Test System consists of: * Firmware uploader * Test processor +There is special command :ref:`cmd_test` to run tests from PlatformIO Project. + .. contents:: .. _unit_testing_design: @@ -388,3 +390,8 @@ Test results ========================= [TEST SUMMARY] ===================================== test:*/env:uno PASSED ========================= [PASSED] Took 13.35 seconds ======================== + +------- + +For the other examples and source code please follow to +`PlatformIO Unit Testing Examples `_ repository. From 8a67ea9ca284f14889531520f6d394a083afc351 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 16 Jun 2016 00:36:04 +0300 Subject: [PATCH 025/284] Allow to ignore tests using glob patterns // Issue #408 --- docs/platforms/unit_testing.rst | 20 ++++++++--------- docs/userguide/cmd_test.rst | 26 ++++++++++++++++++++++ platformio/commands/test.py | 39 +++++++++++++++++++++++---------- 3 files changed, 63 insertions(+), 22 deletions(-) diff --git a/docs/platforms/unit_testing.rst b/docs/platforms/unit_testing.rst index b37c68aa..19f51e1c 100644 --- a/docs/platforms/unit_testing.rst +++ b/docs/platforms/unit_testing.rst @@ -44,7 +44,7 @@ Design PlatformIO Test System design is based on a few isolated components: 1. **Main program**. Contains the independent modules, procedures, - functions or methods that will be the target candidates (TC) for testing + functions or methods that will be the target candidates (TC) for testing. 2. **Unit test**. This a small independent program that is intended to re-use TC from the main program and apply tests for them. 3. **Test processor**. The set of approaches and tools that will be used @@ -53,8 +53,8 @@ PlatformIO Test System design is based on a few isolated components: Workflow -------- -1. Create PlatformIO project using :ref:`cmd_init` command -2. Place source code of main program to ``src`` directory +1. Create PlatformIO project using :ref:`cmd_init` command. +2. Place source code of main program to ``src`` directory. 3. Wrap ``main()`` or ``setup()/loop()`` methods of main program in ``UNIT_TEST`` guard: @@ -86,10 +86,10 @@ Workflow } #endif -4. Create ``test`` directory in the root of project. See :ref:`projectconf_pio_test_dir` +4. Create ``test`` directory in the root of project. See :ref:`projectconf_pio_test_dir`. 5. Write test using :ref:`unit_testing_api`. The each test is a small independent program with own ``main()`` or ``setup()/loop()`` methods. Also, - test should start from ``UNITY_BEGIN()`` and finish with ``UNITY_END()`` + test should start from ``UNITY_BEGIN()`` and finish with ``UNITY_END()``. 6. Place test to ``test`` directory. If you have more than one test, split them into sub-folders. For example, ``test/test_1/*.[c,cpp,h]``, ``test_N/*.[c,cpp,h]``, etc. If no such directory in ``test`` folder, then @@ -185,11 +185,11 @@ Example ------- 1. Please follow to :ref:`quickstart` and create "Blink Project". According - to the Unit Testing :ref:`unit_testing_design` it is the **Main program** + to the Unit Testing :ref:`unit_testing_design` it is the **Main program**. 2. Create ``test`` directory in that project (on the same level as ``src``) - and place ``test_main.cpp`` file to it (the source code is located below) + and place ``test_main.cpp`` file to it (the source code is located below). 3. Wrap ``setup()`` and ``loop()`` methods of main program in ``UNIT_TEST`` - guard + guard. 4. Run tests using :ref:`cmd_test` command. Project structure @@ -313,11 +313,11 @@ Source files delay(500); RUN_TEST(test_led_state_low); delay(500); + i++; } else if (i == max_blinks) { - UNITY_END(); // IMPORTANT LINE! + UNITY_END(); // stop unit testing } - i++; } #endif diff --git a/docs/userguide/cmd_test.rst b/docs/userguide/cmd_test.rst index 8d163db8..af38f9b7 100644 --- a/docs/userguide/cmd_test.rst +++ b/docs/userguide/cmd_test.rst @@ -42,6 +42,32 @@ Options Process specified environments. More details :option:`platformio run --environment` +.. option:: + -i, --ignore + +Ignore tests where the name matches with specified pattern. More than one +option/pattern is allowed. + +.. list-table:: + :header-rows: 1 + + * - Pattern + - Meaning + + * - ``*`` + - matches everything + + * - ``?`` + - matches any single character + + * - ``[seq]`` + - matches any character in seq + + * - ``[!seq]`` + - matches any character not in seq + +For example, ``platformio test --ignore "mytest*" -i "test[13]"`` + .. option:: --upload-port diff --git a/platformio/commands/test.py b/platformio/commands/test.py index 62105c7a..ee09f8a9 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from fnmatch import fnmatch from os import getcwd, listdir from os.path import isdir, join from time import sleep, time @@ -27,22 +28,21 @@ from platformio.managers.platform import PlatformFactory @click.command("test", short_help="Unit Testing") @click.option("--environment", "-e", multiple=True, metavar="") +@click.option("--ignore", "-i", multiple=True, metavar="") @click.option("--upload-port", metavar="") @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("--verbose", "-v", count=True, default=3) @click.pass_context -def cli(ctx, environment, upload_port, # pylint: disable=R0913,R0914 +def cli(ctx, environment, ignore, upload_port, # pylint: disable=R0913,R0914 project_dir, verbose): assert check_project_envs(project_dir, environment) with util.cd(project_dir): test_dir = util.get_projecttest_dir() if not isdir(test_dir): raise exception.TestDirEmpty(test_dir) - config = util.get_project_config() - env_names = set( - [s[4:] for s in config.sections() if s.startswith("env:")]) + projectconf = util.get_project_config() test_names = [] for item in sorted(listdir(test_dir)): @@ -56,11 +56,20 @@ def cli(ctx, environment, upload_port, # pylint: disable=R0913,R0914 start_time = time() results = [] for testname in test_names: - for envname in env_names: + for envname in projectconf.sections(): + if not envname.startswith("env:"): + continue + envname = envname[4:] if environment and envname not in environment: continue + + # check ignore patterns + if testname != "*" and any([fnmatch(testname, i) for i in ignore]): + results.append((None, testname, envname)) + continue + tp = TestProcessor(ctx, testname, envname, { - "project_config": config, + "project_config": projectconf, "project_dir": project_dir, "upload_port": upload_port, "verbose": verbose @@ -72,13 +81,18 @@ def cli(ctx, environment, upload_port, # pylint: disable=R0913,R0914 passed = True for result in results: - if not result[0]: + status, testname, envname = result + status_str = click.style("PASSED", fg="green") + if status is False: passed = False + status_str = click.style("FAILED", fg="red") + elif status is None: + status_str = click.style("IGNORED", fg="yellow") + click.echo("test:%s/env:%s\t%s" % ( - click.style(result[1], fg="yellow"), - click.style(result[2], fg="cyan"), - click.style("PASSED" if passed else "FAILED", fg="green" - if passed else "red")), err=not passed) + click.style(testname, fg="yellow"), + click.style(envname, fg="cyan"), + status_str), err=status is False) print_header("[%s] Took %.2f seconds" % ( (click.style("PASSED", fg="green", bold=True) if passed @@ -144,7 +158,8 @@ class TestProcessor(object): line[:-5], click.style("PASSED", fg="green"))) elif ":FAIL:" in line: passed = False - click.secho(line, fg="red") + click.echo("%s\t%s" % ( + line, click.style("FAILED", fg="red"))) else: click.echo(line) if all([l in line for l in ("Tests", "Failures", "Ignored")]): From 8a13a18737a1e7fe6caea3eb8c13911850dc32a8 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 16 Jun 2016 00:53:19 +0300 Subject: [PATCH 026/284] Fix PyLint warning --- platformio/commands/test.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/platformio/commands/test.py b/platformio/commands/test.py index ee09f8a9..0769f7f7 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -42,14 +42,9 @@ def cli(ctx, environment, ignore, upload_port, # pylint: disable=R0913,R0914 test_dir = util.get_projecttest_dir() if not isdir(test_dir): raise exception.TestDirEmpty(test_dir) + test_names = get_test_names(test_dir) projectconf = util.get_project_config() - test_names = [] - for item in sorted(listdir(test_dir)): - if isdir(join(test_dir, item)): - test_names.append(item) - if not test_names: - test_names = ["*"] click.echo("Collected %d items" % len(test_names)) click.echo() @@ -201,3 +196,13 @@ class TestProcessor(object): "Please specify `upload_port` for environment or use " "global `--upload-port` option.") return port + + +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 From 76e07d5012211ae9c4988f2c2275e9fffda5ccde Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 20 Jun 2016 20:33:53 +0300 Subject: [PATCH 027/284] Refactor source files finder --- platformio/builder/tools/piotest.py | 4 +- platformio/builder/tools/platformio.py | 62 ++++++++++++++------------ 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/platformio/builder/tools/piotest.py b/platformio/builder/tools/piotest.py index 8f97a9cc..75336f0e 100644 --- a/platformio/builder/tools/piotest.py +++ b/platformio/builder/tools/piotest.py @@ -74,8 +74,8 @@ def ProcessTest(env): src_filter = "+" src_filter += " +<%s%s>" % (env['PIOTEST'], sep) - return env.LookupSources( - "$BUILDTEST_DIR", test_dir, duplicate=False, src_filter=src_filter + return env.CollectBuildFiles( + "$BUILDTEST_DIR", test_dir, src_filter=src_filter ) diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 7b866bca..ff48faea 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -92,9 +92,8 @@ def BuildProgram(env): LIBPATH=["$BUILD_DIR"] ) - sources = env.LookupSources( - "$BUILDSRC_DIR", "$PROJECTSRC_DIR", duplicate=False, - src_filter=env.get("SRC_FILTER")) + sources = env.CollectBuildFiles( + "$BUILDSRC_DIR", "$PROJECTSRC_DIR", src_filter=env.get("SRC_FILTER")) if "test" in COMMAND_LINE_TARGETS: sources.extend(env.ProcessTest()) @@ -173,12 +172,7 @@ def IsFileWithExt(env, file_, ext): # pylint: disable=W0613 return False -def VariantDirWrap(env, variant_dir, src_dir, duplicate=True): - DefaultEnvironment().Append(VARIANT_DIRS=[(variant_dir, src_dir)]) - env.VariantDir(variant_dir, src_dir, duplicate) - - -def LookupSources(env, variant_dir, src_dir, duplicate=True, src_filter=None): +def MatchSourceFiles(env, src_dir, src_filter): SRC_FILTER_PATTERNS_RE = re.compile(r"(\+|\-)<([^>]+)>") @@ -186,25 +180,32 @@ def LookupSources(env, variant_dir, src_dir, duplicate=True, src_filter=None): if env.IsFileWithExt(item, SRC_BUILD_EXT + SRC_HEADER_EXT): items.add(item.replace(src_dir + sep, "")) - def _match_sources(src_dir, 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(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 + 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(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: - matches -= items - return sorted(list(matches)) + _append_build_item(items, item, src_dir) + if action == "+": + matches |= items + else: + matches -= items + return sorted(list(matches)) + +def VariantDirWrap(env, variant_dir, src_dir, duplicate=True): + DefaultEnvironment().Append(VARIANT_DIRS=[(variant_dir, src_dir)]) + env.VariantDir(variant_dir, src_dir, duplicate) + + +def CollectBuildFiles(env, variant_dir, src_dir, + src_filter=None, duplicate=False): sources = [] variants = [] @@ -212,7 +213,8 @@ def LookupSources(env, variant_dir, src_dir, duplicate=True, src_filter=None): if src_dir.endswith(sep): src_dir = src_dir[:-1] - for item in _match_sources(src_dir, src_filter or SRC_DEFAULT_FILTER): + for item in env.MatchSourceFiles( + src_dir, src_filter or SRC_DEFAULT_FILTER): _reldir = dirname(item) _src_dir = join(src_dir, _reldir) if _reldir else src_dir _var_dir = join(variant_dir, _reldir) if _reldir else variant_dir @@ -257,7 +259,8 @@ def BuildLibrary(env, variant_dir, src_dir, src_filter=None): lib = env.Clone() return lib.Library( lib.subst(variant_dir), - lib.LookupSources(variant_dir, src_dir, src_filter=src_filter) + lib.CollectBuildFiles( + variant_dir, src_dir, src_filter=src_filter) ) @@ -413,8 +416,9 @@ def generate(env): env.AddMethod(ProcessFlags) env.AddMethod(ProcessUnFlags) env.AddMethod(IsFileWithExt) + env.AddMethod(MatchSourceFiles) env.AddMethod(VariantDirWrap) - env.AddMethod(LookupSources) + env.AddMethod(CollectBuildFiles) env.AddMethod(BuildFrameworks) env.AddMethod(BuildLibrary) env.AddMethod(BuildDependentLibraries) From d656d6d5941cd0445fbf78350b1e1317186cabbe Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 20 Jun 2016 21:37:10 +0300 Subject: [PATCH 028/284] Duplicate source files to pioenvs --- platformio/builder/tools/piotest.py | 2 +- platformio/builder/tools/platformio.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/platformio/builder/tools/piotest.py b/platformio/builder/tools/piotest.py index 75336f0e..6d2ceb18 100644 --- a/platformio/builder/tools/piotest.py +++ b/platformio/builder/tools/piotest.py @@ -75,7 +75,7 @@ def ProcessTest(env): src_filter += " +<%s%s>" % (env['PIOTEST'], sep) return env.CollectBuildFiles( - "$BUILDTEST_DIR", test_dir, src_filter=src_filter + "$BUILDTEST_DIR", test_dir, src_filter=src_filter, duplicate=False ) diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index ff48faea..a80c54b6 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -93,7 +93,8 @@ def BuildProgram(env): ) sources = env.CollectBuildFiles( - "$BUILDSRC_DIR", "$PROJECTSRC_DIR", src_filter=env.get("SRC_FILTER")) + "$BUILDSRC_DIR", "$PROJECTSRC_DIR", + src_filter=env.get("SRC_FILTER"), duplicate=False) if "test" in COMMAND_LINE_TARGETS: sources.extend(env.ProcessTest()) @@ -205,7 +206,7 @@ def VariantDirWrap(env, variant_dir, src_dir, duplicate=True): def CollectBuildFiles(env, variant_dir, src_dir, - src_filter=None, duplicate=False): + src_filter=None, duplicate=True): sources = [] variants = [] From 4736bfeea624f93511871cbf4dea4fe1f987758b Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 20 Jun 2016 21:47:13 +0300 Subject: [PATCH 029/284] Fix missed build.extra_flags for the board --- platformio/builder/tools/platformio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index a80c54b6..3d513a57 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -51,7 +51,7 @@ def BuildProgram(env): # process extra flags from board if "BOARD" in env: - env.ProcessFlags(env.BoardConfig().get("build.extra_flags")) + env.ProcessFlags(env.BoardConfig().get("build.extra_flags", None)) # remove base flags env.ProcessUnFlags(env.get("BUILD_UNFLAGS")) # apply user flags From bb7bf4e91b7e1b01927cbfedf1b0cb9e69dae058 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 22 Jun 2016 19:56:22 +0300 Subject: [PATCH 030/284] Fix issue with board extraFlags --- platformio/builder/tools/platformio.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 3d513a57..ac9306a3 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -50,8 +50,8 @@ def BuildProgram(env): ) # process extra flags from board - if "BOARD" in env: - env.ProcessFlags(env.BoardConfig().get("build.extra_flags", None)) + 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 From f8db1d11a703d5ebcc41a621109c4dc46046ac5b Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 22 Jun 2016 21:25:44 +0300 Subject: [PATCH 031/284] New Library Build System: intelligent dependency finder that interprets C Preprocessor conditional macros // Resolve #432 --- HISTORY.rst | 3 + platformio/__init__.py | 2 +- platformio/builder/main.py | 3 +- platformio/builder/tools/piolib.py | 242 +++++++++++++++++++++++++ platformio/builder/tools/platformio.py | 162 +---------------- 5 files changed, 256 insertions(+), 156 deletions(-) create mode 100644 platformio/builder/tools/piolib.py diff --git a/HISTORY.rst b/HISTORY.rst index d7fb834a..a337c560 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -13,6 +13,9 @@ PlatformIO 3.0 (`issue #479 `_) * Unit Testing for Embedded (`docs `__) (`issue #408 `_) +* New Library Build System: intelligent dependency finder that interprets + C Preprocessor conditional macros + (`issue #432 `_) PlatformIO 2.0 -------------- diff --git a/platformio/__init__.py b/platformio/__init__.py index 1e9074a2..facbf112 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev1") +VERSION = (3, 0, "0.dev2") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/main.py b/platformio/builder/main.py index ab957d57..94b1e41b 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -63,7 +63,8 @@ commonvars.AddVariables( DefaultEnvironment( tools=[ "gcc", "g++", "as", "ar", "gnulink", - "platformio", "devplatform", "piotest", "pioupload", "pioar", "piomisc" + "platformio", "devplatform", + "piolib", "piotest", "pioupload", "pioar", "piomisc" ], toolpath=[join(util.get_source_dir(), "builder", "tools")], variables=commonvars, diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py new file mode 100644 index 00000000..a0836a8a --- /dev/null +++ b/platformio/builder/tools/piolib.py @@ -0,0 +1,242 @@ +# Copyright 2014-present Ivan Kravets +# +# 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 +from os.path import basename, commonprefix, isdir, isfile, join +from sys import modules + +import SCons.Scanner + +from platformio import util + + +class LibBuilderFactory(object): + + @staticmethod + def new(env, path): + clsname = "UnknownLibBuilder" + if isfile(join(path, "library.json")): + clsname = "PlatformIOLibBuilder" + else: + env_frameworks = [ + f.lower().strip() for f in env.get("FRAMEWORK", "").split(",")] + used_frameworks = LibBuilderFactory.get_used_frameworks(env, path) + common_frameworks = set(env_frameworks) & set(used_frameworks) + if common_frameworks: + clsname = "%sLibBuilder" % list(common_frameworks)[0].title() + elif used_frameworks: + clsname = "%sLibBuilder" % used_frameworks[0].title() + + obj = getattr(modules[__name__], clsname)(env, path) + assert isinstance(obj, LibBuilderBase) + return obj + + @staticmethod + def get_used_frameworks(env, path): + if any([isfile(join(path, fname)) + for fname in ("library.properties", "keywords.txt")]): + return ["arduino"] + + if isfile(join(path, "module.json")): + return ["mbed"] + + # check source files + for root, _, files in os.walk(path, followlinks=True): + for fname in files: + if not env.IsFileWithExt(fname, ("c", "cpp", "h")): + continue + with open(join(root, fname)) as f: + content = f.read() + if "Arduino.h" in content: + return ["arduino"] + elif "mbed.h" in content: + return ["mbed"] + return [] + + +class LibBuilderBase(object): + + def __init__(self, env, path): + self.env = env + self.path = path + self._is_built = False + + def __repr__(self): + return "%s(%r)" % (self.__class__, self.path) + + def __contains__(self, path): + return commonprefix((self.path, path)) == self.path + + @property + def name(self): + return basename(self.path) + + @property + def src_filter(self): + return " ".join([ + "+<*>", "-<.git%s>" % os.sep, "-" % os.sep, + "-" % os.sep, "-" % os.sep, + "-" % os.sep, "-" % os.sep + ]) + + @property + def src_dir(self): + return (join(self.path, "src") if isdir(join(self.path, "src")) + else self.path) + + @property + def build_dir(self): + return join("$BUILD_DIR", "lib", self.name) + + @property + def is_built(self): + return self._is_built + + def get_path_dirs(self, use_build_dir=False): + return [self.build_dir if use_build_dir else self.src_dir] + + def build(self): + print "Depends on: %s" % self.name + assert self._is_built is False + self._is_built = True + return self.env.BuildLibrary(self.build_dir, self.src_dir) + + +class UnknownLibBuilder(LibBuilderBase): + pass + + +class ArduinoLibBuilder(LibBuilderBase): + + def get_path_dirs(self, use_build_dir=False): + path_dirs = LibBuilderBase.get_path_dirs(self, use_build_dir) + if not isdir(join(self.src_dir, "utility")): + return path_dirs + path_dirs.append(join(self.build_dir if use_build_dir + else self.src_dir, "utility")) + return path_dirs + + +class MbedLibBuilder(LibBuilderBase): + + def __init__(self, env, path): + self.module_json = {} + if isfile(join(path, "module.json")): + self.module_json = util.load_json(join(path, "module.json")) + + LibBuilderBase.__init__(self, env, path) + + @property + def src_dir(self): + if isdir(join(self.path, "source")): + return join(self.path, "source") + return LibBuilderBase.src_dir.fget(self) + + def get_path_dirs(self, use_build_dir=False): + path_dirs = LibBuilderBase.get_path_dirs(self, use_build_dir) + for p in self.module_json.get("extraIncludes", []): + if p.startswith("source/"): + p = p[7:] + path_dirs.append( + join(self.build_dir if use_build_dir else self.src_dir, p)) + return path_dirs + + +class PlatformIOLibBuilder(LibBuilderBase): + + def __init__(self, env, path): + self.library_json = {} + if isfile(join(path, "library.json")): + self.library_json = util.load_json(join(path, "library.json")) + + LibBuilderBase.__init__(self, env, path) + + +def find_deps(env, scanner, path_dirs, src_dir, src_filter): + result = [] + for item in env.MatchSourceFiles(src_dir, src_filter): + result.extend(env.File(join(src_dir, item)).get_implicit_deps( + env, scanner, path_dirs)) + return result + + +def find_and_build_deps(env, lib_builders, scanner, + src_dir, src_filter): + path_dirs = tuple() + built_path_dirs = tuple() + for lb in lib_builders: + items = [env.Dir(d) for d in lb.get_path_dirs()] + if lb.is_built: + built_path_dirs += tuple(items) + else: + path_dirs += tuple(items) + path_dirs = built_path_dirs + path_dirs + + target_lbs = [] + deps = find_deps(env, scanner, path_dirs, src_dir, src_filter) + for d in deps: + for lb in lib_builders: + if d.get_abspath() in lb: + if lb not in target_lbs and not lb.is_built: + target_lbs.append(lb) + break + + libs = [] + # add build dirs to global CPPPATH + for lb in target_lbs: + env.Append( + CPPPATH=lb.get_path_dirs(use_build_dir=True) + ) + # start builder + for lb in target_lbs: + libs.append(lb.build()) + + if env.get("LIB_DFCYCLIC", "").lower() == "true": + for lb in target_lbs: + libs.extend(find_and_build_deps( + env, lib_builders, scanner, lb.src_dir, lb.src_filter)) + + return libs + + +def BuildDependentLibraries(env, src_dir): + lib_builders = [] + libs_dirs = [env.subst(d) for d in env.get("LIBSOURCE_DIRS", []) + if isdir(env.subst(d))] + for libs_dir in libs_dirs: + if not isdir(libs_dir): + continue + for item in sorted(os.listdir(libs_dir)): + if isdir(join(libs_dir, item)): + lib_builders.append( + LibBuilderFactory.new(env, join(libs_dir, item))) + + print "Looking for dependencies..." + print "Library locations: " + ", ".join(libs_dirs) + print "Collecting %d libraries" % len(lib_builders) + + return find_and_build_deps( + env, lib_builders, SCons.Scanner.C.CScanner(), + src_dir, env.get("SRC_FILTER")) + + +def exists(_): + return True + + +def generate(env): + env.AddMethod(BuildDependentLibraries) + return env diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index ac9306a3..138ba0b7 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -16,8 +16,8 @@ from __future__ import absolute_import import re from glob import glob -from os import listdir, sep, walk -from os.path import basename, dirname, isdir, isfile, join, normpath, realpath +from os import sep, walk +from os.path import basename, dirname, isdir, join, normpath, realpath from SCons.Script import COMMAND_LINE_TARGETS, DefaultEnvironment, SConscript from SCons.Util import case_sensitive_suffixes @@ -26,11 +26,7 @@ from platformio.util import pioversion_to_intstr SRC_BUILD_EXT = ["c", "cpp", "S", "spp", "SPP", "sx", "s", "asm", "ASM"] SRC_HEADER_EXT = ["h", "hpp"] -SRC_DEFAULT_FILTER = " ".join([ - "+<*>", "-<.git%s>" % sep, "-" % sep, - "-" % sep, "-" % sep, - "-" % sep, "-" % sep -]) +SRC_FILTER_DEFAULT = " ".join(["+<*>", "-<.git%s>" % sep, "-" % sep]) def BuildProgram(env): @@ -173,7 +169,7 @@ def IsFileWithExt(env, file_, ext): # pylint: disable=W0613 return False -def MatchSourceFiles(env, src_dir, src_filter): +def MatchSourceFiles(env, src_dir, src_filter=None): SRC_FILTER_PATTERNS_RE = re.compile(r"(\+|\-)<([^>]+)>") @@ -181,6 +177,9 @@ def MatchSourceFiles(env, src_dir, src_filter): 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 = src_filter or SRC_FILTER_DEFAULT + matches = set() # correct fs directory separator src_filter = src_filter.replace("/", sep).replace("\\", sep) @@ -214,8 +213,7 @@ def CollectBuildFiles(env, variant_dir, src_dir, if src_dir.endswith(sep): src_dir = src_dir[:-1] - for item in env.MatchSourceFiles( - src_dir, src_filter or SRC_DEFAULT_FILTER): + for item in env.MatchSourceFiles(src_dir, src_filter): _reldir = dirname(item) _src_dir = join(src_dir, _reldir) if _reldir else src_dir _var_dir = join(variant_dir, _reldir) if _reldir else variant_dir @@ -265,149 +263,6 @@ def BuildLibrary(env, variant_dir, src_dir, src_filter=None): ) -def BuildDependentLibraries(env, src_dir): # pylint: disable=R0914 - - INCLUDES_RE = re.compile( - r"^\s*#include\s+(\<|\")([^\>\"\']+)(?:\>|\")", re.M) - LIBSOURCE_DIRS = [env.subst(d) for d in env.get("LIBSOURCE_DIRS", [])] - - # start internal prototypes - - class IncludeFinder(object): - - def __init__(self, base_dir, name, is_system=False): - self.base_dir = base_dir - self.name = name - self.is_system = is_system - - self._inc_path = None - self._lib_dir = None - self._lib_name = None - - def getIncPath(self): - return self._inc_path - - def getLibDir(self): - return self._lib_dir - - def getLibName(self): - return self._lib_name - - def run(self): - if not self.is_system and self._find_in_local(): - return True - return self._find_in_system() - - def _find_in_local(self): - if isfile(join(self.base_dir, self.name)): - self._inc_path = join(self.base_dir, self.name) - return True - else: - return False - - def _find_in_system(self): - for lsd_dir in LIBSOURCE_DIRS: - if not isdir(lsd_dir): - continue - - for ld in env.get("LIB_USE", []) + sorted(listdir(lsd_dir)): - if not isdir(join(lsd_dir, ld)): - continue - - inc_path = normpath(join(lsd_dir, ld, self.name)) - try: - lib_dir = inc_path[:inc_path.index( - sep, len(lsd_dir) + 1)] - except ValueError: - continue - lib_name = basename(lib_dir) - - # ignore user's specified libs - if lib_name in env.get("LIB_IGNORE", []): - continue - - if not isfile(inc_path): - # if source code is in "src" dir - lib_dir = join(lsd_dir, lib_name, "src") - inc_path = join(lib_dir, self.name) - - if isfile(inc_path): - self._lib_dir = lib_dir - self._lib_name = lib_name - self._inc_path = inc_path - return True - return False - - def _get_dep_libs(src_dir): - state = { - "paths": set(), - "libs": set(), - "ordered": set() - } - - state = _process_src_dir(state, env.subst(src_dir)) - - result = [] - for item in sorted(state['ordered'], key=lambda s: s[0]): - result.append((item[1], item[2])) - return result - - def _process_src_dir(state, src_dir): - for root, _, files in walk(src_dir, followlinks=True): - for f in files: - if env.IsFileWithExt(f, SRC_BUILD_EXT + SRC_HEADER_EXT): - state = _parse_includes(state, env.File(join(root, f))) - return state - - def _parse_includes(state, node): - skip_includes = ("arduino.h", "energia.h") - matches = INCLUDES_RE.findall(node.get_text_contents()) - for (inc_type, inc_name) in matches: - base_dir = dirname(node.get_abspath()) - if inc_name.lower() in skip_includes: - continue - if join(base_dir, inc_name) in state['paths']: - continue - else: - state['paths'].add(join(base_dir, inc_name)) - - finder = IncludeFinder(base_dir, inc_name, inc_type == "<") - if finder.run(): - _parse_includes(state, env.File(finder.getIncPath())) - - _lib_dir = finder.getLibDir() - if _lib_dir and _lib_dir not in state['libs']: - state['ordered'].add(( - len(state['ordered']) + 1, finder.getLibName(), - _lib_dir)) - state['libs'].add(_lib_dir) - - if env.subst("$LIB_DFCYCLIC").lower() == "true": - state = _process_src_dir(state, _lib_dir) - return state - - # end internal prototypes - - deplibs = _get_dep_libs(src_dir) - for l, ld in deplibs: - env.Append( - CPPPATH=[join("$BUILD_DIR", l)] - ) - # add automatically "utility" dir from the lib (Arduino issue) - if isdir(join(ld, "utility")): - env.Append( - CPPPATH=[join("$BUILD_DIR", l, "utility")] - ) - - libs = [] - for (libname, inc_dir) in deplibs: - lib = env.BuildLibrary( - join("$BUILD_DIR", libname), inc_dir) - env.Clean(libname, lib) - libs.append(lib) - return libs - - def exists(_): return True @@ -422,5 +277,4 @@ def generate(env): env.AddMethod(CollectBuildFiles) env.AddMethod(BuildFrameworks) env.AddMethod(BuildLibrary) - env.AddMethod(BuildDependentLibraries) return env From 3572b60afd51080c9aaa7b9c7177ebde0a0a996f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 22 Jun 2016 23:17:02 +0300 Subject: [PATCH 032/284] Show detailed build information about dependent libraries // Resolve #617 --- HISTORY.rst | 2 ++ platformio/builder/tools/piolib.py | 3 +-- platformio/builder/tools/platformio.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index a337c560..242f6205 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -16,6 +16,8 @@ PlatformIO 3.0 * New Library Build System: intelligent dependency finder that interprets C Preprocessor conditional macros (`issue #432 `_) +* Show detailed build information about dependent libraries + (`issue #617 `_) PlatformIO 2.0 -------------- diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index a0836a8a..4547c24d 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -109,7 +109,7 @@ class LibBuilderBase(object): return [self.build_dir if use_build_dir else self.src_dir] def build(self): - print "Depends on: %s" % self.name + print "Depends on <%s> (%s)" % (self.name, self.path) assert self._is_built is False self._is_built = True return self.env.BuildLibrary(self.build_dir, self.src_dir) @@ -225,7 +225,6 @@ def BuildDependentLibraries(env, src_dir): LibBuilderFactory.new(env, join(libs_dir, item))) print "Looking for dependencies..." - print "Library locations: " + ", ".join(libs_dirs) print "Collecting %d libraries" % len(lib_builders) return find_and_build_deps( diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 138ba0b7..fa556e30 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -17,7 +17,7 @@ from __future__ import absolute_import import re from glob import glob from os import sep, walk -from os.path import basename, dirname, isdir, join, normpath, realpath +from os.path import basename, dirname, isdir, join, realpath from SCons.Script import COMMAND_LINE_TARGETS, DefaultEnvironment, SConscript from SCons.Util import case_sensitive_suffixes From 1d7add213ecd12954e1e4a5ac514216f7f6bfd2d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 22 Jun 2016 23:21:36 +0300 Subject: [PATCH 033/284] Embedded Board compatibility with more than one development platform // Resolve #456 --- HISTORY.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HISTORY.rst b/HISTORY.rst index 242f6205..3df3a341 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -18,6 +18,8 @@ PlatformIO 3.0 (`issue #432 `_) * Show detailed build information about dependent libraries (`issue #617 `_) +* Embedded Board compatibility with more than one development platform + (`issue #456 `_) PlatformIO 2.0 -------------- From 2ed00064e2f7763fa9a8b36447d29201053c379f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 22 Jun 2016 23:58:42 +0300 Subject: [PATCH 034/284] Fix PyLint warning --- platformio/builder/tools/piolib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 4547c24d..2f6f49a9 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -143,7 +143,7 @@ class MbedLibBuilder(LibBuilderBase): def src_dir(self): if isdir(join(self.path, "source")): return join(self.path, "source") - return LibBuilderBase.src_dir.fget(self) + return super(LibBuilderBase, self).src_dir # pylint: disable=no-member def get_path_dirs(self, use_build_dir=False): path_dirs = LibBuilderBase.get_path_dirs(self, use_build_dir) From d4a866414f764e7b4ae190868096305b07882ce5 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 23 Jun 2016 15:51:08 +0300 Subject: [PATCH 035/284] Minor fixes --- platformio/builder/tools/piolib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 2f6f49a9..73f97b13 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -56,7 +56,7 @@ class LibBuilderFactory(object): # check source files for root, _, files in os.walk(path, followlinks=True): for fname in files: - if not env.IsFileWithExt(fname, ("c", "cpp", "h")): + if not env.IsFileWithExt(fname, ("c", "cpp", "h", "hpp")): continue with open(join(root, fname)) as f: content = f.read() @@ -109,7 +109,7 @@ class LibBuilderBase(object): return [self.build_dir if use_build_dir else self.src_dir] def build(self): - print "Depends on <%s> (%s)" % (self.name, self.path) + print "Depends on <%s>" % self.name assert self._is_built is False self._is_built = True return self.env.BuildLibrary(self.build_dir, self.src_dir) From 476b43d539204804a3f8e94e95eb6bb402b8806b Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 23 Jun 2016 21:39:24 +0300 Subject: [PATCH 036/284] Fix issue with super() --- platformio/builder/tools/piolib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 73f97b13..ae3ba1dc 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -143,7 +143,7 @@ class MbedLibBuilder(LibBuilderBase): def src_dir(self): if isdir(join(self.path, "source")): return join(self.path, "source") - return super(LibBuilderBase, self).src_dir # pylint: disable=no-member + return LibBuilderBase.src_dir.fget(self) # pylint: disable=no-member def get_path_dirs(self, use_build_dir=False): path_dirs = LibBuilderBase.get_path_dirs(self, use_build_dir) From dd111aac4adc8e421299951b69eda737d5e15dc3 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 23 Jun 2016 23:25:13 +0300 Subject: [PATCH 037/284] Library deep search for dependency finder --- HISTORY.rst | 2 +- docs/projectconf.rst | 59 ++++++++++++++++++++++++------ platformio/builder/main.py | 2 +- platformio/builder/tools/piolib.py | 2 +- platformio/commands/run.py | 2 +- 5 files changed, 51 insertions(+), 16 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 3df3a341..90250fa8 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -14,7 +14,7 @@ PlatformIO 3.0 * Unit Testing for Embedded (`docs `__) (`issue #408 `_) * New Library Build System: intelligent dependency finder that interprets - C Preprocessor conditional macros + C Preprocessor conditional macros, `library deep search `__ (`issue #432 `_) * Show detailed build information about dependent libraries (`issue #617 `_) diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 8572d229..89eaf6c4 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -620,24 +620,59 @@ Example: [env:ignore_some_libs] lib_ignore = SPI,EngduinoV3_ID123 -``lib_dfcyclic`` -^^^^^^^^^^^^^^^^ +``lib_deep_search`` +^^^^^^^^^^^^^^^^^^^ -Control cyclic (recursive) behavior for ``Library Dependency Finder (LDF)``. -By default, this option is turned OFF (``lib_dfcyclic=False``) and means that -``LDF`` will find only libraries which are included in source files from the -project :ref:`projectconf_pio_src_dir`. +By default, this option is turned OFF (``lib_deep_search = false``) and means +that ``Library Dependency Finder (LDF)`` will looking only for the libraries +that are mentioned (using ``#include <...>``) in the source files from the +project :ref:`projectconf_pio_src_dir`. Also, ``LDF`` analyzes nested +``#include <...>`` by default. -If you want to enable cyclic (recursive, nested) search, please set this option -to ``True``. Founded library will be treated like a new source files and +If you want to enable deep search, please set this option to ``true``. +Founded library will be treated like a new source files and ``LDF`` will search dependencies for it. -Example: +For example, there are 2 libraries: -.. code-block:: ini +* Library "Foo" with files: - [env:libs_with_enabled_ldf_cyclic] - lib_dfcyclic = True + - ``Foo/foo.h`` + - ``Foo/foo.cpp`` + +* Library "Bar" with files: + + - ``Bar/bar.h`` + - ``Bar/bar.cpp`` + +:Case 1: + + * ``lib_deep_search = false`` + * ``Foo/foo.h`` depends on "Bar" library (contains ``#include ``) + * ``#include `` is located in the one of the project source files + + Here are nested includes (``project file > foo.h > bar.h``) and ``LDF`` will + find both libraries "Foo" and "Bar". + +:Case 2: + + * ``lib_deep_search = false`` + * ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include ``) + * ``#include `` is located in the one of the project source files + + In this case, ``LDF`` will not find "Bar" library because it doesn't know + about CPP file (``Foo/foo.cpp``). + +:Case 3: + + * ``lib_deep_search = true`` + * ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include ``) + * ``#include `` is located in the one of the project source files + + Firstly, ``LDF`` finds "Foo" library, then it parses all sources from "Foo" + library and finds ``Foo/foo.cpp`` that depends on ``#include ``. + Secondly, it will parse all sources from "Bar" library and this operation + continues until all dependent libraries will not be parsed. ----------- diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 94b1e41b..37ad9648 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -41,7 +41,7 @@ commonvars.AddVariables( ("SRC_BUILD_FLAGS",), ("BUILD_UNFLAGS",), ("SRC_FILTER",), - ("LIB_DFCYCLIC",), + ("LIB_DEEP_SEARCH",), ("LIB_IGNORE",), ("LIB_USE",), diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index ae3ba1dc..c11ceca4 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -204,7 +204,7 @@ def find_and_build_deps(env, lib_builders, scanner, for lb in target_lbs: libs.append(lb.build()) - if env.get("LIB_DFCYCLIC", "").lower() == "true": + if env.get("LIB_DEEP_SEARCH", "").lower() == "true": for lb in target_lbs: libs.extend(find_and_build_deps( env, lib_builders, scanner, lb.src_dir, lb.src_filter)) diff --git a/platformio/commands/run.py b/platformio/commands/run.py index fca60880..e2d735d6 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -101,7 +101,7 @@ class EnvironmentProcessor(object): "INSTALL_LIBS": "LIB_INSTALL", "IGNORE_LIBS": "LIB_IGNORE", "USE_LIBS": "LIB_USE", - "LDF_CYCLIC": "LIB_DFCYCLIC", + "LIB_DFCYCLIC": "LIB_DEEP_SEARCH", "SRCBUILD_FLAGS": "SRC_BUILD_FLAGS" } From bc30bf55660c33e2d4908efb5b658098982fe2a8 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 24 Jun 2016 12:54:01 +0300 Subject: [PATCH 038/284] Typo fixes --- docs/projectconf.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 89eaf6c4..f88fc21e 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -624,13 +624,13 @@ Example: ^^^^^^^^^^^^^^^^^^^ By default, this option is turned OFF (``lib_deep_search = false``) and means -that ``Library Dependency Finder (LDF)`` will looking only for the libraries +that ``Library Dependency Finder (LDF)`` will look only for the libraries that are mentioned (using ``#include <...>``) in the source files from the project :ref:`projectconf_pio_src_dir`. Also, ``LDF`` analyzes nested ``#include <...>`` by default. If you want to enable deep search, please set this option to ``true``. -Founded library will be treated like a new source files and +Found library will be treated like the new source files and ``LDF`` will search dependencies for it. For example, there are 2 libraries: @@ -649,7 +649,7 @@ For example, there are 2 libraries: * ``lib_deep_search = false`` * ``Foo/foo.h`` depends on "Bar" library (contains ``#include ``) - * ``#include `` is located in the one of the project source files + * ``#include `` is located in one of the project source files Here are nested includes (``project file > foo.h > bar.h``) and ``LDF`` will find both libraries "Foo" and "Bar". @@ -658,7 +658,7 @@ For example, there are 2 libraries: * ``lib_deep_search = false`` * ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include ``) - * ``#include `` is located in the one of the project source files + * ``#include `` is located in one of the project source files In this case, ``LDF`` will not find "Bar" library because it doesn't know about CPP file (``Foo/foo.cpp``). @@ -667,7 +667,7 @@ For example, there are 2 libraries: * ``lib_deep_search = true`` * ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include ``) - * ``#include `` is located in the one of the project source files + * ``#include `` is located in one of the project source files Firstly, ``LDF`` finds "Foo" library, then it parses all sources from "Foo" library and finds ``Foo/foo.cpp`` that depends on ``#include ``. From 51a9565a727e7df14d709e6dd90d714319070343 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 25 Jun 2016 13:23:24 +0300 Subject: [PATCH 039/284] Refactored `lib_force` and `lib_ignore` logic --- docs/projectconf.rst | 15 ++-- platformio/__init__.py | 2 +- platformio/builder/main.py | 4 +- platformio/builder/tools/piolib.py | 112 ++++++++++++++++++++-------- platformio/builder/tools/piomisc.py | 31 +------- platformio/commands/run.py | 5 +- 6 files changed, 96 insertions(+), 73 deletions(-) diff --git a/docs/projectconf.rst b/docs/projectconf.rst index f88fc21e..77d72526 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -595,18 +595,19 @@ Example: [env:depends_on_some_libs] lib_install = 1,13,19 -``lib_use`` -^^^^^^^^^^^ +``lib_force`` +^^^^^^^^^^^^^ -Specify libraries which should be used by ``Library Dependency Finder (LDF)`` with -the highest priority. +Force Library Build System to build specified libraries if even they are not +included in the project source code. Also, these libraries will be processed +in the first order. Example: .. code-block:: ini - [env:libs_with_highest_priority] - lib_use = OneWire_ID1,SPI + [env:myenv] + lib_force = OneWire, SPI ``lib_ignore`` ^^^^^^^^^^^^^^ @@ -618,7 +619,7 @@ Example: .. code-block:: ini [env:ignore_some_libs] - lib_ignore = SPI,EngduinoV3_ID123 + lib_ignore = SPI, Ethernet ``lib_deep_search`` ^^^^^^^^^^^^^^^^^^^ diff --git a/platformio/__init__.py b/platformio/__init__.py index facbf112..ca2ab2ae 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev2") +VERSION = (3, 0, "0.dev3") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 37ad9648..0fdcc752 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -43,7 +43,7 @@ commonvars.AddVariables( ("SRC_FILTER",), ("LIB_DEEP_SEARCH",), ("LIB_IGNORE",), - ("LIB_USE",), + ("LIB_FORCE",), # board options ("BOARD",), @@ -104,7 +104,7 @@ for k in commonvars.keys(): env.LoadDevPlatform(commonvars) # Parse library names -for opt in ("LIB_IGNORE", "LIB_USE"): +for opt in ("LIB_IGNORE", "LIB_FORCE"): if opt not in env: continue env[opt] = [l.strip() for l in env[opt].split(",") if l.strip()] diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index c11ceca4..e97f271c 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +# pylint: disable=no-member + from __future__ import absolute_import import os @@ -73,6 +75,7 @@ class LibBuilderBase(object): self.env = env self.path = path self._is_built = False + self._manifest = self.load_manifest() def __repr__(self): return "%s(%r)" % (self.__class__, self.path) @@ -82,7 +85,11 @@ class LibBuilderBase(object): @property def name(self): - return basename(self.path) + return self._manifest.get("name", basename(self.path)) + + @property + def version(self): + return self._manifest.get("version") @property def src_filter(self): @@ -105,13 +112,25 @@ class LibBuilderBase(object): def is_built(self): return self._is_built + def load_manifest(self): # pylint: disable=no-self-use + return {} + def get_path_dirs(self, use_build_dir=False): return [self.build_dir if use_build_dir else self.src_dir] + def append_to_cpppath(self): + self.env.AppendUnique( + CPPPATH=self.get_path_dirs(use_build_dir=True) + ) + def build(self): - print "Depends on <%s>" % self.name + if self.version: + print "Depends on <%s> v%s" % (self.name, self.version) + else: + print "Depends on <%s>" % self.name assert self._is_built is False self._is_built = True + self.append_to_cpppath() return self.env.BuildLibrary(self.build_dir, self.src_dir) @@ -121,33 +140,43 @@ class UnknownLibBuilder(LibBuilderBase): class ArduinoLibBuilder(LibBuilderBase): + def load_manifest(self): + manifest = {} + if not isfile(join(self.path, "library.properties")): + return manifest + with open(join(self.path, "library.properties")) as fp: + for line in fp.readlines(): + if "=" not in line: + continue + key, value = line.split("=", 1) + manifest[key.strip()] = value.strip() + return manifest + def get_path_dirs(self, use_build_dir=False): path_dirs = LibBuilderBase.get_path_dirs(self, use_build_dir) if not isdir(join(self.src_dir, "utility")): return path_dirs - path_dirs.append(join(self.build_dir if use_build_dir - else self.src_dir, "utility")) + path_dirs.append( + join(self.build_dir if use_build_dir else self.src_dir, "utility")) return path_dirs class MbedLibBuilder(LibBuilderBase): - def __init__(self, env, path): - self.module_json = {} - if isfile(join(path, "module.json")): - self.module_json = util.load_json(join(path, "module.json")) - - LibBuilderBase.__init__(self, env, path) + def load_manifest(self): + if not isfile(join(self.path, "module.json")): + return {} + return util.load_json(join(self.path, "module.json")) @property def src_dir(self): if isdir(join(self.path, "source")): return join(self.path, "source") - return LibBuilderBase.src_dir.fget(self) # pylint: disable=no-member + return LibBuilderBase.src_dir.fget(self) def get_path_dirs(self, use_build_dir=False): path_dirs = LibBuilderBase.get_path_dirs(self, use_build_dir) - for p in self.module_json.get("extraIncludes", []): + for p in self._manifest.get("extraIncludes", []): if p.startswith("source/"): p = p[7:] path_dirs.append( @@ -157,12 +186,11 @@ class MbedLibBuilder(LibBuilderBase): class PlatformIOLibBuilder(LibBuilderBase): - def __init__(self, env, path): - self.library_json = {} - if isfile(join(path, "library.json")): - self.library_json = util.load_json(join(path, "library.json")) - - LibBuilderBase.__init__(self, env, path) + def load_manifest(self): + assert isfile(join(self.path, "library.json")) + manifest = util.load_json(join(self.path, "library.json")) + assert "name" in manifest + return manifest def find_deps(env, scanner, path_dirs, src_dir, src_filter): @@ -195,11 +223,9 @@ def find_and_build_deps(env, lib_builders, scanner, break libs = [] - # add build dirs to global CPPPATH + # append PATH directories to global CPPPATH before build starts for lb in target_lbs: - env.Append( - CPPPATH=lb.get_path_dirs(use_build_dir=True) - ) + lb.append_to_cpppath() # start builder for lb in target_lbs: libs.append(lb.build()) @@ -212,24 +238,45 @@ def find_and_build_deps(env, lib_builders, scanner, return libs -def BuildDependentLibraries(env, src_dir): - lib_builders = [] +def GetLibBuilders(env): + items = [] libs_dirs = [env.subst(d) for d in env.get("LIBSOURCE_DIRS", []) if isdir(env.subst(d))] for libs_dir in libs_dirs: - if not isdir(libs_dir): - continue for item in sorted(os.listdir(libs_dir)): - if isdir(join(libs_dir, item)): - lib_builders.append( - LibBuilderFactory.new(env, join(libs_dir, item))) + if item == "__cores__" or not isdir(join(libs_dir, item)): + continue + lb = LibBuilderFactory.new(env, join(libs_dir, item)) + if lb.name in env.get("LIB_IGNORE", []): + continue + items.append(lb) + return items + + +def BuildDependentLibraries(env, src_dir): + libs = [] + scanner = SCons.Scanner.C.CScanner() + lib_builders = env.GetLibBuilders() print "Looking for dependencies..." print "Collecting %d libraries" % len(lib_builders) - return find_and_build_deps( - env, lib_builders, SCons.Scanner.C.CScanner(), - src_dir, env.get("SRC_FILTER")) + built_lib_names = [] + for lib_name in env.get("LIB_FORCE", []): + for lb in lib_builders: + if lb.name != lib_name or lb.name in built_lib_names: + continue + built_lib_names.append(lb.name) + libs.extend(find_and_build_deps( + env, lib_builders, scanner, lb.src_dir, lb.src_filter)) + if not lb.is_built: + libs.append(lb.build()) + + # process project source code + libs.extend(find_and_build_deps( + env, lib_builders, scanner, src_dir, env.get("SRC_FILTER"))) + + return libs def exists(_): @@ -237,5 +284,6 @@ def exists(_): def generate(env): + env.AddMethod(GetLibBuilders) env.AddMethod(BuildDependentLibraries) return env diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 6d0095f5..26ec5945 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -145,7 +145,7 @@ def DumpIDEData(env): def get_includes(env_): includes = [] - # includes from used framework and libs + # includes from used frameworks and libs for item in env_.get("VARIANT_DIRS", []): if "$BUILDSRC_DIR" in item[0]: continue @@ -158,9 +158,8 @@ def DumpIDEData(env): includes.append(env_.subst(item)) # installed libs - for d in env_.get("LIBSOURCE_DIRS", []): - lsd_dir = env_.subst(d) - _append_lib_includes(env_, lsd_dir, includes) + for lb in env.GetLibBuilders(): + includes.extend(lb.get_path_dirs()) # includes from toolchains p = env.DevPlatform() @@ -177,30 +176,6 @@ def DumpIDEData(env): return includes - def _append_lib_includes(env_, libs_dir, includes): - if not isdir(libs_dir): - return - for name in env_.get("LIB_USE", []) + sorted(listdir(libs_dir)): - if not isdir(join(libs_dir, name)): - continue - # ignore user's specified libs - if name in env_.get("LIB_IGNORE", []): - continue - if name == "__cores__": - board_core = env_.BoardConfig().get("build.core") - if isdir(join(libs_dir, name, board_core)): - _append_lib_includes( - env_, join(libs_dir, name, board_core), includes) - return - - include = ( - join(libs_dir, name, "src") - if isdir(join(libs_dir, name, "src")) - else join(libs_dir, name) - ) - if include not in includes: - includes.append(include) - def get_defines(env_): defines = [] # global symbols diff --git a/platformio/commands/run.py b/platformio/commands/run.py index e2d735d6..78591e2e 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -100,9 +100,8 @@ class EnvironmentProcessor(object): RENAMED_OPTIONS = { "INSTALL_LIBS": "LIB_INSTALL", "IGNORE_LIBS": "LIB_IGNORE", - "USE_LIBS": "LIB_USE", - "LIB_DFCYCLIC": "LIB_DEEP_SEARCH", - "SRCBUILD_FLAGS": "SRC_BUILD_FLAGS" + "LIB_USE": "LIB_FORCE", + "LIB_DFCYCLIC": "LIB_DEEP_SEARCH" } def __init__(self, cmd_ctx, name, options, # pylint: disable=R0913 From 7344828cf798ee55e1e8ad2344a37e3ea7681f14 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 25 Jun 2016 13:34:51 +0300 Subject: [PATCH 040/284] Update history --- HISTORY.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index 90250fa8..d5cf04e6 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -14,7 +14,8 @@ PlatformIO 3.0 * Unit Testing for Embedded (`docs `__) (`issue #408 `_) * New Library Build System: intelligent dependency finder that interprets - C Preprocessor conditional macros, `library deep search `__ + C Preprocessor conditional macros, `library deep search `__, support for the 3rd party + manifests (Arduino IDE ``library.properties``, ARM mbed ``module.json``) (`issue #432 `_) * Show detailed build information about dependent libraries (`issue #617 `_) From 13112ad6d4266b5de48033e2ca7d5f138c991af5 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 6 Jul 2016 15:27:46 +0300 Subject: [PATCH 041/284] Fix issue when development platform doesn't support frameworks --- examples | 2 +- platformio/builder/tools/piomisc.py | 4 ++-- platformio/managers/platform.py | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/examples b/examples index a5498135..6c0a7e44 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit a5498135baca2dd71e518406ee5cf19ac4be058b +Subproject commit 6c0a7e4458056fa04657a14422aeae277560341d diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 26ec5945..9b657e68 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -17,8 +17,8 @@ from __future__ import absolute_import import atexit import re from glob import glob -from os import environ, listdir, remove -from os.path import isdir, isfile, join +from os import environ, remove +from os.path import isfile, join from platformio import util diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index c27a66ec..4c148b50 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -461,6 +461,8 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): def configure_default_packages(self, variables, targets): # enbale used frameworks for framework in variables.get("framework", "").split(","): + if not self.frameworks: + continue framework = framework.lower().strip() if not framework or framework not in self.frameworks: continue From d88997c4181a2756a4a1dccf01d2c5494dbea893 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 9 Jul 2016 19:30:02 +0300 Subject: [PATCH 042/284] Typo fix --- platformio/builder/tools/devplatform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/builder/tools/devplatform.py b/platformio/builder/tools/devplatform.py index 4c7921dd..5004c0c7 100644 --- a/platformio/builder/tools/devplatform.py +++ b/platformio/builder/tools/devplatform.py @@ -78,7 +78,7 @@ def LoadDevPlatform(env, variables): return board_config = env.BoardConfig() - for k in variables: + for k in variables.keys(): if (k in env or not any([k.startswith("BOARD_"), k.startswith("UPLOAD_")])): continue From 8427b9c7eef25c89322f9dffd19644ee197ad41a Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 11 Jul 2016 13:27:30 +0300 Subject: [PATCH 043/284] Create BasePkgManager for PlatformManager and Library Manager --- platformio/managers/package.py | 36 +++++++++++++++++++++------------ platformio/managers/platform.py | 18 +++++++++-------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 5d0e0a63..79f57416 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -27,25 +27,25 @@ from platformio.unpacker import FileUnpacker from platformio.vcsclient import VCSClientFactory -class PackageManager(object): +class BasePkgManager(object): _INSTALLED_CACHE = {} - def __init__(self, package_dir=None, repositories=None): + def __init__(self, package_dir, repositories=None): self._INSTALLED_CACHE = {} self.repositories = repositories - self.package_dir = package_dir or join(util.get_home_dir(), "packages") + self.package_dir = package_dir if not isdir(self.package_dir): os.makedirs(self.package_dir) assert isdir(self.package_dir) @staticmethod def reset_cache(): - PackageManager._INSTALLED_CACHE = {} + BasePkgManager._INSTALLED_CACHE = {} @property def manifest_name(self): - return "package.json" + raise NotImplementedError() @staticmethod def download(url, dest_dir, sha1=None): @@ -133,8 +133,8 @@ class PackageManager(object): return best def get_installed(self): - if self.package_dir in PackageManager._INSTALLED_CACHE: - return PackageManager._INSTALLED_CACHE[self.package_dir] + if self.package_dir in BasePkgManager._INSTALLED_CACHE: + return BasePkgManager._INSTALLED_CACHE[self.package_dir] items = [] for p in sorted(os.listdir(self.package_dir)): manifest_path = join(self.package_dir, p, self.manifest_name) @@ -144,7 +144,7 @@ class PackageManager(object): manifest['_manifest_path'] = manifest_path assert set(["name", "version"]) <= set(manifest.keys()) items.append(manifest) - PackageManager._INSTALLED_CACHE[self.package_dir] = items + BasePkgManager._INSTALLED_CACHE[self.package_dir] = items return items def is_installed(self, name, requirements=None): @@ -183,7 +183,8 @@ class PackageManager(object): self.reset_cache() if trigger_event: telemetry.on_event( - category="PackageManager", action="Install", label=name) + category=self.__class__.__name__, + action="Install", label=name) return join(pkg_dir, self.manifest_name) @@ -300,7 +301,8 @@ class PackageManager(object): self.reset_cache() if trigger_event: telemetry.on_event( - category="PackageManager", action="Uninstall", label=name) + category=self.__class__.__name__, + action="Uninstall", label=name) def update(self, name, requirements=None): click.echo("Updating %s %s @ %s:" % ( @@ -310,8 +312,8 @@ class PackageManager(object): latest_version = self.get_latest_repo_version(name, requirements) if latest_version is None: - click.secho("Ignored! '%s' is not listed in " - "Package Repository" % name, fg="yellow") + click.secho("Ignored! '%s' is not listed in repository" % name, + fg="yellow") return current = None @@ -341,7 +343,8 @@ class PackageManager(object): self.install(name, latest_version, trigger_event=False) telemetry.on_event( - category="PackageManager", action="Update", label=name) + category=self.__class__.__name__, + action="Update", label=name) return True @@ -384,3 +387,10 @@ class PackageRepoIterator(object): return manifest[self.package] else: return self.next() + + +class PackageManager(BasePkgManager): + + @property + def manifest_name(self): + return "package.json" diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index ebff72c8..504821ff 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -24,13 +24,15 @@ import click import semantic_version from platformio import exception, util -from platformio.managers.package import PackageManager +from platformio.managers.package import BasePkgManager, PackageManager + +PACKAGE_DIR = join(util.get_home_dir(), "packages") -class PlatformManager(PackageManager): +class PlatformManager(BasePkgManager): def __init__(self): - PackageManager.__init__( + BasePkgManager.__init__( self, join(util.get_home_dir(), "platforms"), ["http://dl.platformio.org/platforms/manifest.json"] @@ -43,7 +45,7 @@ class PlatformManager(PackageManager): def install(self, # pylint: disable=too-many-arguments,arguments-differ name, requirements=None, with_packages=None, without_packages=None, skip_default_packages=False): - manifest_path = PackageManager.install(self, name, requirements) + manifest_path = BasePkgManager.install(self, name, requirements) p = PlatformFactory.newPlatform(manifest_path, requirements) p.install_packages( with_packages, without_packages, skip_default_packages) @@ -53,14 +55,14 @@ class PlatformManager(PackageManager): def uninstall(self, # pylint: disable=arguments-differ name, requirements=None): p = PlatformFactory.newPlatform(name, requirements) - PackageManager.uninstall(self, name, requirements) + BasePkgManager.uninstall(self, name, requirements) self.cleanup_packages(p.packages.keys()) return True def update(self, # pylint: disable=arguments-differ name, requirements=None, only_packages=False): if not only_packages: - PackageManager.update(self, name, requirements) + BasePkgManager.update(self, name, requirements) p = PlatformFactory.newPlatform(name, requirements) p.update_packages() self.cleanup_packages(p.packages.keys()) @@ -82,7 +84,7 @@ class PlatformManager(PackageManager): deppkgs[pkgname] = set() deppkgs[pkgname].add(pkgmanifest['version']) - pm = PackageManager() + pm = PackageManager(PACKAGE_DIR) for manifest in pm.get_installed(): if manifest['name'] not in names: continue @@ -322,7 +324,7 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): self._manifest = util.load_json(manifest_path) self.pm = PackageManager( - repositories=self._manifest.get("packageRepositories")) + PACKAGE_DIR, self._manifest.get("packageRepositories")) self._found_error = False self._last_echo_line = None From 4b622b86036bd519d6958845eb76ab6fd9078d72 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 13 Jul 2016 13:24:44 +0300 Subject: [PATCH 044/284] Improve library builder for Arduino lib structure --- platformio/builder/tools/piolib.py | 26 +++++++++++++++++--------- platformio/builder/tools/platformio.py | 4 +++- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index e97f271c..d110a279 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -23,6 +23,7 @@ from sys import modules import SCons.Scanner from platformio import util +from platformio.builder.tools import platformio as piotool class LibBuilderFactory(object): @@ -72,7 +73,7 @@ class LibBuilderFactory(object): class LibBuilderBase(object): def __init__(self, env, path): - self.env = env + self.env = env.Clone() self.path = path self._is_built = False self._manifest = self.load_manifest() @@ -93,11 +94,10 @@ class LibBuilderBase(object): @property def src_filter(self): - return " ".join([ - "+<*>", "-<.git%s>" % os.sep, "-" % os.sep, + return piotool.SRC_FILTER_DEFAULT + [ "-" % os.sep, "-" % os.sep, "-" % os.sep, "-" % os.sep - ]) + ] @property def src_dir(self): @@ -118,8 +118,8 @@ class LibBuilderBase(object): def get_path_dirs(self, use_build_dir=False): return [self.build_dir if use_build_dir else self.src_dir] - def append_to_cpppath(self): - self.env.AppendUnique( + def append_to_cpppath(self, env): + env.AppendUnique( CPPPATH=self.get_path_dirs(use_build_dir=True) ) @@ -130,8 +130,8 @@ class LibBuilderBase(object): print "Depends on <%s>" % self.name assert self._is_built is False self._is_built = True - self.append_to_cpppath() - return self.env.BuildLibrary(self.build_dir, self.src_dir) + return self.env.BuildLibrary( + self.build_dir, self.src_dir, self.src_filter) class UnknownLibBuilder(LibBuilderBase): @@ -160,6 +160,13 @@ class ArduinoLibBuilder(LibBuilderBase): join(self.build_dir if use_build_dir else self.src_dir, "utility")) return path_dirs + @property + def src_filter(self): + if isdir(join(self.path, "src")): + return LibBuilderBase.src_filter.fget(self) + return ["+<*.%s>" % ext + for ext in piotool.SRC_BUILD_EXT + piotool.SRC_HEADER_EXT] + class MbedLibBuilder(LibBuilderBase): @@ -225,7 +232,7 @@ def find_and_build_deps(env, lib_builders, scanner, libs = [] # append PATH directories to global CPPPATH before build starts for lb in target_lbs: - lb.append_to_cpppath() + lb.append_to_cpppath(env) # start builder for lb in target_lbs: libs.append(lb.build()) @@ -270,6 +277,7 @@ def BuildDependentLibraries(env, src_dir): libs.extend(find_and_build_deps( env, lib_builders, scanner, lb.src_dir, lb.src_filter)) if not lb.is_built: + lb.append_to_cpppath(env) libs.append(lb.build()) # process project source code diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index b96c47a6..91a0a149 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -26,7 +26,7 @@ from platformio.util import pioversion_to_intstr SRC_BUILD_EXT = ["c", "cpp", "S", "spp", "SPP", "sx", "s", "asm", "ASM"] SRC_HEADER_EXT = ["h", "hpp"] -SRC_FILTER_DEFAULT = " ".join(["+<*>", "-<.git%s>" % sep, "-" % sep]) +SRC_FILTER_DEFAULT = ["+<*>", "-<.git%s>" % sep, "-" % sep] def BuildProgram(env): @@ -179,6 +179,8 @@ def MatchSourceFiles(env, src_dir, src_filter=None): src_dir = env.subst(src_dir) src_filter = src_filter or SRC_FILTER_DEFAULT + if isinstance(src_filter, list) or isinstance(src_filter, tuple): + src_filter = " ".join(src_filter) matches = set() # correct fs directory separator From 4997528f6aaf3e71ab9945ce61edf7a51991836a Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 15 Jul 2016 16:12:07 +0300 Subject: [PATCH 045/284] Handle specific extra build flags from library.json // Resolve #289 --- HISTORY.rst | 3 + docs/faq.rst | 6 -- docs/librarymanager/config.rst | 80 +++++++++++++++++++++++++- docs/projectconf.rst | 2 + platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 63 +++++++++++++++++--- platformio/builder/tools/platformio.py | 2 +- 7 files changed, 141 insertions(+), 17 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index cded83ea..a948fcfa 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -17,6 +17,9 @@ PlatformIO 3.0 C Preprocessor conditional macros, `library deep search `__, support for the 3rd party manifests (Arduino IDE ``library.properties``, ARM mbed ``module.json``) (`issue #432 `_) +* Handle extra build flags and build script from + `library.json `__ + (`issue #289 `_) * Show detailed build information about dependent libraries (`issue #617 `_) * Embedded Board compatibility with more than one development platform diff --git a/docs/faq.rst b/docs/faq.rst index 663c108f..75ed3cfb 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -155,12 +155,6 @@ Answered in `issue #144 `_ -* `#331: Unable to use MySensors library `_ - ARM toolchain: cc1plus: error while loading shared libraries '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index c56d74ed..2072aabc 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -22,6 +22,7 @@ to keep project in own structure and define: * examples list * compatible frameworks and platforms * library dependencies +* advanced build settings PlatformIO Library Crawler uses ``library.json`` manifest to extract source code from developer's location and keeps cleaned library in own @@ -397,7 +398,7 @@ See more ``library.json`` :ref:`library_creating_examples`. .. _libjson_examples: ``examples`` ----------------- +------------ *Optional* | Type: ``String`` or ``Array`` | `Glob Pattern `_ @@ -413,3 +414,80 @@ A list of example patterns. This field is predefined with default value: "[Ee]xamples/*/*.ino", "[Ee]xamples/*/*.pde" ] + + +.. _libjson_build: + +``build`` +------------ + +*Optional* | Type: ``Object`` + +Specify advanced settings, options and flags for the build system. Possible +options: + +* ``flags`` - extra flags to control preprocessing, compilation, assembly and + linking processes. More details :ref:`projectconf_build_flags` +* ``unflags`` - remove base/initial flags which were set by development + platform. More details :ref:`projectconf_build_unflags` +* ``srcFilter`` - specify which source files should be included/excluded + from build process. More details :ref:`projectconf_src_filter` +* ``extraScript`` - launch extra script before build process. + More details :ref:`projectconf_extra_script`. + +**Examples** + +1. Custom macros/defines + +.. code-block:: javascript + + "build": { + "flags": "-D MYLIB_REV=0.1.2 -DRELEASE" + } + +2. Extra includes for C preprocessor + +.. code-block:: javascript + + "build": { + "flags": "-I inc -I inc/target_x13" + } + +3. Force to use ``C99`` standard instead ``C11`` + +.. code-block:: javascript + + "build": { + "unflags": "-std=gnu++11", + "flags": "-std=c99" + } + +4. Build source files (``c, cpp, h``) only from the root of the library + +.. code-block:: javascript + + "build": { + "srcFilter": [ + "+<*.c>", + "+<*.cpp>", + "+<*.h>" + ] + } + + +5. Extend PlatformIO Build System with own extra script + +.. code-block:: javascript + + "build": { + "extraScript": "generate_headers.py" + } + +``generate_headers.py`` + +.. code-block:: python + + # Import('env') + # print env.Dump() + + # some python code that generates headers files "on-the-fly" diff --git a/docs/projectconf.rst b/docs/projectconf.rst index f3700743..5d5b9596 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -422,6 +422,8 @@ but will be applied only for the project source code from This option can be set by global environment variable :envvar:`PLATFORMIO_SRC_BUILD_FLAGS`. +.. _projectconf_build_unflags: + ``build_unflags`` ^^^^^^^^^^^^^^^^^ diff --git a/platformio/__init__.py b/platformio/__init__.py index 15f4a2a8..6ab03493 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev4") +VERSION = (3, 0, "0.dev5") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index d110a279..ac31c85f 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -17,7 +17,7 @@ from __future__ import absolute_import import os -from os.path import basename, commonprefix, isdir, isfile, join +from os.path import basename, commonprefix, isdir, isfile, join, realpath from sys import modules import SCons.Scanner @@ -73,7 +73,7 @@ class LibBuilderFactory(object): class LibBuilderBase(object): def __init__(self, env, path): - self.env = env.Clone() + self.env = env self.path = path self._is_built = False self._manifest = self.load_manifest() @@ -108,6 +108,18 @@ class LibBuilderBase(object): def build_dir(self): return join("$BUILD_DIR", "lib", self.name) + @property + def build_flags(self): + return None + + @property + def build_unflags(self): + return None + + @property + def extra_script(self): + return None + @property def is_built(self): return self._is_built @@ -118,8 +130,8 @@ class LibBuilderBase(object): def get_path_dirs(self, use_build_dir=False): return [self.build_dir if use_build_dir else self.src_dir] - def append_to_cpppath(self, env): - env.AppendUnique( + def append_to_cpppath(self): + self.env.AppendUnique( CPPPATH=self.get_path_dirs(use_build_dir=True) ) @@ -130,8 +142,20 @@ class LibBuilderBase(object): print "Depends on <%s>" % self.name assert self._is_built is False self._is_built = True - return self.env.BuildLibrary( - self.build_dir, self.src_dir, self.src_filter) + self.append_to_cpppath() + + env = self.env.Clone() + with util.cd(self.path): + env.ProcessUnFlags(self.build_unflags) + env.ProcessFlags(self.build_flags) + if self.extra_script: + env.SConscript(realpath(self.extra_script), exports="env") + + # copy some data to global env + for key in ("CPPPATH", "LIBPATH", "LIBS", "LINKFLAGS"): + self.env.AppendUnique(**{key: env.get(key)}) + + return env.BuildLibrary(self.build_dir, self.src_dir, self.src_filter) class UnknownLibBuilder(LibBuilderBase): @@ -199,6 +223,30 @@ class PlatformIOLibBuilder(LibBuilderBase): assert "name" in manifest return manifest + @property + def src_filter(self): + if "srcFilter" in self._manifest.get("build", {}): + return self._manifest.get("build").get("srcFilter") + return LibBuilderBase.src_filter.fget(self) + + @property + def build_flags(self): + if "flags" in self._manifest.get("build", {}): + return self._manifest.get("build").get("flags") + return LibBuilderBase.build_flags.fget(self) + + @property + def build_unflags(self): + if "unflags" in self._manifest.get("build", {}): + return self._manifest.get("build").get("unflags") + return LibBuilderBase.build_unflags.fget(self) + + @property + def extra_script(self): + if "extra_script" in self._manifest.get("build", {}): + return self._manifest.get("build").get("extra_script") + return LibBuilderBase.extra_script.fget(self) + def find_deps(env, scanner, path_dirs, src_dir, src_filter): result = [] @@ -232,7 +280,7 @@ def find_and_build_deps(env, lib_builders, scanner, libs = [] # append PATH directories to global CPPPATH before build starts for lb in target_lbs: - lb.append_to_cpppath(env) + lb.append_to_cpppath() # start builder for lb in target_lbs: libs.append(lb.build()) @@ -277,7 +325,6 @@ def BuildDependentLibraries(env, src_dir): libs.extend(find_and_build_deps( env, lib_builders, scanner, lb.src_dir, lb.src_filter)) if not lb.is_built: - lb.append_to_cpppath(env) libs.append(lb.build()) # process project source code diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 91a0a149..7ce3692e 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -154,7 +154,7 @@ def ProcessUnFlags(env, flags): all_flags = set(all_flags) for key in parsed_flags: - cur_flags = set(env.get(key, [])) + cur_flags = set(env.Flatten(env.get(key, []))) for item in cur_flags & all_flags: while item in env[key]: env[key].remove(item) From c7d9ab84747e81ac16351c33e51b69ff9f2942f6 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 15 Jul 2016 18:41:16 +0300 Subject: [PATCH 046/284] Allow to use extra build options as array for library.json // Issue #289 --- docs/librarymanager/config.rst | 41 +++++++++++++++++++------- platformio/builder/tools/platformio.py | 5 +++- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index 2072aabc..50a82cc9 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -426,14 +426,28 @@ A list of example patterns. This field is predefined with default value: Specify advanced settings, options and flags for the build system. Possible options: -* ``flags`` - extra flags to control preprocessing, compilation, assembly and - linking processes. More details :ref:`projectconf_build_flags` -* ``unflags`` - remove base/initial flags which were set by development - platform. More details :ref:`projectconf_build_unflags` -* ``srcFilter`` - specify which source files should be included/excluded - from build process. More details :ref:`projectconf_src_filter` -* ``extraScript`` - launch extra script before build process. - More details :ref:`projectconf_extra_script`. +.. list-table:: + :header-rows: 1 + + * - Option + - Type + - Description + * - ``flags`` + - ``String`` or ``Array`` + - Extra flags to control preprocessing, compilation, assembly and + linking processes. More details :ref:`projectconf_build_flags` + * - ``unflags`` + - ``String`` or ``Array`` + - Remove base/initial flags which were set by development + platform. More details :ref:`projectconf_build_unflags` + * - ``srcFilter`` + - ``String`` or ``Array`` + - Specify which source files should be included/excluded + from build process. More details :ref:`projectconf_src_filter` + * - ``extraScript`` + - ``String`` + - Launch extra script before build process. + More details :ref:`projectconf_extra_script` **Examples** @@ -450,7 +464,10 @@ options: .. code-block:: javascript "build": { - "flags": "-I inc -I inc/target_x13" + "flags": [ + "-I inc", + "-I inc/target_x13" + ] } 3. Force to use ``C99`` standard instead ``C11`` @@ -487,7 +504,11 @@ options: .. code-block:: python - # Import('env') + Import('env') # print env.Dump() + env.Append( + CPPDEFINES=["HELLO=WORLD", "TAG=1.2.3", "DEBUG"], + CPPPATH=["inc", "inc/devices"] + ) # some python code that generates headers files "on-the-fly" diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 7ce3692e..c3440897 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -114,7 +114,9 @@ def BuildProgram(env): def ProcessFlags(env, flags): if not flags: return - parsed_flags = env.ParseFlags(str(flags)) + if isinstance(flags, list): + flags = " ".join(flags) + parsed_flags = env.ParseFlags(flags) for flag in parsed_flags.pop("CPPDEFINES"): if not isinstance(flag, list): env.Append(CPPDEFINES=flag) @@ -147,6 +149,7 @@ def ProcessFlags(env, flags): def ProcessUnFlags(env, flags): if not flags: return + flags = " ".join(flags) parsed_flags = env.ParseFlags(flags) all_flags = [] for items in parsed_flags.values(): From 8726f8317c0bd4bc0251bea3f6658ef5cc75b0e2 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 15 Jul 2016 18:59:10 +0300 Subject: [PATCH 047/284] Typo fix --- platformio/builder/tools/platformio.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index c3440897..6010088f 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -149,7 +149,8 @@ def ProcessFlags(env, flags): def ProcessUnFlags(env, flags): if not flags: return - flags = " ".join(flags) + if isinstance(flags, list): + flags = " ".join(flags) parsed_flags = env.ParseFlags(flags) all_flags = [] for items in parsed_flags.values(): From 06494729f13c33ea6d9364ab68852bc7a2ad9b6e Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 15 Jul 2016 19:40:11 +0300 Subject: [PATCH 048/284] Fix for Python 2.6 --- platformio/builder/tools/platformio.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 6010088f..fe196955 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -116,7 +116,7 @@ def ProcessFlags(env, flags): return if isinstance(flags, list): flags = " ".join(flags) - parsed_flags = env.ParseFlags(flags) + parsed_flags = env.ParseFlags(str(flags)) for flag in parsed_flags.pop("CPPDEFINES"): if not isinstance(flag, list): env.Append(CPPDEFINES=flag) @@ -151,7 +151,7 @@ def ProcessUnFlags(env, flags): return if isinstance(flags, list): flags = " ".join(flags) - parsed_flags = env.ParseFlags(flags) + parsed_flags = env.ParseFlags(str(flags)) all_flags = [] for items in parsed_flags.values(): all_flags.extend(items) From 2bfa3517f052217b117e70e5c4134be2ed31f0b1 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 15 Jul 2016 19:57:55 +0300 Subject: [PATCH 049/284] Add license field to library.json // Resolve #522 --- HISTORY.rst | 2 ++ docs/librarymanager/config.rst | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index a948fcfa..74948581 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -20,6 +20,8 @@ PlatformIO 3.0 * Handle extra build flags and build script from `library.json `__ (`issue #289 `_) +* Added ``license`` field to `library.json `__ + (`issue #522 `_) * Show detailed build information about dependent libraries (`issue #617 `_) * Embedded Board compatibility with more than one development platform diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index 50a82cc9..709e42ff 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -222,6 +222,19 @@ Example: }, "version": "1.0.0" + +``license`` +----------- + +A license of the library. You can check +`the full list of SPDX license IDs `_. Ideally you +should pick one that is `OSI `_ +approved. + +.. code-block:: javascript + + "license": "Apache-2.0" + .. _libjson_downloadurl: ``downloadUrl`` @@ -479,7 +492,7 @@ options: "flags": "-std=c99" } -4. Build source files (``c, cpp, h``) only from the root of the library +4. Build source files (``c, cpp, h``) at the top level of the library .. code-block:: javascript From 9838aef6b80f4b985ec5abc2daed6ce6028d3d57 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 15 Jul 2016 23:06:10 +0300 Subject: [PATCH 050/284] Check library compatibility with project environment before building // Resolve #415 --- HISTORY.rst | 2 ++ platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 40 +++++++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 74948581..d6fbe399 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -20,6 +20,8 @@ PlatformIO 3.0 * Handle extra build flags and build script from `library.json `__ (`issue #289 `_) +* Check library compatibility with project environment before building + (`issue #415 `_) * Added ``license`` field to `library.json `__ (`issue #522 `_) * Show detailed build information about dependent libraries diff --git a/platformio/__init__.py b/platformio/__init__.py index 6ab03493..d770fc9b 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev5") +VERSION = (3, 0, "0.dev6") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index ac31c85f..5c1389ce 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -124,6 +124,12 @@ class LibBuilderBase(object): def is_built(self): return self._is_built + def is_platform_compatible(self, platform): + return True + + def is_framework_compatible(self, framework): + return True + def load_manifest(self): # pylint: disable=no-self-use return {} @@ -191,6 +197,9 @@ class ArduinoLibBuilder(LibBuilderBase): return ["+<*.%s>" % ext for ext in piotool.SRC_BUILD_EXT + piotool.SRC_HEADER_EXT] + def is_framework_compatible(self, framework): + return framework.lower() in ("arduino", "energia") + class MbedLibBuilder(LibBuilderBase): @@ -214,6 +223,9 @@ class MbedLibBuilder(LibBuilderBase): join(self.build_dir if use_build_dir else self.src_dir, p)) return path_dirs + def is_framework_compatible(self, framework): + return framework.lower() == "mbed" + class PlatformIOLibBuilder(LibBuilderBase): @@ -247,6 +259,25 @@ class PlatformIOLibBuilder(LibBuilderBase): return self._manifest.get("build").get("extra_script") return LibBuilderBase.extra_script.fget(self) + def is_platform_compatible(self, platform): + items = self._manifest.get("platforms") + if not items: + return LibBuilderBase.is_platform_compatible(self, platform) + return self._item_in_list(platform, items) + + def is_framework_compatible(self, framework): + items = self._manifest.get("frameworks") + if not items: + return LibBuilderBase.is_framework_compatible(self, framework) + return self._item_in_list(framework, items) + + def _item_in_list(self, item, ilist): + if ilist == "*": + return True + if not isinstance(ilist, list): + ilist = [i.strip() for i in ilist.split(",")] + return item.lower() in [i.lower() for i in ilist] + def find_deps(env, scanner, path_dirs, src_dir, src_filter): result = [] @@ -295,6 +326,8 @@ def find_and_build_deps(env, lib_builders, scanner, def GetLibBuilders(env): items = [] + env_frameworks = [ + f.lower().strip() for f in env.get("FRAMEWORK", "").split(",")] libs_dirs = [env.subst(d) for d in env.get("LIBSOURCE_DIRS", []) if isdir(env.subst(d))] for libs_dir in libs_dirs: @@ -304,6 +337,11 @@ def GetLibBuilders(env): lb = LibBuilderFactory.new(env, join(libs_dir, item)) if lb.name in env.get("LIB_IGNORE", []): continue + if not lb.is_platform_compatible(env['PLATFORM']): + continue + if not any([lb.is_framework_compatible(f) + for f in env_frameworks]): + continue items.append(lb) return items @@ -314,7 +352,7 @@ def BuildDependentLibraries(env, src_dir): lib_builders = env.GetLibBuilders() print "Looking for dependencies..." - print "Collecting %d libraries" % len(lib_builders) + print "Collecting %d compatible libraries" % len(lib_builders) built_lib_names = [] for lib_name in env.get("LIB_FORCE", []): From 02e883b55c4ef172d3495703f17d9f72319deb8b Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 15 Jul 2016 23:51:33 +0300 Subject: [PATCH 051/284] Implement "lib_extra_dirs" option for project environment // Resolve #537 --- HISTORY.rst | 3 +++ docs/envvars.rst | 4 ++++ docs/projectconf.rst | 24 ++++++++++++++++++++++++ platformio/__init__.py | 2 +- platformio/builder/main.py | 24 +++++++++++++----------- platformio/builder/tools/piolib.py | 14 ++++++++++---- 6 files changed, 55 insertions(+), 16 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index d6fbe399..981c883e 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -17,6 +17,9 @@ PlatformIO 3.0 C Preprocessor conditional macros, `library deep search `__, support for the 3rd party manifests (Arduino IDE ``library.properties``, ARM mbed ``module.json``) (`issue #432 `_) +* New `lib_extra_dirs `__ option for project environment. + Multiple custom library locations! + (`issue #537 `_) * Handle extra build flags and build script from `library.json `__ (`issue #289 `_) diff --git a/docs/envvars.rst b/docs/envvars.rst index d0165b05..40d93b83 100644 --- a/docs/envvars.rst +++ b/docs/envvars.rst @@ -107,6 +107,10 @@ Allows to set :ref:`projectconf` option :ref:`projectconf_src_filter`. Allows to set :ref:`projectconf` option :ref:`projectconf_extra_script`. +.. envvar:: PLATFORMIO_LIB_EXTRA_DIRS + +Allows to set :ref:`projectconf` option :ref:`projectconf_lib_extra_dirs`. + Uploading --------- diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 5d5b9596..0c905b2f 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -681,6 +681,30 @@ For example, there are 2 libraries: Secondly, it will parse all sources from "Bar" library and this operation continues until all dependent libraries will not be parsed. +.. _projectconf_lib_extra_dirs: + +``lib_extra_dirs`` +^^^^^^^^^^^^^^^^^^ + +A list with extra directories where ``Library Dependency Finder (LDF)`` will +look for dependencies. Multiple paths are allowed. Please separate them using +comma ``,`` symbol. + +This option can be set by global environment variable +:envvar:`PLATFORMIO_LIB_EXTRA_DIRS`. + +.. warning:: + This is a not direct path to library with source code. It should be the path + to directory that contains libraries grouped by folders. For example, + ``/extra/lib/path/`` but not ``/extra/lib/path/MyLibrary``. + +Example: + +.. code-block:: ini + + [env:custom_lib_dirs] + lib_extra_dirs = /path/to/private/dir1,/path/to/private/dir2 + ----------- .. _projectconf_examples: diff --git a/platformio/__init__.py b/platformio/__init__.py index d770fc9b..28a1507b 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev6") +VERSION = (3, 0, "0.dev7") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 0fdcc752..822421ec 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -34,16 +34,19 @@ commonvars.AddVariables( ("PIOENV",), ("PIOTEST",), ("PLATFORM",), - - # options ("FRAMEWORK",), + + # build options ("BUILD_FLAGS",), ("SRC_BUILD_FLAGS",), ("BUILD_UNFLAGS",), ("SRC_FILTER",), + + # library options ("LIB_DEEP_SEARCH",), ("LIB_IGNORE",), ("LIB_FORCE",), + ("LIB_EXTRA_DIRS",), # board options ("BOARD",), @@ -101,21 +104,20 @@ for k in commonvars.keys(): if k in env: env[k] = base64.b64decode(env[k]) -env.LoadDevPlatform(commonvars) - -# Parse library names -for opt in ("LIB_IGNORE", "LIB_FORCE"): - if opt not in env: - continue - env[opt] = [l.strip() for l in env[opt].split(",") if l.strip()] - # Handle custom variables from system environment for var in ("BUILD_FLAGS", "SRC_BUILD_FLAGS", "SRC_FILTER", "EXTRA_SCRIPT", - "UPLOAD_PORT", "UPLOAD_FLAGS"): + "UPLOAD_PORT", "UPLOAD_FLAGS", "LIB_EXTRA_DIRS"): k = "PLATFORMIO_%s" % var if environ.get(k): env[var] = environ.get(k) +# Parse comma separated items +for opt in ("LIB_IGNORE", "LIB_FORCE", "LIB_EXTRA_DIRS"): + if opt not in env: + continue + env[opt] = [l.strip() for l in env[opt].split(",") if l.strip()] + +env.LoadDevPlatform(commonvars) env.SConscriptChdir(0) env.SConsignFile(join("$PIOENVS_DIR", ".sconsign.dblite")) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 5c1389ce..6a06f985 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=no-member +# pylint: disable=no-member, no-self-use, unused-argument from __future__ import absolute_import @@ -130,7 +130,7 @@ class LibBuilderBase(object): def is_framework_compatible(self, framework): return True - def load_manifest(self): # pylint: disable=no-self-use + def load_manifest(self): return {} def get_path_dirs(self, use_build_dir=False): @@ -326,10 +326,16 @@ def find_and_build_deps(env, lib_builders, scanner, def GetLibBuilders(env): items = [] + libs_dirs = [] env_frameworks = [ f.lower().strip() for f in env.get("FRAMEWORK", "").split(",")] - libs_dirs = [env.subst(d) for d in env.get("LIBSOURCE_DIRS", []) - if isdir(env.subst(d))] + + for key in ("LIB_EXTRA_DIRS", "LIBSOURCE_DIRS"): + for d in env.get(key, []): + d = env.subst(d) + if isdir(d): + libs_dirs.append(d) + for libs_dir in libs_dirs: for item in sorted(os.listdir(libs_dir)): if item == "__cores__" or not isdir(join(libs_dir, item)): From da6f424b111ae78395d8a4b789054e1b20fc582d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 16 Jul 2016 00:19:56 +0300 Subject: [PATCH 052/284] Export root "env" to the extra script --- docs/projectconf.rst | 4 +--- platformio/builder/main.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 0c905b2f..f0e6b941 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -486,9 +486,7 @@ Example, specify own upload command for :ref:`platform_atmelavr`: .. code-block:: python - from SCons.Script import DefaultEnvironment - - env = DefaultEnvironment() + Import('env') env.Replace(UPLOADHEXCMD='"$UPLOADER" ${ARGUMENTS.get("custom_option")} --uploader --flags') diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 822421ec..7c1fc192 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -128,7 +128,7 @@ if "UPLOAD_FLAGS" in env: env.Append(UPLOADERFLAGS=["$UPLOAD_FLAGS"]) if env.get("EXTRA_SCRIPT"): - env.SConscript(env.get("EXTRA_SCRIPT")) + env.SConscript(env.get("EXTRA_SCRIPT"), exports="env") if "envdump" in COMMAND_LINE_TARGETS: print env.Dump() From 70031040b371a71933f45c30b4645386228cfff0 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 16 Jul 2016 18:00:55 +0300 Subject: [PATCH 053/284] Rename test --ignore option to --skip --- docs/userguide/cmd_test.rst | 6 +++--- platformio/commands/test.py | 14 ++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/userguide/cmd_test.rst b/docs/userguide/cmd_test.rst index af38f9b7..1a4dba6c 100644 --- a/docs/userguide/cmd_test.rst +++ b/docs/userguide/cmd_test.rst @@ -43,9 +43,9 @@ Options Process specified environments. More details :option:`platformio run --environment` .. option:: - -i, --ignore + --skip -Ignore tests where the name matches with specified pattern. More than one +Skip over tests where the name matches specified patterns. More than one option/pattern is allowed. .. list-table:: @@ -66,7 +66,7 @@ option/pattern is allowed. * - ``[!seq]`` - matches any character not in seq -For example, ``platformio test --ignore "mytest*" -i "test[13]"`` +For example, ``platformio test --skip "mytest*" -i "test[13]"`` .. option:: --upload-port diff --git a/platformio/commands/test.py b/platformio/commands/test.py index 0769f7f7..0585a0b1 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +# pylint: disable=R0913,R0914 + from fnmatch import fnmatch from os import getcwd, listdir from os.path import isdir, join @@ -28,15 +30,14 @@ from platformio.managers.platform import PlatformFactory @click.command("test", short_help="Unit Testing") @click.option("--environment", "-e", multiple=True, metavar="") -@click.option("--ignore", "-i", multiple=True, metavar="") +@click.option("--skip", multiple=True, metavar="") @click.option("--upload-port", metavar="") @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("--verbose", "-v", count=True, default=3) @click.pass_context -def cli(ctx, environment, ignore, upload_port, # pylint: disable=R0913,R0914 - project_dir, verbose): +def cli(ctx, environment, skip, upload_port, project_dir, verbose): assert check_project_envs(project_dir, environment) with util.cd(project_dir): test_dir = util.get_projecttest_dir() @@ -58,8 +59,8 @@ def cli(ctx, environment, ignore, upload_port, # pylint: disable=R0913,R0914 if environment and envname not in environment: continue - # check ignore patterns - if testname != "*" and any([fnmatch(testname, i) for i in ignore]): + # check skip patterns + if testname != "*" and any([fnmatch(testname, p) for p in skip]): results.append((None, testname, envname)) continue @@ -133,7 +134,8 @@ class TestProcessor(object): return self.cmd_ctx.invoke( cmd_run, project_dir=self.options['project_dir'], upload_port=self.options['upload_port'], - verbose=self.options['verbose'], environment=[self.env_name], + verbose=self.options['verbose'], + environment=[self.env_name], target=target ) From daac1b2590f267f1ea22a97281751865b55e8208 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 17 Jul 2016 00:48:59 +0300 Subject: [PATCH 054/284] Print human-readable information when processing environments without // Resolve #721 --- HISTORY.rst | 3 + docs/envvars.rst | 4 + docs/userguide/cmd_ci.rst | 6 +- docs/userguide/cmd_run.rst | 157 ++++++++++++++----------- docs/userguide/cmd_settings.rst | 14 +++ docs/userguide/cmd_test.rst | 6 +- platformio/__init__.py | 2 +- platformio/app.py | 4 + platformio/builder/main.py | 10 +- platformio/builder/tools/piomisc.py | 9 ++ platformio/builder/tools/platformio.py | 4 +- platformio/commands/ci.py | 2 +- platformio/commands/run.py | 6 +- platformio/commands/test.py | 2 +- platformio/managers/platform.py | 52 +++----- 15 files changed, 161 insertions(+), 120 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 981c883e..e89b8e1d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -25,6 +25,9 @@ PlatformIO 3.0 (`issue #289 `_) * Check library compatibility with project environment before building (`issue #415 `_) +* Print human-readable information when processing environments without + ``-v, --verbose`` option + (`issue #721 `_) * Added ``license`` field to `library.json `__ (`issue #522 `_) * Show detailed build information about dependent libraries diff --git a/docs/envvars.rst b/docs/envvars.rst index 40d93b83..fdbbada7 100644 --- a/docs/envvars.rst +++ b/docs/envvars.rst @@ -157,3 +157,7 @@ Allows to override setting :ref:`setting_enable_prompts`. .. envvar:: PLATFORMIO_SETTING_ENABLE_TELEMETRY Allows to override setting :ref:`setting_enable_telemetry`. + +.. envvar:: PLATFORMIO_SETTING_FORCE_VERBOSE + +Allows to override setting :ref:`setting_force_verbose`. diff --git a/docs/userguide/cmd_ci.rst b/docs/userguide/cmd_ci.rst index d97d3b96..785f2e0d 100644 --- a/docs/userguide/cmd_ci.rst +++ b/docs/userguide/cmd_ci.rst @@ -112,8 +112,10 @@ Buid project using pre-configured :ref:`projectconf`. .. option:: -v, --verbose -Shows details about the results of processing environments. More details -:option:`platformio run --verbose` +Shows detailed information when processing environments. + +This option can be set globally using :ref:`setting_force_verbose` setting +or by environment variable :envvar:`PLATFORMIO_SETTING_FORCE_VERBOSE`. Examples -------- diff --git a/docs/userguide/cmd_run.rst b/docs/userguide/cmd_run.rst index 383970c1..6d2696de 100644 --- a/docs/userguide/cmd_run.rst +++ b/docs/userguide/cmd_run.rst @@ -77,17 +77,10 @@ to current working directory (``CWD``). .. option:: -v, --verbose -Shows details about the results of processing environments. Each instance of -``--verbose`` on the command line increases the verbosity level by one, so if -you need more details on the output, specify it twice. +Shows detailed information when processing environments. -There 3 levels of verbosity: - -1. ``-v`` - output errors only -2. ``-vv`` - output errors and warnings -3. ``-vvv`` - output errors, warnings and additional information - -By default, verbosity level is set to 3 (maximum information). +This option can be set globally using :ref:`setting_force_verbose` setting +or by environment variable :envvar:`PLATFORMIO_SETTING_FORCE_VERBOSE`. .. option:: --disable-auto-clean @@ -103,17 +96,34 @@ Examples .. code-block:: bash $ platformio run - Processing arduino_pro5v environment: - scons: `.pioenvs/arduino_pro5v/firmware.elf' is up to date. - scons: `.pioenvs/arduino_pro5v/firmware.hex' is up to date. + [Sun Jul 17 00:09:16 2016] Processing uno (platform: atmelavr, board: uno, framework: arduino) + ----------------------------------------------------------------------------------------------- + Looking for dependencies... + Collecting 32 compatible libraries + Processing src/main.cpp + Processing .pioenvs/uno/libFrameworkArduinoVariant.a + Processing .platformio/packages/framework-arduinoavr/cores/arduino/CDC.cpp + Processing .platformio/packages/framework-arduinoavr/cores/arduino/HardwareSerial.cpp + Processing .platformio/packages/framework-arduinoavr/cores/arduino/HardwareSerial0.cpp + ... + Processing .platformio/packages/framework-arduinoavr/cores/arduino/wiring_analog.c + Processing .platformio/packages/framework-arduinoavr/cores/arduino/wiring_digital.c + Processing .platformio/packages/framework-arduinoavr/cores/arduino/wiring_pulse.c + Processing .platformio/packages/framework-arduinoavr/cores/arduino/wiring_shift.c + Processing .pioenvs/uno/libFrameworkArduino.a + Processing .pioenvs/uno/firmware.elf + Processing .pioenvs/uno/firmware.hex + Processing size + AVR Memory Usage + ---------------- + Device: atmega328p - Processing launchpad_msp430g2 environment: - scons: `.pioenvs/launchpad_msp430g2/firmware.elf' is up to date. - scons: `.pioenvs/launchpad_msp430g2/firmware.hex' is up to date. + Program: 1034 bytes (3.2% Full) + (.text + .data + .bootloader) + + Data: 9 bytes (0.4% Full) + (.data + .bss + .noinit) - Processing launchpad_lm4f120 environment: - scons: `.pioenvs/launchpad_lm4f120/firmware.elf' is up to date. - scons: `.pioenvs/launchpad_lm4f120/firmware.hex' is up to date 2. Process specific environment @@ -121,13 +131,27 @@ Examples .. code-block:: bash $ platformio run -e arduino_pro5v -e launchpad_lm4f120 - Processing arduino_pro5v environment: - scons: `.pioenvs/arduino_pro5v/firmware.elf' is up to date. - scons: `.pioenvs/arduino_pro5v/firmware.hex' is up to date. - - Processing launchpad_lm4f120 environment: - scons: `.pioenvs/launchpad_lm4f120/firmware.elf' is up to date. - scons: `.pioenvs/launchpad_lm4f120/firmware.hex' is up to date. + [Sun Jul 17 00:10:14 2016] Processing nodemcu (platform: espressif, board: nodemcu, framework: arduino) + -------------------------------------------------------------------------------------------------------- + Looking for dependencies... + Collecting 29 compatible libraries + Processing src/main.cpp + Processing .pioenvs/nodemcu/libFrameworkArduinoVariant.a + Processing .platformio/packages/framework-arduinoespressif/cores/esp8266/Esp.cpp + ... + Processing .platformio/packages/framework-arduinoespressif/cores/esp8266/pgmspace.cpp + Processing .platformio/packages/framework-arduinoespressif/cores/esp8266/setjmp.S + Processing .pioenvs/nodemcu/libFrameworkArduino.a + Processing .platformio/packages/framework-arduinoespressif/tools/sdk/lib/libmesh.a + ... + Processing .platformio/packages/framework-arduinoespressif/tools/sdk/lib/libaxtls.a + Processing .platformio/packages/framework-arduinoespressif/tools/sdk/lib/libstdc++.a + Processing .pioenvs/nodemcu/firmware.elf + Processing .platformio/packages/tool-esptool/esptool + Processing .pioenvs/nodemcu/firmware.bin + Processing size + text data bss dec hex filename + 221456 884 29496 251836 3d7bc .pioenvs/nodemcu/firmware.elf 3. Process specific target @@ -135,52 +159,49 @@ Examples .. code-block:: bash $ platformio run -t clean - Processing arduino_pro5v environment: - Removed .pioenvs/arduino_pro5v/src/main.o + [Sun Jul 17 00:19:36 2016] Processing uno (platform: atmelavr, board: uno, framework: arduino) + ---------------------------------------------------------------------------------------------------------------------------------------------------------------- + Looking for dependencies... + Collecting 32 compatible libraries + Removed .pioenvs/uno/FrameworkArduino/CDC.o + Removed .pioenvs/uno/FrameworkArduino/HardwareSerial.o ... - Removed .pioenvs/arduino_pro5v/firmware.hex - - Processing launchpad_msp430g2 environment: - Removed .pioenvs/launchpad_msp430g2/src/main.o - ... - Removed .pioenvs/launchpad_msp430g2/firmware.hex - - Processing launchpad_lm4f120 environment: - Removed .pioenvs/launchpad_lm4f120/src/main.o - ... - Removed .pioenvs/launchpad_lm4f120/firmware.hex + Removed .pioenvs/uno/libFrameworkArduinoVariant.a + Removed .pioenvs/uno/src/main.o + Removed .pioenvs/uno/libFrameworkArduino.a + Removed .pioenvs/uno/firmware.elf + Removed .pioenvs/uno/firmware.hex 4. Mix environments and targets .. code-block:: bash - $ platformio run -e launchpad_msp430g2 -t upload - Processing launchpad_msp430g2 environment: - /Users/ikravets/.platformio/timsp430/tools/mspdebug/mspdebug rf2500 --force-reset "prog .pioenvs/launchpad_msp430g2/firmware.hex" - MSPDebug version 0.20 - debugging tool for MSP430 MCUs - Copyright (C) 2009-2012 Daniel Beer - This is free software; see the source for copying conditions. There is NO - warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - Trying to open interface 1 on 009 - Initializing FET... - FET protocol version is 30394216 - Configured for Spy-Bi-Wire - Sending reset... - Set Vcc: 3000 mV - Device ID: 0x2553 - Code start address: 0xc000 - Code size : 16384 byte = 16 kb - RAM start address: 0x200 - RAM end address: 0x3ff - RAM size : 512 byte = 0 kb - Device: MSP430G2553/G2403 - Code memory starts at 0xc000 - Number of breakpoints: 2 - Chip ID data: 25 53 - Erasing... - Programming... - Writing 646 bytes at c000... - Writing 32 bytes at ffe0... - Done, 678 bytes total + $ platformio run -e teensy31 -t upload + [Sun Jul 17 00:27:14 2016] Processing teensy31 (platform: teensy, board: teensy31, framework: arduino) + ------------------------------------------------------------------------------------------------------- + Looking for dependencies... + Collecting 25 compatible libraries + Processing src/main.cpp + Processing .platformio/packages/framework-arduinoteensy/cores/teensy3/AudioStream.cpp + Processing .platformio/packages/framework-arduinoteensy/cores/teensy3/DMAChannel.cpp + Processing .platformio/packages/framework-arduinoteensy/cores/teensy3/HardwareSerial1.cpp + ... + Processing .platformio/packages/framework-arduinoteensy/cores/teensy3/yield.cpp + Processing .platformio/packages/tool-teensy/teensy_loader_cli + Processing .pioenvs/teensy31/libFrameworkArduino.a + Processing .pioenvs/teensy31/firmware.elf + Check program size... + text data bss dec hex filename + 11080 168 2288 13536 34e0 .pioenvs/teensy31/firmware.elf + Processing .pioenvs/teensy31/firmware.hex + Processing upload + Teensy Loader, Command Line, Version 2.0 + Read ".pioenvs/teensy31/firmware.hex": 11248 bytes, 4.3% usage + Soft reboot is not implemented for OSX + Waiting for Teensy device... + (hint: press the reset button) + Found HalfKay Bootloader + Read ".pioenvs/teensy31/firmware.hex": 11248 bytes, 4.3% usage + Programming........... + Booting diff --git a/docs/userguide/cmd_settings.rst b/docs/userguide/cmd_settings.rst index ff5640d0..24d592d3 100644 --- a/docs/userguide/cmd_settings.rst +++ b/docs/userguide/cmd_settings.rst @@ -87,6 +87,20 @@ Check for the new PlatformIO interval. Check for the platform updates interval. +.. _setting_force_verbose: + +``force_verbose`` +^^^^^^^^^^^^^^^^^ + +:Default: No +:Values: Yes/No + +Force verbose output when processing environments. This setting overrides + +* :option:`platformio run --verbose` +* :option:`platformio ci --verbose` +* :option:`platformio test --verbose` + .. _setting_enable_prompts: ``enable_prompts`` diff --git a/docs/userguide/cmd_test.rst b/docs/userguide/cmd_test.rst index 1a4dba6c..628be957 100644 --- a/docs/userguide/cmd_test.rst +++ b/docs/userguide/cmd_test.rst @@ -85,8 +85,10 @@ to current working directory (``CWD``). .. option:: -v, --verbose -Shows details about the results of processing environments. More details -:option:`platformio run --verbose` +Shows detailed information when processing environments. + +This option can be set globally using :ref:`setting_force_verbose` setting +or by environment variable :envvar:`PLATFORMIO_SETTING_FORCE_VERBOSE`. Examples -------- diff --git a/platformio/__init__.py b/platformio/__init__.py index 28a1507b..4c0361d7 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev7") +VERSION = (3, 0, "0.dev8") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/app.py b/platformio/app.py index f7fcce2a..ab2d71d4 100644 --- a/platformio/app.py +++ b/platformio/app.py @@ -44,6 +44,10 @@ DEFAULT_SETTINGS = { "description": "Automatically update libraries (Yes/No)", "value": False }, + "force_verbose": { + "description": "Force verbose output when processing environments", + "value": False + }, "enable_telemetry": { "description": ( "Telemetry service self._verbose_level: - click.secho(".", fg=fg, err=level < 3, nl=False) - self._last_echo_line = "." - return - - if self._last_echo_line == ".": - click.echo("") - self._last_echo_line = line - - click.secho(line, fg=fg, err=level < 3) + click.secho(line, fg=fg, err=level > 1) @staticmethod def get_job_nums(): @@ -326,13 +310,7 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): self.pm = PackageManager( PACKAGE_DIR, self._manifest.get("packageRepositories")) - self._found_error = False - self._last_echo_line = None - - # 1 = errors - # 2 = 1 + warnings - # 3 = 2 + others - self._verbose_level = 3 + self._verbose = False @property def name(self): From 8eed54ca4582500e30628daa2b1bd001eaa37034 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 17 Jul 2016 16:05:28 +0300 Subject: [PATCH 055/284] Refactor PLATFORM and FRAMEWORK build variables with PIO prefix --- platformio/builder/main.py | 4 ++-- platformio/builder/tools/devplatform.py | 2 +- platformio/builder/tools/piolib.py | 4 ++-- platformio/builder/tools/piomisc.py | 2 +- platformio/builder/tools/piotest.py | 2 +- platformio/builder/tools/pioupload.py | 2 +- platformio/builder/tools/platformio.py | 4 ++-- platformio/commands/run.py | 7 +++++++ platformio/managers/platform.py | 2 +- 9 files changed, 18 insertions(+), 11 deletions(-) diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 3fbb0d58..1f4dd490 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -34,8 +34,8 @@ commonvars.AddVariables( ("EXTRA_SCRIPT",), ("PIOENV",), ("PIOTEST",), - ("PLATFORM",), - ("FRAMEWORK",), + ("PIOPLATFORM",), + ("PIOFRAMEWORK",), # build options ("BUILD_FLAGS",), diff --git a/platformio/builder/tools/devplatform.py b/platformio/builder/tools/devplatform.py index 5004c0c7..deaa017e 100644 --- a/platformio/builder/tools/devplatform.py +++ b/platformio/builder/tools/devplatform.py @@ -29,7 +29,7 @@ def initDevPlatform(name): def DevPlatform(env): variables = {} - for key in ("board", "framework"): + for key in ("board", "pioframework"): if key not in env: continue variables[key] = env[key.upper()] diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 6a06f985..d00f0c08 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -35,7 +35,7 @@ class LibBuilderFactory(object): clsname = "PlatformIOLibBuilder" else: env_frameworks = [ - f.lower().strip() for f in env.get("FRAMEWORK", "").split(",")] + f.lower().strip() for f in env.get("PIOFRAMEWORK", "").split(",")] used_frameworks = LibBuilderFactory.get_used_frameworks(env, path) common_frameworks = set(env_frameworks) & set(used_frameworks) if common_frameworks: @@ -328,7 +328,7 @@ def GetLibBuilders(env): items = [] libs_dirs = [] env_frameworks = [ - f.lower().strip() for f in env.get("FRAMEWORK", "").split(",")] + f.lower().strip() for f in env.get("PIOFRAMEWORK", "").split(",")] for key in ("LIB_EXTRA_DIRS", "LIBSOURCE_DIRS"): for d in env.get(key, []): diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 4280d353..94b2b4d6 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -185,7 +185,7 @@ def DumpIDEData(env): defines.append(env_.subst(item).replace('\\"', '"')) # special symbol for Atmel AVR MCU - if env.subst("$PLATFORM") == "atmelavr": + if env['PIOPLATFORM'] == "atmelavr": defines.append( "__AVR_%s__" % env.BoardConfig().get("build.mcu").upper() .replace("ATMEGA", "ATmega") diff --git a/platformio/builder/tools/piotest.py b/platformio/builder/tools/piotest.py index db1e1886..af820dc4 100644 --- a/platformio/builder/tools/piotest.py +++ b/platformio/builder/tools/piotest.py @@ -122,7 +122,7 @@ void output_complete(void) print("Warning: Could not remove temporary file '%s'. " "Please remove it manually." % file_) - framework = env.subst("$FRAMEWORK").lower() + framework = env.subst("$PIOFRAMEWORK").lower() if framework not in FRAMEWORK_PARAMETERS: env.Exit( "Error: %s framework doesn't support testing feature!" % framework) diff --git a/platformio/builder/tools/pioupload.py b/platformio/builder/tools/pioupload.py index 88b1d4ff..198885cd 100644 --- a/platformio/builder/tools/pioupload.py +++ b/platformio/builder/tools/pioupload.py @@ -114,7 +114,7 @@ def AutodetectUploadPort(*args, **kwargs): # pylint: disable=unused-argument print env.subst("Manually specified: $UPLOAD_PORT") return - if env.subst("$FRAMEWORK") == "mbed": + if env.subst("$PIOFRAMEWORK") == "mbed": env.Replace(UPLOAD_PORT=_look_for_mbed_disk()) else: if (system() == "Linux" and diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 601b43e5..f1963f36 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -53,9 +53,9 @@ def BuildProgram(env): # apply user flags env.ProcessFlags(env.get("BUILD_FLAGS")) - if env.get("FRAMEWORK"): + if env.get("PIOFRAMEWORK"): env.BuildFrameworks([ - f.lower().strip() for f in env.get("FRAMEWORK", "").split(",")]) + f.lower().strip() for f in env['PIOFRAMEWORK'].split(",")]) # restore PIO macros if it was deleted by framework _append_pio_macros() diff --git a/platformio/commands/run.py b/platformio/commands/run.py index a678ceae..f23e35ac 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -97,6 +97,11 @@ def cli(ctx, environment, target, upload_port, # pylint: disable=R0913,R0914 class EnvironmentProcessor(object): + REMAPED_OPTIONS = { + "FRAMEWORK": "PIOFRAMEWORK", + "PLATFORM": "PIOPLATFORM" + } + RENAMED_OPTIONS = { "INSTALL_LIBS": "LIB_INSTALL", "IGNORE_LIBS": "LIB_IGNORE", @@ -158,6 +163,8 @@ class EnvironmentProcessor(object): if self.upload_port: variables['upload_port'] = self.upload_port for k, v in self.options.items(): + if k.upper() in self.REMAPED_OPTIONS: + k = self.REMAPED_OPTIONS[k.upper()] k = k.lower() if k == "targets" or (k == "upload_port" and self.upload_port): continue diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 16cf6c86..d0d83b93 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -440,7 +440,7 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): def configure_default_packages(self, variables, targets): # enbale used frameworks - for framework in variables.get("framework", "").split(","): + for framework in variables.get("pioframework", "").split(","): if not self.frameworks: continue framework = framework.lower().strip() From 49f5c1d0788256d4066b0dd9d7edaea289abbfd4 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 17 Jul 2016 16:19:24 +0300 Subject: [PATCH 056/284] Fix PyLint "line too long" warning --- platformio/builder/tools/piolib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index d00f0c08..56b59458 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -35,7 +35,8 @@ class LibBuilderFactory(object): clsname = "PlatformIOLibBuilder" else: env_frameworks = [ - f.lower().strip() for f in env.get("PIOFRAMEWORK", "").split(",")] + f.lower().strip() + for f in env.get("PIOFRAMEWORK", "").split(",")] used_frameworks = LibBuilderFactory.get_used_frameworks(env, path) common_frameworks = set(env_frameworks) & set(used_frameworks) if common_frameworks: From e264788f8ee94f58819735e2001d83f719eab3ad Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 17 Jul 2016 16:36:05 +0300 Subject: [PATCH 057/284] Fix non renamed PLATFORM variable --- platformio/builder/tools/piolib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 56b59458..082b4a74 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -344,7 +344,7 @@ def GetLibBuilders(env): lb = LibBuilderFactory.new(env, join(libs_dir, item)) if lb.name in env.get("LIB_IGNORE", []): continue - if not lb.is_platform_compatible(env['PLATFORM']): + if not lb.is_platform_compatible(env['PIOPLATFORM']): continue if not any([lb.is_framework_compatible(f) for f in env_frameworks]): From 7b3a235bd7dd89256c66b7ba93742e949bdc15bb Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 17 Jul 2016 19:19:53 +0300 Subject: [PATCH 058/284] Don't duplicate source code to .pioenvs directory --- platformio/builder/tools/platformio.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index f1963f36..66e4893c 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -205,13 +205,13 @@ def MatchSourceFiles(env, src_dir, src_filter=None): return sorted(list(matches)) -def VariantDirWrap(env, variant_dir, src_dir, duplicate=None): +def VariantDirWrap(env, variant_dir, src_dir, duplicate=False): DefaultEnvironment().Append(VARIANT_DIRS=[(variant_dir, src_dir)]) env.VariantDir(variant_dir, src_dir, duplicate) def CollectBuildFiles(env, variant_dir, src_dir, - src_filter=None, duplicate=None): + src_filter=None, duplicate=False): sources = [] variants = [] From f10202c00b845c2c4b1aeceea6b21381c3b34cf3 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 18 Jul 2016 01:38:35 +0300 Subject: [PATCH 059/284] Refactor base package manager; Full VCS support as external package item --- platformio/__init__.py | 2 +- platformio/commands/platform.py | 6 +- platformio/managers/package.py | 707 +++++++++++++++++--------------- platformio/managers/platform.py | 25 +- platformio/vcsclient.py | 94 +++-- 5 files changed, 479 insertions(+), 355 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 4c0361d7..8fb65016 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev8") +VERSION = (3, 0, "0.dev9") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index 5a703fdd..0fdd6d70 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -13,6 +13,7 @@ # limitations under the License. import json +from os.path import basename import click @@ -79,7 +80,10 @@ def platform_install(platforms, with_package, without_package, for platform in platforms: _platform = platform _version = None - if "@" in platform: + if any([s in platform for s in ("\\", "/")]): + _platform = basename(platform) + _version = platform + elif "@" in platform: _platform, _version = platform.rsplit("@", 1) if PlatformManager().install(_platform, _version, with_package, without_package, skip_default_package): diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 79f57416..f0cec055 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import json import os from os.path import dirname, isdir, isfile, islink, join from shutil import copyfile, copytree, rmtree @@ -27,327 +28,6 @@ from platformio.unpacker import FileUnpacker from platformio.vcsclient import VCSClientFactory -class BasePkgManager(object): - - _INSTALLED_CACHE = {} - - def __init__(self, package_dir, repositories=None): - self._INSTALLED_CACHE = {} - self.repositories = repositories - self.package_dir = package_dir - if not isdir(self.package_dir): - os.makedirs(self.package_dir) - assert isdir(self.package_dir) - - @staticmethod - def reset_cache(): - BasePkgManager._INSTALLED_CACHE = {} - - @property - def manifest_name(self): - raise NotImplementedError() - - @staticmethod - def download(url, dest_dir, sha1=None): - fd = FileDownloader(url, dest_dir) - fd.start() - if sha1: - fd.verify(sha1) - return fd.get_filepath() - - @staticmethod - def unpack(source_path, dest_dir): - fu = FileUnpacker(source_path, dest_dir) - return fu.start() - - def check_structure(self, pkg_dir): - if isfile(join(pkg_dir, self.manifest_name)): - return True - - for root, _, files in os.walk(pkg_dir): - if self.manifest_name not in files: - continue - # copy contents to the root of package directory - for item in os.listdir(root): - item_path = join(root, item) - if isfile(item_path): - copyfile(item_path, join(pkg_dir, item)) - elif isdir(item_path): - copytree(item_path, join(pkg_dir, item), symlinks=True) - # remove not used contents - while True: - rmtree(root) - root = dirname(root) - if root == pkg_dir: - break - break - - if isfile(join(pkg_dir, self.manifest_name)): - return True - - raise exception.PlatformioException( - "Could not find '%s' manifest file in the package" % - self.manifest_name) - - @staticmethod - def max_satisfying_repo_version(versions, requirements=None): - item = None - systype = util.get_systype() - if requirements is not None: - requirements = str(requirements) - for v in versions: - if isinstance(v['version'], int): - continue - if v['system'] not in ("all", "*") and systype not in v['system']: - continue - if requirements and not semantic_version.match( - requirements, v['version']): - continue - if item is None or semantic_version.compare( - v['version'], item['version']) == 1: - item = v - return item - - def get_latest_repo_version(self, name, requirements): - version = None - for versions in PackageRepoIterator(name, self.repositories): - pkgdata = self.max_satisfying_repo_version(versions, requirements) - if not pkgdata: - continue - if (not version or semantic_version.compare( - pkgdata['version'], version) == 1): - version = pkgdata['version'] - return version - - def max_satisfying_version(self, name, requirements=None): - best = None - for manifest in self.get_installed(): - if manifest['name'] != name: - continue - elif requirements and not semantic_version.match( - requirements, manifest['version']): - continue - elif (not best or semantic_version.compare( - manifest['version'], best['version']) == 1): - best = manifest - return best - - def get_installed(self): - if self.package_dir in BasePkgManager._INSTALLED_CACHE: - return BasePkgManager._INSTALLED_CACHE[self.package_dir] - items = [] - for p in sorted(os.listdir(self.package_dir)): - manifest_path = join(self.package_dir, p, self.manifest_name) - if not isfile(manifest_path): - continue - manifest = util.load_json(manifest_path) - manifest['_manifest_path'] = manifest_path - assert set(["name", "version"]) <= set(manifest.keys()) - items.append(manifest) - BasePkgManager._INSTALLED_CACHE[self.package_dir] = items - return items - - def is_installed(self, name, requirements=None): - installed = self.get_installed() - if requirements is None: - return any([p['name'] == name for p in installed]) - - for p in installed: - if p['name'] != name: - continue - elif semantic_version.match(requirements, p['version']): - return True - return None - - def install(self, name, requirements, silent=False, trigger_event=True): - installed = self.is_installed(name, requirements) - if not installed or not silent: - click.echo("Installing %s %s @ %s:" % ( - self.manifest_name.split(".")[0], - click.style(name, fg="cyan"), - requirements if requirements else "latest")) - if installed: - if not silent: - click.secho("Already installed", fg="yellow") - return self.max_satisfying_version( - name, requirements).get("_manifest_path") - - if "://" in name: - pkg_dir = self._install_from_url(name, requirements) - else: - pkg_dir = self._install_from_piorepo(name, requirements) - if not pkg_dir or not isfile(join(pkg_dir, self.manifest_name)): - raise exception.PackageInstallError( - name, requirements or "latest", util.get_systype()) - - self.reset_cache() - if trigger_event: - telemetry.on_event( - category=self.__class__.__name__, - action="Install", label=name) - - return join(pkg_dir, self.manifest_name) - - def _install_from_piorepo(self, name, requirements): - pkg_dir = None - pkgdata = None - versions = None - for versions in PackageRepoIterator(name, self.repositories): - pkgdata = self.max_satisfying_repo_version(versions, requirements) - if not pkgdata: - continue - try: - pkg_dir = self._install_from_url( - pkgdata['url'], requirements, pkgdata.get("sha1")) - break - except Exception as e: # pylint: disable=broad-except - click.secho("Warning! Package Mirror: %s" % e, fg="yellow") - click.secho("Looking for another mirror...", fg="yellow") - - if versions is None: - raise exception.UnknownPackage(name) - elif not pkgdata: - if "platform" in self.manifest_name: - raise exception.UndefinedPlatformVersion( - name, requirements or "latest") - else: - raise exception.UndefinedPackageVersion( - name, requirements or "latest", util.get_systype()) - return pkg_dir - - def _install_from_url(self, url, requirements=None, sha1=None): - pkg_dir = None - tmp_dir = mkdtemp("-package", "installing-", self.package_dir) - - # Handle GitHub URL (https://github.com/user/repo.git) - if url.endswith(".git") and not url.startswith("git"): - url = "git+" + url - - try: - if url.startswith("file://"): - rmtree(tmp_dir) - copytree(url[7:], tmp_dir) - elif url.startswith(("http://", "https://", "ftp://")): - dlpath = self.download(url, tmp_dir, sha1) - assert isfile(dlpath) - self.unpack(dlpath, tmp_dir) - os.remove(dlpath) - else: - repo = VCSClientFactory.newClient(url) - repo.export(tmp_dir) - - self.check_structure(tmp_dir) - pkg_dir = self._install_from_tmp_dir(tmp_dir, requirements) - finally: - if isdir(tmp_dir): - rmtree(tmp_dir) - return pkg_dir - - def _install_from_tmp_dir(self, tmp_dir, requirements=None): - tmpmanifest = util.load_json(join(tmp_dir, self.manifest_name)) - assert set(["name", "version"]) <= set(tmpmanifest.keys()) - name = tmpmanifest['name'] - - # package should satisfy requirements - if requirements: - assert semantic_version.match(requirements, tmpmanifest['version']) - - pkg_dir = join(self.package_dir, name) - if isfile(join(pkg_dir, self.manifest_name)): - manifest = util.load_json(join(pkg_dir, self.manifest_name)) - cmp_result = semantic_version.compare( - tmpmanifest['version'], manifest['version']) - if cmp_result == 1: - # if main package version < new package, backup it - os.rename(pkg_dir, join( - self.package_dir, "%s@%s" % (name, manifest['version']))) - elif cmp_result == -1: - pkg_dir = join( - self.package_dir, "%s@%s" % (name, tmpmanifest['version'])) - - # remove previous/not-satisfied package - if isdir(pkg_dir): - rmtree(pkg_dir) - os.rename(tmp_dir, pkg_dir) - assert isdir(pkg_dir) - return pkg_dir - - def uninstall(self, name, requirements=None, trigger_event=True): - click.echo("Uninstalling %s %s @ %s: \t" % ( - self.manifest_name.split(".")[0], - click.style(name, fg="cyan"), - requirements if requirements else "latest"), nl=False) - found = False - for manifest in self.get_installed(): - if manifest['name'] != name: - continue - if (requirements and not semantic_version.match( - requirements, manifest['version'])): - continue - found = True - if isfile(manifest['_manifest_path']): - pkg_dir = dirname(manifest['_manifest_path']) - if islink(pkg_dir): - os.unlink(pkg_dir) - else: - rmtree(pkg_dir) - - if not found: - click.secho("Not installed", fg="yellow") - return False - else: - click.echo("[%s]" % click.style("OK", fg="green")) - - self.reset_cache() - if trigger_event: - telemetry.on_event( - category=self.__class__.__name__, - action="Uninstall", label=name) - - def update(self, name, requirements=None): - click.echo("Updating %s %s @ %s:" % ( - self.manifest_name.split(".")[0], - click.style(name, fg="yellow"), - requirements if requirements else "latest")) - - latest_version = self.get_latest_repo_version(name, requirements) - if latest_version is None: - click.secho("Ignored! '%s' is not listed in repository" % name, - fg="yellow") - return - - current = None - for manifest in self.get_installed(): - if manifest['name'] != name: - continue - if (requirements and not semantic_version.match( - requirements, manifest['version'])): - continue - if (not current or semantic_version.compare( - manifest['version'], current['version']) == 1): - current = manifest - - if current is None: - return - - current_version = current['version'] - click.echo("Versions: Current=%s, Latest=%s \t " % - (current_version, latest_version), nl=False) - - if current_version == latest_version: - click.echo("[%s]" % (click.style("Up-to-date", fg="green"))) - return True - else: - click.echo("[%s]" % (click.style("Out-of-date", fg="red"))) - - self.install(name, latest_version, trigger_event=False) - - telemetry.on_event( - category=self.__class__.__name__, - action="Update", label=name) - return True - - class PackageRepoIterator(object): _MANIFEST_CACHE = {} @@ -389,6 +69,391 @@ class PackageRepoIterator(object): return self.next() +class PkgRepoMixin(object): + + @staticmethod + def max_satisfying_repo_version(versions, requirements=None): + item = None + systype = util.get_systype() + if requirements is not None: + requirements = str(requirements) + for v in versions: + if isinstance(v['version'], int): + continue + if v['system'] not in ("all", "*") and systype not in v['system']: + continue + if requirements and not semantic_version.match( + requirements, v['version']): + continue + if item is None or semantic_version.compare( + v['version'], item['version']) == 1: + item = v + return item + + def get_latest_repo_version(self, name, requirements): + version = None + for versions in PackageRepoIterator(name, self.repositories): + pkgdata = self.max_satisfying_repo_version(versions, requirements) + if not pkgdata: + continue + if (not version or semantic_version.compare( + pkgdata['version'], version) == 1): + version = pkgdata['version'] + return version + + +class PkgInstallerMixin(object): + + VCS_MANIFEST_NAME = ".piopkgmanager.json" + + def get_manifest_path(self, pkg_dir): + if not isdir(pkg_dir): + return None + manifest_path = join(pkg_dir, self.manifest_name) + if isfile(manifest_path): + return manifest_path + for item in os.listdir(pkg_dir): + if not isdir(join(pkg_dir, item)): + continue + if isfile(join(pkg_dir, item, self.VCS_MANIFEST_NAME)): + return join(pkg_dir, item, self.VCS_MANIFEST_NAME) + return None + + def manifest_exists(self, pkg_dir): + return self.get_manifest_path(pkg_dir) is not None + + def load_manifest(self, pkg_dir): + manifest_path = self.get_manifest_path(pkg_dir) + if manifest_path: + manifest = util.load_json(manifest_path) + manifest['_manifest_path'] = manifest_path + manifest['__pkg_dir'] = pkg_dir + return manifest + return None + + def _install_from_piorepo(self, name, requirements): + pkg_dir = None + pkgdata = None + versions = None + for versions in PackageRepoIterator(name, self.repositories): + pkgdata = self.max_satisfying_repo_version(versions, requirements) + if not pkgdata: + continue + try: + pkg_dir = self._install_from_url( + name, pkgdata['url'], requirements, pkgdata.get("sha1")) + break + except Exception as e: # pylint: disable=broad-except + click.secho("Warning! Package Mirror: %s" % e, fg="yellow") + click.secho("Looking for another mirror...", fg="yellow") + + if versions is None: + raise exception.UnknownPackage(name) + elif not pkgdata: + if "platform" in self.manifest_name: + raise exception.UndefinedPlatformVersion( + name, requirements or "latest") + else: + raise exception.UndefinedPackageVersion( + name, requirements or "latest", util.get_systype()) + return pkg_dir + + def _install_from_url(self, name, url, requirements=None, sha1=None): + pkg_dir = None + tmp_dir = mkdtemp("-package", "installing-", self.package_dir) + + # Handle GitHub URL (https://github.com/user/repo.git) + if url.endswith(".git") and not url.startswith("git"): + url = "git+" + url + + try: + if url.startswith("file://"): + url = url[7:] + if isfile(url): + self.unpack(url, tmp_dir) + else: + rmtree(tmp_dir) + copytree(url, tmp_dir) + elif url.startswith(("http://", "https://", "ftp://")): + dlpath = self.download(url, tmp_dir, sha1) + assert isfile(dlpath) + self.unpack(dlpath, tmp_dir) + os.remove(dlpath) + else: + vcs = VCSClientFactory.newClient(tmp_dir, url) + assert vcs.export() + with open(join(vcs.storage_dir, + self.VCS_MANIFEST_NAME), "w") as fp: + json.dump({ + "name": name, + "version": "0.0.0+rev%s" % vcs.get_latest_revision(), + "url": url}, fp) + + self._check_pkg_structure(tmp_dir) + pkg_dir = self._install_from_tmp_dir(tmp_dir, requirements) + finally: + if isdir(tmp_dir): + rmtree(tmp_dir) + return pkg_dir + + def _check_pkg_structure(self, pkg_dir): + if self.manifest_exists(pkg_dir): + return True + + for root, _, _ in os.walk(pkg_dir): + if not self.manifest_exists(root): + continue + # copy contents to the root of package directory + for item in os.listdir(root): + item_path = join(root, item) + if isfile(item_path): + copyfile(item_path, join(pkg_dir, item)) + elif isdir(item_path): + copytree(item_path, join(pkg_dir, item), symlinks=True) + # remove not used contents + while True: + rmtree(root) + root = dirname(root) + if root == pkg_dir: + break + break + + if self.manifest_exists(pkg_dir): + return True + + raise exception.PlatformioException( + "Could not find '%s' manifest file in the package" % + self.manifest_name) + + def _install_from_tmp_dir(self, tmp_dir, requirements=None): + tmpmanifest = self.load_manifest(tmp_dir) + assert set(["name", "version"]) <= set(tmpmanifest.keys()) + name = tmpmanifest['name'] + pkg_dir = join(self.package_dir, name) + + # package should satisfy requirements + if requirements: + assert semantic_version.match( + requirements, tmpmanifest['version']) + + if self.manifest_exists(pkg_dir): + manifest = self.load_manifest(pkg_dir) + cmp_result = semantic_version.compare( + tmpmanifest['version'], manifest['version']) + if cmp_result == 1: + # if main package version < new package, backup it + os.rename(pkg_dir, join( + self.package_dir, "%s@%s" % (name, manifest['version']))) + elif cmp_result == -1: + pkg_dir = join( + self.package_dir, "%s@%s" % (name, tmpmanifest['version'])) + + # remove previous/not-satisfied package + if isdir(pkg_dir): + rmtree(pkg_dir) + os.rename(tmp_dir, pkg_dir) + assert isdir(pkg_dir) + return pkg_dir + + +class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): + + _INSTALLED_CACHE = {} + + def __init__(self, package_dir, repositories=None): + self._INSTALLED_CACHE = {} + self.repositories = repositories + self.package_dir = package_dir + if not isdir(self.package_dir): + os.makedirs(self.package_dir) + assert isdir(self.package_dir) + + @property + def manifest_name(self): + raise NotImplementedError() + + @staticmethod + def reset_cache(): + BasePkgManager._INSTALLED_CACHE = {} + + @staticmethod + def download(url, dest_dir, sha1=None): + fd = FileDownloader(url, dest_dir) + fd.start() + if sha1: + fd.verify(sha1) + return fd.get_filepath() + + @staticmethod + def unpack(source_path, dest_dir): + fu = FileUnpacker(source_path, dest_dir) + return fu.start() + + def print_message(self, message, nl=True): + click.echo("%s: %s" % (self.__class__.__name__, message), nl=nl) + + def get_installed(self): + if self.package_dir in BasePkgManager._INSTALLED_CACHE: + return BasePkgManager._INSTALLED_CACHE[self.package_dir] + items = [] + for p in sorted(os.listdir(self.package_dir)): + manifest = self.load_manifest(join(self.package_dir, p)) + if not manifest: + continue + assert set(["name", "version"]) <= set(manifest.keys()) + items.append(manifest) + BasePkgManager._INSTALLED_CACHE[self.package_dir] = items + return items + + def is_installed(self, name, requirements=None): + installed = self.get_installed() + reqspec = None + if requirements: + try: + reqspec = semantic_version.Spec(requirements) + except ValueError: + pass + + if not reqspec: + return any([p['name'] == name for p in installed]) + + for p in installed: + if p['name'] != name: + continue + elif reqspec.match(semantic_version.Version(p['version'])): + return True + return None + + def max_installed_version(self, name, requirements=None): + best = None + reqspec = None + if requirements: + try: + reqspec = semantic_version.Spec(requirements) + except ValueError: + pass + + for manifest in self.get_installed(): + if manifest['name'] != name: + continue + elif reqspec and not reqspec.match( + semantic_version.Version(manifest['version'])): + continue + elif (not best or semantic_version.compare( + manifest['version'], best['version']) == 1): + best = manifest + + if best: + return best.get("__pkg_dir") + return None + + def install(self, name, requirements, silent=False, trigger_event=True): + installed = self.is_installed(name, requirements) + if not installed or not silent: + self.print_message("Installing %s @ %s:" % ( + click.style(name, fg="cyan"), + requirements if requirements else "latest")) + if installed: + if not silent: + click.secho("Already installed", fg="yellow") + return self.max_installed_version( + name, requirements) + + if (requirements and any([s in requirements for s in ("\\", "/")]) and + "://" not in requirements and ( + isfile(requirements) or isdir(requirements))): + requirements = "file://" + requirements + + if requirements and "://" in requirements: + pkg_dir = self._install_from_url(name, requirements) + else: + pkg_dir = self._install_from_piorepo(name, requirements) + if not pkg_dir or not self.manifest_exists(pkg_dir): + raise exception.PackageInstallError( + name, requirements or "latest", util.get_systype()) + + self.reset_cache() + if trigger_event: + telemetry.on_event( + category=self.__class__.__name__, + action="Install", label=name) + + return pkg_dir + + def uninstall(self, name, requirements=None, trigger_event=True): + self.print_message("Uninstalling %s @ %s: \t" % ( + click.style(name, fg="cyan"), + requirements if requirements else "latest"), nl=False) + found = False + for manifest in self.get_installed(): + if manifest['name'] != name: + continue + if (requirements and not semantic_version.match( + requirements, manifest['version'])): + continue + found = True + if isdir(manifest['__pkg_dir']): + if islink(manifest['__pkg_dir']): + os.unlink(manifest['__pkg_dir']) + else: + rmtree(manifest['__pkg_dir']) + + if not found: + click.secho("Not installed", fg="yellow") + return False + else: + click.echo("[%s]" % click.style("OK", fg="green")) + + self.reset_cache() + if trigger_event: + telemetry.on_event( + category=self.__class__.__name__, + action="Uninstall", label=name) + + def update(self, name, requirements=None): + self.print_message("Updating %s @ %s:" % ( + click.style(name, fg="yellow"), + requirements if requirements else "latest")) + + latest_version = self.get_latest_repo_version(name, requirements) + if latest_version is None: + click.secho( + "Ignored! '%s' is not listed in registry" % name, + fg="yellow") + return + + current = None + for manifest in self.get_installed(): + if manifest['name'] != name: + continue + if (requirements and not semantic_version.match( + requirements, manifest['version'])): + continue + if (not current or semantic_version.compare( + manifest['version'], current['version']) == 1): + current = manifest + + if current is None: + return + + current_version = current['version'] + click.echo("Versions: Current=%s, Latest=%s \t " % + (current_version, latest_version), nl=False) + + if current_version == latest_version: + click.echo("[%s]" % (click.style("Up-to-date", fg="green"))) + return True + else: + click.echo("[%s]" % (click.style("Out-of-date", fg="red"))) + + self.install(name, latest_version, trigger_event=False) + + telemetry.on_event( + category=self.__class__.__name__, + action="Update", label=name) + return True + + class PackageManager(BasePkgManager): @property diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index d0d83b93..83402f0f 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -45,8 +45,8 @@ class PlatformManager(BasePkgManager): def install(self, # pylint: disable=too-many-arguments,arguments-differ name, requirements=None, with_packages=None, without_packages=None, skip_default_packages=False): - manifest_path = BasePkgManager.install(self, name, requirements) - p = PlatformFactory.newPlatform(manifest_path, requirements) + platform_dir = BasePkgManager.install(self, name, requirements) + p = PlatformFactory.newPlatform(self.get_manifest_path(platform_dir)) p.install_packages( with_packages, without_packages, skip_default_packages) self.cleanup_packages(p.packages.keys()) @@ -99,7 +99,8 @@ class PlatformManager(BasePkgManager): def get_installed_boards(self): boards = [] for manifest in self.get_installed(): - p = PlatformFactory.newPlatform(manifest['_manifest_path']) + p = PlatformFactory.newPlatform( + self.get_manifest_path(manifest['__pkg_dir'])) for config in p.get_boards().values(): boards.append(config.get_brief_data()) return boards @@ -138,10 +139,8 @@ class PlatformFactory(object): platform_dir = dirname(name) name = util.load_json(name)['name'] else: - _manifest = PlatformManager().max_satisfying_version( + platform_dir = PlatformManager().max_installed_version( name, requirements) - if _manifest: - platform_dir = dirname(_manifest['_manifest_path']) if not platform_dir: raise exception.UnknownPlatform( @@ -169,9 +168,17 @@ class PlatformPackagesMixin(object): installed = self.pm.get_installed() for name, opts in self.packages.items(): manifest = None + reqspec = None + try: + reqspec = semantic_version.Spec(opts['version']) + except ValueError: + pass + for p in installed: - if (p['name'] != name or not semantic_version.match( - opts['version'], p['version'])): + if p['name'] != name: + continue + if reqspec and not reqspec.match( + semantic_version.Version(p['version'])): continue elif (not manifest or semantic_version.compare( p['version'], manifest['version']) == 1): @@ -413,7 +420,7 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): packages = self.get_installed_packages() if name not in packages: return None - return dirname(packages[name]['_manifest_path']) + return packages[name]['__pkg_dir'] def get_package_version(self, name): packages = self.get_installed_packages() diff --git a/platformio/vcsclient.py b/platformio/vcsclient.py index 612f287a..f915e0e3 100644 --- a/platformio/vcsclient.py +++ b/platformio/vcsclient.py @@ -12,25 +12,42 @@ # See the License for the specific language governing permissions and # limitations under the License. +from os import listdir +from os.path import isdir, join from platform import system from subprocess import check_call from sys import modules from urlparse import urlsplit, urlunsplit +from platformio import util from platformio.exception import PlatformioException class VCSClientFactory(object): @staticmethod - def newClient(url): - scheme, netloc, path, query, fragment = urlsplit(url) - type_ = scheme - if "+" in type_: - type_, scheme = type_.split("+", 1) - url = urlunsplit((scheme, netloc, path, query, None)) - clsname = "%sClient" % type_.title() - obj = getattr(modules[__name__], clsname)(url, fragment) + def newClient(src_dir, remote_url=None, branch=None): + clsnametpl = "%sClient" + vcscls = None + type_ = None + if remote_url: + scheme, netloc, path, query, branch = urlsplit(remote_url) + type_ = scheme + if "+" in type_: + type_, scheme = type_.split("+", 1) + remote_url = urlunsplit((scheme, netloc, path, query, None)) + vcscls = getattr(modules[__name__], clsnametpl % type_.title()) + elif isdir(src_dir): + for item in listdir(src_dir): + if not isdir(join(src_dir, item)) or not item.startswith("."): + continue + try: + vcscls = getattr( + modules[__name__], clsnametpl % item[1:].title()) + except AttributeError: + pass + assert vcscls + obj = vcscls(src_dir, remote_url, branch) assert isinstance(obj, VCSClientBase) return obj @@ -39,59 +56,90 @@ class VCSClientBase(object): command = None - def __init__(self, url, branch=None): - self.url = url + def __init__(self, src_dir, remote_url=None, branch=None): + self.src_dir = src_dir + self.remote_url = remote_url self.branch = branch self.check_client() def check_client(self): try: assert self.command - assert self.run_cmd(["--version"]) == 0 + assert self.run_cmd(["--version"]) except (AssertionError, OSError): raise PlatformioException( "VCS: `%s` client is not installed in your system" % self.command) return True - def export(self, dst_dir): + @property + def storage_dir(self): + return join(self.src_dir, "." + self.command) + + def export(self): raise NotImplementedError - def run_cmd(self, args): - return check_call([self.command] + args, shell=system() == "Windows") + def get_latest_revision(self): + raise NotImplementedError + + def run_cmd(self, args, **kwargs): + args = [self.command] + args + kwargs['shell'] = system() == "Windows" + return check_call(args, **kwargs) == 0 + + def get_cmd_output(self, args, **kwargs): + args = [self.command] + args + result = util.exec_command(args, **kwargs) + if result['returncode'] == 0: + return result['out'] + raise PlatformioException( + "VCS: Could not receive an output from `%s` command (%s)" % ( + args, result)) class GitClient(VCSClientBase): command = "git" - def export(self, dst_dir): + def export(self): args = ["clone", "--recursive", "--depth", "1"] if self.branch: args.extend(["--branch", self.branch]) - args.extend([self.url, dst_dir]) - self.run_cmd(args) + args.extend([self.remote_url, self.src_dir]) + return self.run_cmd(args) + + def get_latest_revision(self): + return self.get_cmd_output(["rev-parse", "--short", "HEAD"], + cwd=self.src_dir).strip() class HgClient(VCSClientBase): command = "hg" - def export(self, dst_dir): + def export(self): args = ["clone"] if self.branch: args.extend(["--updaterev", self.branch]) - args.extend([self.url, dst_dir]) - self.run_cmd(args) + args.extend([self.remote_url, self.src_dir]) + return self.run_cmd(args) + + def get_latest_revision(self): + return self.get_cmd_output(["identify", "--id"], + cwd=self.src_dir).strip() class SvnClient(VCSClientBase): command = "svn" - def export(self, dst_dir): + def export(self): args = ["export", "--force"] if self.branch: args.extend(["--revision", self.branch]) - args.extend([self.url, dst_dir]) - self.run_cmd(args) + args.extend([self.remote_url, self.src_dir]) + return self.run_cmd(args) + + def get_latest_revision(self): + return self.get_cmd_output(["info", "-r", "HEAD"], + cwd=self.src_dir).strip() From 5b68d34764f7ce347a5c4a21451109d91f076feb Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 18 Jul 2016 15:36:08 +0300 Subject: [PATCH 060/284] Allow to load PlatformIO project using passed directory --- platformio/commands/init.py | 28 +++++++++++++--------------- platformio/commands/run.py | 21 ++++++++++----------- platformio/commands/test.py | 2 +- platformio/ide/projectgenerator.py | 19 +++++++++---------- platformio/util.py | 21 ++++++++++++++------- 5 files changed, 47 insertions(+), 44 deletions(-) diff --git a/platformio/commands/init.py b/platformio/commands/init.py index 3cdec20c..ca429aa0 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -84,7 +84,7 @@ def cli(ctx, project_dir, board, ide, # pylint: disable=R0913 if board: fill_project_envs( - ctx, join(project_dir, "platformio.ini"), board, + ctx, project_dir, board, enable_auto_uploading, env_prefix, ide is not None ) @@ -121,25 +121,23 @@ def cli(ctx, project_dir, board, ide, # pylint: disable=R0913 def get_first_board(project_dir): - with util.cd(project_dir): - config = util.get_project_config() - for section in config.sections(): - if not section.startswith("env:"): - continue - elif config.has_option(section, "board"): - return config.get(section, "board") + config = util.load_project_config(project_dir) + for section in config.sections(): + if not section.startswith("env:"): + continue + elif config.has_option(section, "board"): + return config.get(section, "board") return None def init_base_project(project_dir): - platformio_ini = join(project_dir, "platformio.ini") - if not isfile(platformio_ini): + if not util.is_platformio_project(project_dir): copyfile(join(util.get_source_dir(), "projectconftpl.ini"), - platformio_ini) + join(project_dir, "platformio.ini")) lib_dir = join(project_dir, "lib") src_dir = join(project_dir, "src") - config = util.get_project_config(platformio_ini) + config = util.load_project_config(project_dir) if config.has_option("platformio", "src_dir"): src_dir = join(project_dir, config.get("platformio", "src_dir")) @@ -277,14 +275,14 @@ def init_cvs_ignore(project_dir): def fill_project_envs( # pylint: disable=too-many-arguments,too-many-locals - ctx, platformio_ini, board_ids, enable_auto_uploading, + ctx, project_dir, board_ids, enable_auto_uploading, env_prefix, force_download): installed_boards = PlatformManager().get_installed_boards() content = [] used_boards = [] used_platforms = [] - config = util.get_project_config(platformio_ini) + config = util.load_project_config(project_dir) for section in config.sections(): if not all([section.startswith("env:"), config.has_option(section, "board")]): @@ -324,7 +322,7 @@ def fill_project_envs( # pylint: disable=too-many-arguments,too-many-locals if not content: return - with open(platformio_ini, "a") as f: + with open(join(project_dir, "platformio.ini"), "a") as f: content.append("") f.write("\n".join(content)) diff --git a/platformio/commands/run.py b/platformio/commands/run.py index f23e35ac..910c15c0 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -55,7 +55,7 @@ def cli(ctx, environment, target, upload_port, # pylint: disable=R0913,R0914 fg="yellow" ) - config = util.get_project_config() + config = util.load_project_config() env_default = None if config.has_option("platformio", "env_default"): env_default = [ @@ -257,18 +257,17 @@ def print_header(label, is_error=False): def check_project_envs(project_dir, environments): - with util.cd(project_dir): - config = util.get_project_config() + config = util.load_project_config(project_dir) - if not config.sections(): - raise exception.ProjectEnvsNotAvailable() + 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)) + 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 diff --git a/platformio/commands/test.py b/platformio/commands/test.py index 7dcc0060..35b7fe97 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -44,7 +44,7 @@ def cli(ctx, environment, skip, upload_port, project_dir, verbose): if not isdir(test_dir): raise exception.TestDirEmpty(test_dir) test_names = get_test_names(test_dir) - projectconf = util.get_project_config() + projectconf = util.load_project_config() click.echo("Collected %d items" % len(test_names)) click.echo() diff --git a/platformio/ide/projectgenerator.py b/platformio/ide/projectgenerator.py index 4c0a4365..f59ed98b 100644 --- a/platformio/ide/projectgenerator.py +++ b/platformio/ide/projectgenerator.py @@ -46,16 +46,15 @@ class ProjectGenerator(object): @util.memoized def get_project_env(self): data = {"env_name": "PlatformIO"} - with util.cd(self.project_dir): - config = util.get_project_config() - for section in config.sections(): - if not section.startswith("env:"): - continue - data = {"env_name": section[4:]} - for k, v in config.items(section): - data[k] = v - if self.board == data.get("board"): - break + config = util.load_project_config(self.project_dir) + for section in config.sections(): + if not section.startswith("env:"): + continue + data = {"env_name": section[4:]} + for k, v in config.items(section): + data[k] = v + if self.board == data.get("board"): + break return data @util.memoized diff --git a/platformio/util.py b/platformio/util.py index 0e5271d0..ff1fc5b3 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -81,6 +81,7 @@ class cd(object): class memoized(object): + ''' Decorator. Caches a function's return value each time it is called. If called later with the same arguments, the cached value is returned @@ -148,7 +149,7 @@ def _get_projconf_option_dir(name, default=None): return os.getenv(_env_name) try: - config = get_project_config() + config = load_project_config() if (config.has_section("platformio") and config.has_option("platformio", name)): option_dir = config.get("platformio", name) @@ -232,16 +233,22 @@ def get_projectdata_dir(): ) -def get_project_config(ini_path=None): - if not ini_path: - ini_path = join(get_project_dir(), "platformio.ini") - if not isfile(ini_path): - raise exception.NotPlatformProject(get_project_dir()) +def load_project_config(project_dir=None): + if not project_dir: + project_dir = get_project_dir() + if not is_platformio_project(project_dir): + raise exception.NotPlatformProject(project_dir) cp = ConfigParser() - cp.read(ini_path) + cp.read(join(project_dir, "platformio.ini")) return cp +def is_platformio_project(project_dir=None): + if not project_dir: + project_dir = get_project_dir() + return isfile(join(project_dir, "platformio.ini")) + + def change_filemtime(path, time): os.utime(path, (time, time)) From 1127914512304fd0dbfb5ace37843c93a1df6dd8 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 18 Jul 2016 15:47:38 +0300 Subject: [PATCH 061/284] Fix broken import --- tests/commands/test_init.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/commands/test_init.py b/tests/commands/test_init.py index b702e323..817e0cbb 100644 --- a/tests/commands/test_init.py +++ b/tests/commands/test_init.py @@ -62,7 +62,7 @@ def test_init_special_board(platformio_setup, clirunner, validate_cliresult): validate_cliresult(result) boards = json.loads(result.output) - config = util.get_project_config() + config = util.load_project_config() expected_result = [ ("platform", str(boards[0]['platform'])), ("framework", str(boards[0]['frameworks'][0])), @@ -81,7 +81,7 @@ def test_init_enable_auto_uploading(platformio_setup, clirunner, ["-b", "uno", "--enable-auto-uploading"]) validate_cliresult(result) validate_pioproject(getcwd()) - config = util.get_project_config() + config = util.load_project_config() expected_result = [ ("platform", "atmelavr"), ("framework", "arduino"), From 30733e837677b941c54806aae8b850b21f8ec006 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 19 Jul 2016 23:49:50 +0300 Subject: [PATCH 062/284] Improve package caching for PkgManager --- platformio/managers/package.py | 9 ++++----- platformio/managers/platform.py | 16 ++++++++-------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/platformio/managers/package.py b/platformio/managers/package.py index f0cec055..352c0d00 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -261,7 +261,6 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): _INSTALLED_CACHE = {} def __init__(self, package_dir, repositories=None): - self._INSTALLED_CACHE = {} self.repositories = repositories self.package_dir = package_dir if not isdir(self.package_dir): @@ -272,10 +271,6 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): def manifest_name(self): raise NotImplementedError() - @staticmethod - def reset_cache(): - BasePkgManager._INSTALLED_CACHE = {} - @staticmethod def download(url, dest_dir, sha1=None): fd = FileDownloader(url, dest_dir) @@ -289,6 +284,10 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): fu = FileUnpacker(source_path, dest_dir) return fu.start() + def reset_cache(self): + if self.package_dir in BasePkgManager._INSTALLED_CACHE: + del BasePkgManager._INSTALLED_CACHE[self.package_dir] + def print_message(self, message, nl=True): click.echo("%s: %s" % (self.__class__.__name__, message), nl=nl) diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 83402f0f..db7ea51a 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -26,17 +26,17 @@ import semantic_version from platformio import app, exception, util from platformio.managers.package import BasePkgManager, PackageManager -PACKAGE_DIR = join(util.get_home_dir(), "packages") +PLATFORMS_DIR = join(util.get_home_dir(), "platforms") +PACKAGES_DIR = join(util.get_home_dir(), "packages") class PlatformManager(BasePkgManager): - def __init__(self): + def __init__(self, package_dir=None, repositories=None): + if not repositories: + repositories = ["http://dl.platformio.org/platforms/manifest.json"] BasePkgManager.__init__( - self, - join(util.get_home_dir(), "platforms"), - ["http://dl.platformio.org/platforms/manifest.json"] - ) + self, package_dir or PLATFORMS_DIR, repositories) @property def manifest_name(self): @@ -84,7 +84,7 @@ class PlatformManager(BasePkgManager): deppkgs[pkgname] = set() deppkgs[pkgname].add(pkgmanifest['version']) - pm = PackageManager(PACKAGE_DIR) + pm = PackageManager(PACKAGES_DIR) for manifest in pm.get_installed(): if manifest['name'] not in names: continue @@ -315,7 +315,7 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): self._manifest = util.load_json(manifest_path) self.pm = PackageManager( - PACKAGE_DIR, self._manifest.get("packageRepositories")) + PACKAGES_DIR, self._manifest.get("packageRepositories")) self._verbose = False From 1738f44847053c05c76758241fdd7b76babbbc4b Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 19 Jul 2016 23:51:22 +0300 Subject: [PATCH 063/284] Simplify platformio.ini default template --- platformio/projectconftpl.ini | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/platformio/projectconftpl.ini b/platformio/projectconftpl.ini index da48cf88..8e3b9e7d 100644 --- a/platformio/projectconftpl.ini +++ b/platformio/projectconftpl.ini @@ -1,18 +1,6 @@ # -# Project Configuration File +# PlatformIO Project Configuration File # -# A detailed documentation with the EXAMPLES is located here: +# Please check documentation with examples # http://docs.platformio.org/en/latest/projectconf.html # - -# A sign `#` at the beginning of the line indicates a comment -# Comment lines are ignored. - -# Simple and base environment -# [env:mybaseenv] -# platform = %INSTALLED_PLATFORM_NAME_HERE% -# framework = -# board = -# -# Automatic targets - enable auto-uploading -# targets = upload From 6900052ecd67e5d97c7203ec0c56646f7eee1155 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 22 Jul 2016 18:02:04 +0300 Subject: [PATCH 064/284] Reorder command options --- platformio/commands/__init__.py | 2 +- platformio/commands/ci.py | 6 +++--- platformio/commands/init.py | 2 +- platformio/commands/platform.py | 4 ++-- platformio/commands/run.py | 10 +++++----- platformio/commands/test.py | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/platformio/commands/__init__.py b/platformio/commands/__init__.py index 0c05c3b0..5466a0e8 100644 --- a/platformio/commands/__init__.py +++ b/platformio/commands/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index 1df83ba8..b7b1fe32 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -53,9 +53,9 @@ def validate_path(ctx, param, value): # pylint: disable=W0613 @click.command("ci", short_help="Continuous Integration") @click.argument("src", nargs=-1, callback=validate_path) -@click.option("--lib", "-l", multiple=True, callback=validate_path) +@click.option("-l", "--lib", multiple=True, callback=validate_path) @click.option("--exclude", multiple=True) -@click.option("--board", "-b", multiple=True, metavar="ID", +@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, @@ -64,7 +64,7 @@ def validate_path(ctx, param, value): # pylint: disable=W0613 @click.option("--project-conf", type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True, resolve_path=True)) -@click.option("--verbose", "-v", is_flag=True) +@click.option("-v", "--verbose", is_flag=True) @click.pass_context def cli(ctx, src, lib, exclude, board, # pylint: disable=R0913 build_dir, keep_build_dir, project_conf, verbose): diff --git a/platformio/commands/init.py b/platformio/commands/init.py index ca429aa0..a7e3d750 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -46,7 +46,7 @@ def validate_boards(ctx, param, value): # pylint: disable=W0613 @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("--board", "-b", multiple=True, metavar="ID", +@click.option("-b", "--board", multiple=True, metavar="ID", callback=validate_boards) @click.option("--ide", type=click.Choice(ProjectGenerator.get_supported_ides())) diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index 0fdd6d70..eb81ddac 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -72,8 +72,8 @@ def platform_search(query, json_output): @cli.command("install", short_help="Install new platforms") @click.argument("platforms", nargs=-1, required=True) -@click.option("--with-package", multiple=True, metavar="") -@click.option("--without-package", multiple=True, metavar="") +@click.option("--with-package", multiple=True) +@click.option("--without-package", multiple=True) @click.option("--skip-default-package", is_flag=True) def platform_install(platforms, with_package, without_package, skip_default_package): diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 910c15c0..9aaa9912 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -30,13 +30,13 @@ from platformio.managers.platform import PlatformFactory @click.command("run", short_help="Process project environments") -@click.option("--environment", "-e", multiple=True, metavar="") -@click.option("--target", "-t", multiple=True, metavar="") -@click.option("--upload-port", metavar="") -@click.option("--project-dir", "-d", default=getcwd, +@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=False, dir_okay=True, writable=True, resolve_path=True)) -@click.option("--verbose", "-v", 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, # pylint: disable=R0913,R0914 diff --git a/platformio/commands/test.py b/platformio/commands/test.py index 35b7fe97..55ea49df 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -32,7 +32,7 @@ from platformio.managers.platform import PlatformFactory @click.option("--environment", "-e", multiple=True, metavar="") @click.option("--skip", multiple=True, metavar="") @click.option("--upload-port", metavar="") -@click.option("--project-dir", "-d", default=getcwd, +@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("--verbose", "-v", is_flag=True) From fc9c66b0c38f48fc54450c43c9e3a14a2b1ee4a1 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 22 Jul 2016 18:03:35 +0300 Subject: [PATCH 065/284] Update examples --- examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples b/examples index a657ca42..3b8f997b 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit a657ca4225f55af7239b89486350c9f02bb3ee93 +Subproject commit 3b8f997b6e69879f1b935087e988290046a3fc84 From 2892cb8c2f54bc52adf525e617099ce8b0e59538 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 22 Jul 2016 18:16:26 +0300 Subject: [PATCH 066/284] Fix cmd_init test --- tests/commands/test_init.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/commands/test_init.py b/tests/commands/test_init.py index 817e0cbb..45c23ed5 100644 --- a/tests/commands/test_init.py +++ b/tests/commands/test_init.py @@ -96,5 +96,5 @@ def test_init_enable_auto_uploading(platformio_setup, clirunner, def test_init_incorrect_board(clirunner): result = clirunner.invoke(cli, ["-b", "missed_board"]) assert result.exit_code == 2 - assert 'Error: Invalid value for "--board" / "-b"' in result.output + assert 'Error: Invalid value for "-b" / "--board' in result.output assert isinstance(result.exception, SystemExit) From 01c0b45ea22ed98cf2ee0680344a2b1a2e375222 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 24 Jul 2016 18:17:23 +0300 Subject: [PATCH 067/284] Introduce "lib_compat_level" option for project configuration file --- HISTORY.rst | 7 ++- docs/faq.rst | 27 ++++++++++++ docs/projectconf.rst | 70 ++++++++++++++++++++++++------ platformio/__init__.py | 2 +- platformio/builder/main.py | 2 + platformio/builder/tools/piolib.py | 37 +++++++++------- 6 files changed, 114 insertions(+), 31 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index fd52b09a..084ce934 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -14,8 +14,11 @@ PlatformIO 3.0 * Unit Testing for Embedded (`docs `__) (`issue #408 `_) * New Library Build System: intelligent dependency finder that interprets - C Preprocessor conditional macros, `library deep search `__, support for the 3rd party - manifests (Arduino IDE ``library.properties``, ARM mbed ``module.json``) + C Preprocessor conditional macros, + `library deep search `__, + `library compatibility level `__, + support for the 3rd party manifests (Arduino IDE ``library.properties``, + ARM mbed ``module.json``) (`issue #432 `_) * New `lib_extra_dirs `__ option for project environment. Multiple custom library locations! diff --git a/docs/faq.rst b/docs/faq.rst index 75ed3cfb..18605764 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -33,6 +33,33 @@ What is ``.pioenvs`` directory Please refer to :ref:`projectconf_pio_envs_dir`. +.. _faq_ldf: + +How works Library Dependency Finder (LDF) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Library Dependency Finder is a part of PlatformIO Library Build System. It +operates with the header files (``*.h, *.hpp``) and looks for +``#include <...>`` directives. What is more, LDF interprets C Preprocessor +conditional macros (``#ifdef ...``, etc.). Library Dependency Finder starts +work from analyzing source files from :ref:`projectconf_pio_src_dir`. It +understands "nested includes/chain" by default if they depend on each other. + +There are different library storages where Library Dependency Finder looks for +dependencies. These storages/folders have priority. LDF operates in the next +order: + +1. :ref:`projectconf_lib_extra_dirs` +2. :ref:`projectconf_pio_lib_dir` +3. :ref:`projectconf_pio_home_dir`/lib + +Library Dependency Finder has a few key factors from :ref:`projectconf`: + +* :ref:`projectconf_lib_ignore` +* :ref:`projectconf_lib_deep_search` +* :ref:`projectconf_lib_extra_dirs` +* :ref:`projectconf_lib_compat_level` + Command completion in Terminal ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 17e0bf23..aef7c784 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -606,10 +606,15 @@ Example: ``lib_force`` ^^^^^^^^^^^^^ -Force Library Build System to build specified libraries if even they are not +Force Library Build System to build specified libraries if they even are not included in the project source code. Also, these libraries will be processed in the first order. +The correct value for this option is library name (not +folder name). In the most cases, library name is pre-defined in manifest file +(:ref:`library_config`, ``library.properties``, ``module.json``). The multiple +library names are allowed, split them with comma ``,`` separator. + Example: .. code-block:: ini @@ -617,10 +622,19 @@ Example: [env:myenv] lib_force = OneWire, SPI +.. _projectconf_lib_ignore: + ``lib_ignore`` ^^^^^^^^^^^^^^ -Specify libraries which should be ignored by ``Library Dependency Finder (LDF)`` +Please make sure to read :ref:`faq_ldf` guides first. + +Specify libraries which should be ignored by Library Dependency Finder. + +The correct value for this option is library name (not +folder name). In the most cases, library name is pre-defined in manifest file +(:ref:`library_config`, ``library.properties``, ``module.json``). The multiple +library names are allowed, split them with comma ``,`` separator. Example: @@ -629,18 +643,25 @@ Example: [env:ignore_some_libs] lib_ignore = SPI, Ethernet +.. _projectconf_lib_deep_search: + ``lib_deep_search`` ^^^^^^^^^^^^^^^^^^^ +Please make sure to read :ref:`faq_ldf` guides first. + By default, this option is turned OFF (``lib_deep_search = false``) and means -that ``Library Dependency Finder (LDF)`` will look only for the libraries -that are mentioned (using ``#include <...>``) in the source files from the -project :ref:`projectconf_pio_src_dir`. Also, ``LDF`` analyzes nested -``#include <...>`` by default. +that Library Dependency Finder will analyzes only "nested includes/chain". + +Nevertheless, some libraries depend on other libraries and the +``#include <...>`` directives for these libraries are not declared in the +"main" header file that is used by upper library. In this case, LDF will not +handle these libraries automatically because it doesn't analyze "each source +file" of the nested libraries. If you want to enable deep search, please set this option to ``true``. -Found library will be treated like the new source files and -``LDF`` will search dependencies for it. +Found library will be treated like the new source files and LDF will +search dependencies for it. For example, there are 2 libraries: @@ -688,17 +709,19 @@ For example, there are 2 libraries: ``lib_extra_dirs`` ^^^^^^^^^^^^^^^^^^ -A list with extra directories where ``Library Dependency Finder (LDF)`` will -look for dependencies. Multiple paths are allowed. Please separate them using -comma ``,`` symbol. +Please make sure to read :ref:`faq_ldf` guides first. + +A list with extra directories/storages where Library Dependency Finder will +look for dependencies. Multiple paths are allowed. Please separate them +using comma ``,`` symbol. This option can be set by global environment variable :envvar:`PLATFORMIO_LIB_EXTRA_DIRS`. .. warning:: This is a not direct path to library with source code. It should be the path - to directory that contains libraries grouped by folders. For example, - ``/extra/lib/path/`` but not ``/extra/lib/path/MyLibrary``. + to storage that contains libraries grouped by folders. For example, + ``/extra/lib/storage/`` but not ``/extra/lib/storage/MyLibrary``. Example: @@ -707,6 +730,27 @@ Example: [env:custom_lib_dirs] lib_extra_dirs = /path/to/private/dir1,/path/to/private/dir2 +.. _projectconf_lib_compat_level: + +``lib_compat_level`` +^^^^^^^^^^^^^^^^^^^^ + +Please make sure to read :ref:`faq_ldf` guides first. + +Library compatibility level that allows to control Library Dependency Finder +strictness. If library contains manifest file (:ref:`library_config`, +``library.properties``, ``module.json``), then LDF check compatibility of this +library with real build environment. Available compatibility levels: + +* ``0`` - don't check for compatibility (disable) +* ``1`` - check for the compatibility with :ref:`projectconf_env_framework` + from build environment +* ``2`` - check for the compatibility with :ref:`projectconf_env_framework` + and :ref:`projectconf_env_platform` from build environment. + +By default, this value is set to ``lib_compat_level = 1`` and means that LDF +will check only for framework compatibility. + ----------- .. _projectconf_examples: diff --git a/platformio/__init__.py b/platformio/__init__.py index 8fb65016..f133db64 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev9") +VERSION = (3, 0, "0.dev10") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 1f4dd490..1fc1d079 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -45,6 +45,7 @@ commonvars.AddVariables( # library options ("LIB_DEEP_SEARCH",), + ("LIB_COMPAT_LEVEL",), ("LIB_IGNORE",), ("LIB_FORCE",), ("LIB_EXTRA_DIRS",), @@ -121,6 +122,7 @@ for opt in ("LIB_IGNORE", "LIB_FORCE", "LIB_EXTRA_DIRS"): continue env[opt] = [l.strip() for l in env[opt].split(",") if l.strip()] +env.Prepend(LIBSOURCE_DIRS=env.get("LIB_EXTRA_DIRS", [])) env.LoadDevPlatform(commonvars) env.SConscriptChdir(0) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 082b4a74..b930fe2f 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -17,8 +17,8 @@ from __future__ import absolute_import import os +import sys from os.path import basename, commonprefix, isdir, isfile, join, realpath -from sys import modules import SCons.Scanner @@ -44,7 +44,7 @@ class LibBuilderFactory(object): elif used_frameworks: clsname = "%sLibBuilder" % used_frameworks[0].title() - obj = getattr(modules[__name__], clsname)(env, path) + obj = getattr(sys.modules[__name__], clsname)(env, path) assert isinstance(obj, LibBuilderBase) return obj @@ -327,27 +327,34 @@ def find_and_build_deps(env, lib_builders, scanner, def GetLibBuilders(env): items = [] - libs_dirs = [] env_frameworks = [ - f.lower().strip() for f in env.get("PIOFRAMEWORK", "").split(",")] + f.lower().strip() for f in env.get("PIOFRAMEWORK", "").split(",") + ] + compat_level = int(env.get("LIB_COMPAT_LEVEL", 1)) - for key in ("LIB_EXTRA_DIRS", "LIBSOURCE_DIRS"): - for d in env.get(key, []): - d = env.subst(d) - if isdir(d): - libs_dirs.append(d) - - for libs_dir in libs_dirs: + for libs_dir in env['LIBSOURCE_DIRS']: + libs_dir = env.subst(libs_dir) + if not isdir(libs_dir): + continue for item in sorted(os.listdir(libs_dir)): if item == "__cores__" or not isdir(join(libs_dir, item)): continue lb = LibBuilderFactory.new(env, join(libs_dir, item)) if lb.name in env.get("LIB_IGNORE", []): + if not env.GetOption("silent"): + print "Ignored library " + lb.path continue - if not lb.is_platform_compatible(env['PIOPLATFORM']): + if compat_level > 1 and not lb.is_platform_compatible(env[ + 'PIOPLATFORM']): + if not env.GetOption("silent"): + sys.stderr.write("Platform incompatible library %s\n" % + lb.path) continue - if not any([lb.is_framework_compatible(f) - for f in env_frameworks]): + if compat_level > 0 and not any([lb.is_framework_compatible(f) + for f in env_frameworks]): + if not env.GetOption("silent"): + sys.stderr.write("Framework incompatible library %s\n" % + lb.path) continue items.append(lb) return items @@ -358,8 +365,8 @@ def BuildDependentLibraries(env, src_dir): scanner = SCons.Scanner.C.CScanner() lib_builders = env.GetLibBuilders() - print "Looking for dependencies..." print "Collecting %d compatible libraries" % len(lib_builders) + print "Looking for dependencies..." built_lib_names = [] for lib_name in env.get("LIB_FORCE", []): From 187315fc08063e770dcf9f72e8b5582f892cde41 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 24 Jul 2016 20:04:09 +0300 Subject: [PATCH 068/284] Allow to disable library archiving ("*.ar") // Resolve #719 --- HISTORY.rst | 39 +++++++++++++++----------- docs/librarymanager/config.rst | 4 +++ platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 25 +++++++++++++++-- platformio/builder/tools/platformio.py | 29 +++++++++++-------- 5 files changed, 66 insertions(+), 33 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 084ce934..b78463ae 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -13,28 +13,33 @@ PlatformIO 3.0 (`issue #479 `_) * Unit Testing for Embedded (`docs `__) (`issue #408 `_) -* New Library Build System: intelligent dependency finder that interprets - C Preprocessor conditional macros, - `library deep search `__, - `library compatibility level `__, - support for the 3rd party manifests (Arduino IDE ``library.properties``, - ARM mbed ``module.json``) - (`issue #432 `_) -* New `lib_extra_dirs `__ option for project environment. - Multiple custom library locations! - (`issue #537 `_) -* Handle extra build flags and build script from - `library.json `__ - (`issue #289 `_) -* Check library compatibility with project environment before building - (`issue #415 `_) +* New Intelligent Library Build System + + + `Library Dependency Finder `__ + that interprets C Preprocessor conditional macros and nested includes/chain + + Check library compatibility with project environment before building + (`issue #415 `_) + + Control Library Dependency Finder for compatibility using + `lib_compat_level `__ + option + + Custom library storages/directories with + `lib_extra_dirs `__ option + (`issue #537 `_) + + Handle extra build flags, source filters and build script from + `library.json `__ + (`issue #289 `_) + + Allowed to disable library archiving (``*.ar``) + (`issue #719 `_) + + Show detailed build information about dependent libraries + (`issue #617 `_) + + Support for the 3rd party manifests (Arduino IDE "library.properties" + and ARM mbed "module.json") + * Print human-readable information when processing environments without ``-v, --verbose`` option (`issue #721 `_) * Added ``license`` field to `library.json `__ (`issue #522 `_) -* Show detailed build information about dependent libraries - (`issue #617 `_) * Embedded Board compatibility with more than one development platform (`issue #456 `_) diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index 709e42ff..ae31284e 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -461,6 +461,10 @@ options: - ``String`` - Launch extra script before build process. More details :ref:`projectconf_extra_script` + * - ``libArchive`` + - ``Boolean`` + - Archive object files to Static Library. This is default behavior of + PlatformIO Build System (``"libArchive": true``). **Examples** diff --git a/platformio/__init__.py b/platformio/__init__.py index f133db64..d37c5b19 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev10") +VERSION = (3, 0, "0.dev11") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index b930fe2f..777dbb7e 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -121,6 +121,10 @@ class LibBuilderBase(object): def extra_script(self): return None + @property + def lib_archive(self): + return True + @property def is_built(self): return self._is_built @@ -162,7 +166,12 @@ class LibBuilderBase(object): for key in ("CPPPATH", "LIBPATH", "LIBS", "LINKFLAGS"): self.env.AppendUnique(**{key: env.get(key)}) - return env.BuildLibrary(self.build_dir, self.src_dir, self.src_filter) + if self.lib_archive: + return env.BuildLibrary( + self.build_dir, self.src_dir, self.src_filter) + else: + return env.BuildSources( + self.build_dir, self.src_dir, self.src_filter) class UnknownLibBuilder(LibBuilderBase): @@ -260,6 +269,12 @@ class PlatformIOLibBuilder(LibBuilderBase): return self._manifest.get("build").get("extra_script") return LibBuilderBase.extra_script.fget(self) + @property + def lib_archive(self): + if "libArchive" in self._manifest.get("build", {}): + return self._manifest.get("build").get("libArchive") + return LibBuilderBase.lib_archive.fget(self) + def is_platform_compatible(self, platform): items = self._manifest.get("platforms") if not items: @@ -315,7 +330,9 @@ def find_and_build_deps(env, lib_builders, scanner, lb.append_to_cpppath() # start builder for lb in target_lbs: - libs.append(lb.build()) + lib_node = lb.build() + if lib_node: + libs.append(lib_node) if env.get("LIB_DEEP_SEARCH", "").lower() == "true": for lb in target_lbs: @@ -377,7 +394,9 @@ def BuildDependentLibraries(env, src_dir): libs.extend(find_and_build_deps( env, lib_builders, scanner, lb.src_dir, lb.src_filter)) if not lb.is_built: - libs.append(lb.build()) + lib_node = lb.build() + if lib_node: + libs.append(lib_node) # process project source code libs.extend(find_and_build_deps( diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 66e4893c..e4875e15 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -85,24 +85,24 @@ def BuildProgram(env): env.Append( CPPPATH=["$PROJECTSRC_DIR"], LIBS=deplibs, - LIBPATH=["$BUILD_DIR"] - ) - - sources = env.CollectBuildFiles( - "$BUILDSRC_DIR", "$PROJECTSRC_DIR", - src_filter=env.get("SRC_FILTER"), duplicate=False) + LIBPATH=["$BUILD_DIR"], + PIOBUILDFILES=env.CollectBuildFiles( + "$BUILDSRC_DIR", + "$PROJECTSRC_DIR", + src_filter=env.get("SRC_FILTER"), + duplicate=False)) if "test" in COMMAND_LINE_TARGETS: - sources.extend(env.ProcessTest()) + env.Append(PIOBUILDFILES=env.ProcessTest()) - if not sources and not COMMAND_LINE_TARGETS: + if not env['PIOBUILDFILES'] and not COMMAND_LINE_TARGETS: env.Exit( "Error: Nothing to build. Please put your source code files " "to '%s' folder" % env.subst("$PROJECTSRC_DIR")) program = env.Program( join("$BUILD_DIR", env.subst("$PROGNAME")), - sources + env['PIOBUILDFILES'] ) if set(["upload", "uploadlazy", "program"]) & set(COMMAND_LINE_TARGETS): @@ -262,11 +262,15 @@ def BuildFrameworks(env, frameworks): def BuildLibrary(env, variant_dir, src_dir, src_filter=None): lib = env.Clone() - return lib.Library( + return lib.StaticLibrary( lib.subst(variant_dir), lib.CollectBuildFiles( - variant_dir, src_dir, src_filter=src_filter) - ) + variant_dir, src_dir, src_filter=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)) def exists(_): @@ -283,4 +287,5 @@ def generate(env): env.AddMethod(CollectBuildFiles) env.AddMethod(BuildFrameworks) env.AddMethod(BuildLibrary) + env.AddMethod(BuildSources) return env From be85eb3e4a3c9af91a59cecd6b7c9975b9ae5a4f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 28 Jul 2016 01:52:18 +0300 Subject: [PATCH 069/284] Refactor Library Dependency Finder --- HISTORY.rst | 2 +- docs/faq.rst | 3 +-- docs/projectconf.rst | 19 +++++++++---------- docs/userguide/lib/cmd_install.rst | 8 ++++++++ platformio/__init__.py | 2 +- setup.py | 2 +- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index b78463ae..b9a19c34 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -16,7 +16,7 @@ PlatformIO 3.0 * New Intelligent Library Build System + `Library Dependency Finder `__ - that interprets C Preprocessor conditional macros and nested includes/chain + that interprets C Preprocessor conditional macros with deep search behavior + Check library compatibility with project environment before building (`issue #415 `_) + Control Library Dependency Finder for compatibility using diff --git a/docs/faq.rst b/docs/faq.rst index 18605764..bd55be30 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -42,8 +42,7 @@ Library Dependency Finder is a part of PlatformIO Library Build System. It operates with the header files (``*.h, *.hpp``) and looks for ``#include <...>`` directives. What is more, LDF interprets C Preprocessor conditional macros (``#ifdef ...``, etc.). Library Dependency Finder starts -work from analyzing source files from :ref:`projectconf_pio_src_dir`. It -understands "nested includes/chain" by default if they depend on each other. +work from analyzing source files from :ref:`projectconf_pio_src_dir`. There are different library storages where Library Dependency Finder looks for dependencies. These storages/folders have priority. LDF operates in the next diff --git a/docs/projectconf.rst b/docs/projectconf.rst index aef7c784..6f5ae26f 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -650,18 +650,17 @@ Example: Please make sure to read :ref:`faq_ldf` guides first. -By default, this option is turned OFF (``lib_deep_search = false``) and means -that Library Dependency Finder will analyzes only "nested includes/chain". +By default, this option is turned ON (``lib_deep_search = true``) and means +that Library Dependency Finder will analyze ALL source files from the library +and will try automatically find all dependencies. -Nevertheless, some libraries depend on other libraries and the +If you want to disable deep search, please set this option to ``false``. +Note! Some libraries depend on other libraries and the ``#include <...>`` directives for these libraries are not declared in the -"main" header file that is used by upper library. In this case, LDF will not -handle these libraries automatically because it doesn't analyze "each source -file" of the nested libraries. - -If you want to enable deep search, please set this option to ``true``. -Found library will be treated like the new source files and LDF will -search dependencies for it. +"main" header file that is used by upper library. If LDF is turned OFF +(``lib_deep_search = false``), it will not handle these libraries automatically +because it doesn't analyze "each source file" of the nested libraries +(only "nested includes/chain"). For example, there are 2 libraries: diff --git a/docs/userguide/lib/cmd_install.rst b/docs/userguide/lib/cmd_install.rst index a28c24a6..7b6e2986 100644 --- a/docs/userguide/lib/cmd_install.rst +++ b/docs/userguide/lib/cmd_install.rst @@ -30,6 +30,14 @@ Description Install new library by specified `PlatformIO Library Registry ID `_. +Installs the project library dependencies or a specific set of libraries. +[LIBRARY] can have multiple forms: , @, + or =@ + +Where, is a registry ID, registry name, repository URL, physical +location, is a valid semantic version/range, commit, branch, etc., and + is the name it should have locally. + Options ------- diff --git a/platformio/__init__.py b/platformio/__init__.py index d37c5b19..7d384e5c 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev11") +VERSION = (3, 0, "0.dev12") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/setup.py b/setup.py index d228de9c..c1511504 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ from platformio import (__author__, __description__, __email__, __license__, install_requires = [ "bottle<0.13", - "click>=3.2,<6", + "click>=5,<6", "lockfile>=0.9.1,<0.13", "requests>=2.4.0,<3", "semantic_version>=2.5.0", From e3e6676420dc79bd5f66a937399b4adac1f3fd11 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 28 Jul 2016 01:54:09 +0300 Subject: [PATCH 070/284] Refactor Library Dependency Finder --- platformio/builder/tools/piolib.py | 292 +++++++++++++++++------------ 1 file changed, 176 insertions(+), 116 deletions(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 777dbb7e..3b2068ac 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -36,7 +36,8 @@ class LibBuilderFactory(object): else: env_frameworks = [ f.lower().strip() - for f in env.get("PIOFRAMEWORK", "").split(",")] + for f in env.get("PIOFRAMEWORK", "").split(",") + ] used_frameworks = LibBuilderFactory.get_used_frameworks(env, path) common_frameworks = set(env_frameworks) & set(used_frameworks) if common_frameworks: @@ -73,11 +74,19 @@ class LibBuilderFactory(object): class LibBuilderBase(object): + INC_SCANNER = SCons.Scanner.C.CScanner() + def __init__(self, env, path): - self.env = env - self.path = path - self._is_built = False + self.env = env.Clone() + self.path = env.subst(path) self._manifest = self.load_manifest() + self._is_dependent = False + self._deps = [] + self._scanner_visited = tuple() + self._built_node = None + + # process extra options and append to build environment + self.process_extra_options() def __repr__(self): return "%s(%r)" % (self.__class__, self.path) @@ -96,14 +105,14 @@ class LibBuilderBase(object): @property def src_filter(self): return piotool.SRC_FILTER_DEFAULT + [ - "-" % os.sep, "-" % os.sep, - "-" % os.sep, "-" % os.sep + "-" % os.sep, "-" % os.sep, "-" % + os.sep, "-" % os.sep ] @property def src_dir(self): - return (join(self.path, "src") if isdir(join(self.path, "src")) - else self.path) + return (join(self.path, "src") + if isdir(join(self.path, "src")) else self.path) @property def build_dir(self): @@ -126,8 +135,17 @@ class LibBuilderBase(object): return True @property - def is_built(self): - return self._is_built + def dependencies(self): + return self._deps + + def depends_on(self, lb): + assert isinstance(lb, LibBuilderBase) + if lb not in self._deps: + self._deps.append(lb) + + @property + def dependent(self): + return self._is_dependent def is_platform_compatible(self, platform): return True @@ -138,46 +156,123 @@ class LibBuilderBase(object): def load_manifest(self): return {} - def get_path_dirs(self, use_build_dir=False): + def process_extra_options(self): + with util.cd(self.path): + self.env.ProcessUnFlags(self.build_unflags) + self.env.ProcessFlags(self.build_flags) + if self.extra_script: + self.env.SConscript(realpath(self.extra_script), exports="env") + + def get_inc_dirs(self, use_build_dir=False): return [self.build_dir if use_build_dir else self.src_dir] - def append_to_cpppath(self): - self.env.AppendUnique( - CPPPATH=self.get_path_dirs(use_build_dir=True) - ) + def _validate_search_paths(self, lib_builders, search_paths=None): + if not search_paths: + search_paths = tuple() + deep_search = self.env.get("LIB_DEEP_SEARCH", "true").lower() == "true" + + if not self._scanner_visited and ( + isinstance(self, ProjectAsLibBuilder) or deep_search): + for item in self.env.MatchSourceFiles(self.src_dir, + self.src_filter): + path = join(self.src_dir, item) + if (path not in self._scanner_visited and + path not in search_paths): + search_paths += (path, ) + + _search_paths = tuple() + for path in search_paths: + if path not in self._scanner_visited: + _search_paths += (path, ) + self._scanner_visited += (path, ) + + return _search_paths + + def _get_found_includes(self, lib_builders, search_paths=None): + inc_dirs = tuple() + used_inc_dirs = tuple() + for lb in [self] + lib_builders: + items = tuple(self.env.Dir(d) for d in lb.get_inc_dirs()) + if lb.dependent: + used_inc_dirs += items + else: + inc_dirs += items + inc_dirs = used_inc_dirs + inc_dirs + + result = tuple() + for path in self._validate_search_paths(search_paths): + for inc in self.env.File(path).get_found_includes( + self.env, LibBuilderBase.INC_SCANNER, inc_dirs): + if inc not in result: + result += (inc, ) + return result + + def search_dependencies(self, lib_builders, search_paths=None): + self._is_dependent = True + lib_inc_map = {} + for inc in self._get_found_includes(lib_builders, search_paths): + for lb in lib_builders: + if inc.get_abspath() in lb: + if lb not in lib_inc_map: + lib_inc_map[lb] = [] + lib_inc_map[lb].append(inc.get_abspath()) + break + + for lb, lb_src_files in lib_inc_map.items(): + if lb != self and lb not in self.dependencies: + self.depends_on(lb) + lb.search_dependencies(lib_builders, lb_src_files) def build(self): - if self.version: - print "Depends on <%s> v%s" % (self.name, self.version) - else: - print "Depends on <%s>" % self.name - assert self._is_built is False - self._is_built = True - self.append_to_cpppath() + libs = [] + for lb in self.dependencies: + libs.extend(lb.build()) + # copy shared information to self env + for key in ("CPPPATH", "LIBPATH", "LIBS", "LINKFLAGS"): + self.env.AppendUnique(**{key: lb.env.get(key)}) - env = self.env.Clone() - with util.cd(self.path): - env.ProcessUnFlags(self.build_unflags) - env.ProcessFlags(self.build_flags) - if self.extra_script: - env.SConscript(realpath(self.extra_script), exports="env") + self.env.AppendUnique(CPPPATH=self.get_inc_dirs(use_build_dir=True)) - # copy some data to global env - for key in ("CPPPATH", "LIBPATH", "LIBS", "LINKFLAGS"): - self.env.AppendUnique(**{key: env.get(key)}) - - if self.lib_archive: - return env.BuildLibrary( - self.build_dir, self.src_dir, self.src_filter) - else: - return env.BuildSources( - self.build_dir, self.src_dir, self.src_filter) + if not self._built_node: + if self.lib_archive: + self._built_node = self.env.BuildLibrary( + self.build_dir, self.src_dir, self.src_filter) + else: + self._built_node = self.env.BuildSources( + self.build_dir, self.src_dir, self.src_filter) + return libs + [self._built_node] class UnknownLibBuilder(LibBuilderBase): pass +class ProjectAsLibBuilder(LibBuilderBase): + + @property + def src_filter(self): + return self.env.get("SRC_FILTER", LibBuilderBase.src_filter.fget(self)) + + def process_extra_options(self): + # skip for project, options are already processed + pass + + def search_dependencies(self, lib_builders, search_paths=None): + for lib_name in self.env.get("LIB_FORCE", []): + for lb in lib_builders: + if lb.name == lib_name and lb not in self.dependencies: + self.depends_on(lb) + lb.search_dependencies(lib_builders) + break + return LibBuilderBase.search_dependencies(self, lib_builders, + search_paths) + + def build(self): + # dummy mark that project is built + self._built_node = "dummy" + return [l for l in LibBuilderBase.build(self) if l != "dummy"] + + class ArduinoLibBuilder(LibBuilderBase): def load_manifest(self): @@ -192,13 +287,13 @@ class ArduinoLibBuilder(LibBuilderBase): manifest[key.strip()] = value.strip() return manifest - def get_path_dirs(self, use_build_dir=False): - path_dirs = LibBuilderBase.get_path_dirs(self, use_build_dir) + def get_inc_dirs(self, use_build_dir=False): + inc_dirs = LibBuilderBase.get_inc_dirs(self, use_build_dir) if not isdir(join(self.src_dir, "utility")): - return path_dirs - path_dirs.append( + return inc_dirs + inc_dirs.append( join(self.build_dir if use_build_dir else self.src_dir, "utility")) - return path_dirs + return inc_dirs @property def src_filter(self): @@ -224,14 +319,13 @@ class MbedLibBuilder(LibBuilderBase): return join(self.path, "source") return LibBuilderBase.src_dir.fget(self) - def get_path_dirs(self, use_build_dir=False): - path_dirs = LibBuilderBase.get_path_dirs(self, use_build_dir) + def get_inc_dirs(self, use_build_dir=False): + inc_dirs = LibBuilderBase.get_inc_dirs(self, use_build_dir) + if self.path not in inc_dirs: + inc_dirs.append(self.path) for p in self._manifest.get("extraIncludes", []): - if p.startswith("source/"): - p = p[7:] - path_dirs.append( - join(self.build_dir if use_build_dir else self.src_dir, p)) - return path_dirs + inc_dirs.append(join(self.path, p)) + return inc_dirs def is_framework_compatible(self, framework): return framework.lower() == "mbed" @@ -295,53 +389,6 @@ class PlatformIOLibBuilder(LibBuilderBase): return item.lower() in [i.lower() for i in ilist] -def find_deps(env, scanner, path_dirs, src_dir, src_filter): - result = [] - for item in env.MatchSourceFiles(src_dir, src_filter): - result.extend(env.File(join(src_dir, item)).get_implicit_deps( - env, scanner, path_dirs)) - return result - - -def find_and_build_deps(env, lib_builders, scanner, - src_dir, src_filter): - path_dirs = tuple() - built_path_dirs = tuple() - for lb in lib_builders: - items = [env.Dir(d) for d in lb.get_path_dirs()] - if lb.is_built: - built_path_dirs += tuple(items) - else: - path_dirs += tuple(items) - path_dirs = built_path_dirs + path_dirs - - target_lbs = [] - deps = find_deps(env, scanner, path_dirs, src_dir, src_filter) - for d in deps: - for lb in lib_builders: - if d.get_abspath() in lb: - if lb not in target_lbs and not lb.is_built: - target_lbs.append(lb) - break - - libs = [] - # append PATH directories to global CPPPATH before build starts - for lb in target_lbs: - lb.append_to_cpppath() - # start builder - for lb in target_lbs: - lib_node = lb.build() - if lib_node: - libs.append(lib_node) - - if env.get("LIB_DEEP_SEARCH", "").lower() == "true": - for lb in target_lbs: - libs.extend(find_and_build_deps( - env, lib_builders, scanner, lb.src_dir, lb.src_filter)) - - return libs - - def GetLibBuilders(env): items = [] env_frameworks = [ @@ -378,31 +425,44 @@ def GetLibBuilders(env): def BuildDependentLibraries(env, src_dir): - libs = [] - scanner = SCons.Scanner.C.CScanner() + + def print_deps_tree(root, level=0): + margin = "| " * (level) + for lb in root.dependencies: + title = "<%s>" % lb.name + if lb.version: + title += " v%s" % lb.version + if not env.GetOption("silent"): + title += " (%s)" % lb.path + print "%s|-- %s" % (margin, title) + if lb.dependencies: + print_deps_tree(lb, level + 1) + lib_builders = env.GetLibBuilders() - print "Collecting %d compatible libraries" % len(lib_builders) + print "Collected %d compatible libraries" % len(lib_builders) print "Looking for dependencies..." - built_lib_names = [] - for lib_name in env.get("LIB_FORCE", []): - for lb in lib_builders: - if lb.name != lib_name or lb.name in built_lib_names: - continue - built_lib_names.append(lb.name) - libs.extend(find_and_build_deps( - env, lib_builders, scanner, lb.src_dir, lb.src_filter)) - if not lb.is_built: - lib_node = lb.build() - if lib_node: - libs.append(lib_node) + from time import time + start = time() + project = ProjectAsLibBuilder(env, src_dir) + project.env = env + project.search_dependencies(lib_builders) + print 13, time() - start - # process project source code - libs.extend(find_and_build_deps( - env, lib_builders, scanner, src_dir, env.get("SRC_FILTER"))) + if project.dependencies: + print "Library Dependency Map" + print_deps_tree(project) + else: + print "Project does not have dependencies" - return libs + # print "root", lbproj, lbproj._deps + # for lb_ in lib_builders: + # if not lb_.dependent: + # continue + # print lb_.name, lb_, lb_._deps + + return project.build() def exists(_): From 3c795a215ec69e5340516fcee7abd27de9670507 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 28 Jul 2016 02:08:30 +0300 Subject: [PATCH 071/284] Fix typo --- platformio/builder/tools/piomisc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 94b2b4d6..dd198061 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -159,7 +159,7 @@ def DumpIDEData(env): # installed libs for lb in env.GetLibBuilders(): - includes.extend(lb.get_path_dirs()) + includes.extend(lb.get_inc_dirs()) # includes from toolchains p = env.DevPlatform() From b177bb5bfb6c4ad8c7f822f0ee046a1e743211d4 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 28 Jul 2016 14:09:29 +0300 Subject: [PATCH 072/284] Remove debug code; a few bugfixes --- platformio/builder/tools/piolib.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 3b2068ac..bccc9073 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -166,9 +166,10 @@ class LibBuilderBase(object): def get_inc_dirs(self, use_build_dir=False): return [self.build_dir if use_build_dir else self.src_dir] - def _validate_search_paths(self, lib_builders, search_paths=None): + def _validate_search_paths(self, search_paths=None): if not search_paths: search_paths = tuple() + assert isinstance(search_paths, tuple) deep_search = self.env.get("LIB_DEEP_SEARCH", "true").lower() == "true" if not self._scanner_visited and ( @@ -214,8 +215,8 @@ class LibBuilderBase(object): for lb in lib_builders: if inc.get_abspath() in lb: if lb not in lib_inc_map: - lib_inc_map[lb] = [] - lib_inc_map[lb].append(inc.get_abspath()) + lib_inc_map[lb] = tuple() + lib_inc_map[lb] += (inc.get_abspath(), ) break for lb, lb_src_files in lib_inc_map.items(): @@ -231,9 +232,9 @@ class LibBuilderBase(object): for key in ("CPPPATH", "LIBPATH", "LIBS", "LINKFLAGS"): self.env.AppendUnique(**{key: lb.env.get(key)}) - self.env.AppendUnique(CPPPATH=self.get_inc_dirs(use_build_dir=True)) - if not self._built_node: + self.env.AppendUnique(CPPPATH=self.get_inc_dirs( + use_build_dir=True)) if self.lib_archive: self._built_node = self.env.BuildLibrary( self.build_dir, self.src_dir, self.src_filter) @@ -443,12 +444,9 @@ def BuildDependentLibraries(env, src_dir): print "Collected %d compatible libraries" % len(lib_builders) print "Looking for dependencies..." - from time import time - start = time() project = ProjectAsLibBuilder(env, src_dir) project.env = env project.search_dependencies(lib_builders) - print 13, time() - start if project.dependencies: print "Library Dependency Map" @@ -456,12 +454,6 @@ def BuildDependentLibraries(env, src_dir): else: print "Project does not have dependencies" - # print "root", lbproj, lbproj._deps - # for lb_ in lib_builders: - # if not lb_.dependent: - # continue - # print lb_.name, lb_, lb_._deps - return project.build() From 269967a809d300a406f25228e21d23a13f8bf5c9 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 28 Jul 2016 14:39:38 +0300 Subject: [PATCH 073/284] Typo fix --- docs/librarymanager/config.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index ae31284e..13c0745f 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -487,7 +487,7 @@ options: ] } -3. Force to use ``C99`` standard instead ``C11`` +3. Force to use ``C99`` standard instead of ``C11`` .. code-block:: javascript @@ -528,4 +528,4 @@ options: CPPPATH=["inc", "inc/devices"] ) - # some python code that generates headers files "on-the-fly" + # some python code that generates header files "on-the-fly" From 8c5fabe41107cfba898dc5a7942ed93ae84a9325 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 28 Jul 2016 16:13:49 +0300 Subject: [PATCH 074/284] Avoid infinite loop when we've already searched for dependencies --- platformio/builder/tools/piolib.py | 31 +++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index bccc9073..3e34bc03 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -78,10 +78,11 @@ class LibBuilderBase(object): def __init__(self, env, path): self.env = env.Clone() + self.envorigin = env self.path = env.subst(path) self._manifest = self.load_manifest() self._is_dependent = False - self._deps = [] + self._deps = tuple() self._scanner_visited = tuple() self._built_node = None @@ -138,11 +139,6 @@ class LibBuilderBase(object): def dependencies(self): return self._deps - def depends_on(self, lb): - assert isinstance(lb, LibBuilderBase) - if lb not in self._deps: - self._deps.append(lb) - @property def dependent(self): return self._is_dependent @@ -192,7 +188,7 @@ class LibBuilderBase(object): def _get_found_includes(self, lib_builders, search_paths=None): inc_dirs = tuple() used_inc_dirs = tuple() - for lb in [self] + lib_builders: + for lb in (self, ) + lib_builders: items = tuple(self.env.Dir(d) for d in lb.get_inc_dirs()) if lb.dependent: used_inc_dirs += items @@ -208,6 +204,17 @@ class LibBuilderBase(object): result += (inc, ) return result + def depends_on(self, lb, lib_builders, search_paths=None): + assert isinstance(lb, LibBuilderBase) + if lb not in self._deps: + self._deps += (lb, ) + + # avoid infinite loop when we've already searched for dependencies + for lb_ in lib_builders: + if lb in lb_._deps: + return + lb.search_dependencies(lib_builders, search_paths) + def search_dependencies(self, lib_builders, search_paths=None): self._is_dependent = True lib_inc_map = {} @@ -221,8 +228,7 @@ class LibBuilderBase(object): for lb, lb_src_files in lib_inc_map.items(): if lb != self and lb not in self.dependencies: - self.depends_on(lb) - lb.search_dependencies(lib_builders, lb_src_files) + self.depends_on(lb, lib_builders, lb_src_files) def build(self): libs = [] @@ -262,8 +268,7 @@ class ProjectAsLibBuilder(LibBuilderBase): for lib_name in self.env.get("LIB_FORCE", []): for lb in lib_builders: if lb.name == lib_name and lb not in self.dependencies: - self.depends_on(lb) - lb.search_dependencies(lib_builders) + self.depends_on(lb, lib_builders) break return LibBuilderBase.search_dependencies(self, lib_builders, search_paths) @@ -391,7 +396,7 @@ class PlatformIOLibBuilder(LibBuilderBase): def GetLibBuilders(env): - items = [] + items = tuple() env_frameworks = [ f.lower().strip() for f in env.get("PIOFRAMEWORK", "").split(",") ] @@ -421,7 +426,7 @@ def GetLibBuilders(env): sys.stderr.write("Framework incompatible library %s\n" % lb.path) continue - items.append(lb) + items += (lb, ) return items From 339acab9179b6a28d37b16dc06367eb3fa341a1e Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 28 Jul 2016 16:27:48 +0300 Subject: [PATCH 075/284] PyLint fix --- platformio/builder/tools/piolib.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 3e34bc03..5e440952 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -78,7 +78,6 @@ class LibBuilderBase(object): def __init__(self, env, path): self.env = env.Clone() - self.envorigin = env self.path = env.subst(path) self._manifest = self.load_manifest() self._is_dependent = False @@ -208,11 +207,6 @@ class LibBuilderBase(object): assert isinstance(lb, LibBuilderBase) if lb not in self._deps: self._deps += (lb, ) - - # avoid infinite loop when we've already searched for dependencies - for lb_ in lib_builders: - if lb in lb_._deps: - return lb.search_dependencies(lib_builders, search_paths) def search_dependencies(self, lib_builders, search_paths=None): From 3a7032ec9c4cbe2b1f156d269d9c06c2b904c8ae Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 28 Jul 2016 17:29:53 +0300 Subject: [PATCH 076/284] Show a warning about Circular Dependencies --- platformio/builder/tools/piolib.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 5e440952..f9797560 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -203,11 +203,13 @@ class LibBuilderBase(object): result += (inc, ) return result - def depends_on(self, lb, lib_builders, search_paths=None): + def depends_on(self, lb): assert isinstance(lb, LibBuilderBase) - if lb not in self._deps: + if self in lb.dependencies: + sys.stderr.write("Warning! Circular dependencies detected " + "between `%s` and `%s`\n" % (self.path, lb.path)) + elif lb not in self._deps: self._deps += (lb, ) - lb.search_dependencies(lib_builders, search_paths) def search_dependencies(self, lib_builders, search_paths=None): self._is_dependent = True @@ -222,7 +224,8 @@ class LibBuilderBase(object): for lb, lb_src_files in lib_inc_map.items(): if lb != self and lb not in self.dependencies: - self.depends_on(lb, lib_builders, lb_src_files) + self.depends_on(lb) + lb.search_dependencies(lib_builders, lb_src_files) def build(self): libs = [] @@ -262,7 +265,8 @@ class ProjectAsLibBuilder(LibBuilderBase): for lib_name in self.env.get("LIB_FORCE", []): for lb in lib_builders: if lb.name == lib_name and lb not in self.dependencies: - self.depends_on(lb, lib_builders) + self.depends_on(lb) + lb.search_dependencies(lib_builders) break return LibBuilderBase.search_dependencies(self, lib_builders, search_paths) From 34b1f3b0a14310e681beb7dc4b7081a5050b50c4 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 28 Jul 2016 22:15:03 +0300 Subject: [PATCH 077/284] Handle includes from CPPPATH for PlatformIOLibBuilder --- platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 7d384e5c..735c7548 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev12") +VERSION = (3, 0, "0.dev13") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index f9797560..ebddb279 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -72,12 +72,13 @@ class LibBuilderFactory(object): return [] -class LibBuilderBase(object): +class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes INC_SCANNER = SCons.Scanner.C.CScanner() def __init__(self, env, path): self.env = env.Clone() + self.envorigin = env.Clone() self.path = env.subst(path) self._manifest = self.load_manifest() self._is_dependent = False @@ -156,7 +157,10 @@ class LibBuilderBase(object): self.env.ProcessUnFlags(self.build_unflags) self.env.ProcessFlags(self.build_flags) if self.extra_script: - self.env.SConscript(realpath(self.extra_script), exports="env") + self.env.SConscript( + realpath(self.extra_script), + exports={"env": self.env, + "pio_lib_builder": self}) def get_inc_dirs(self, use_build_dir=False): return [self.build_dir if use_build_dir else self.src_dir] @@ -363,8 +367,8 @@ class PlatformIOLibBuilder(LibBuilderBase): @property def extra_script(self): - if "extra_script" in self._manifest.get("build", {}): - return self._manifest.get("build").get("extra_script") + if "extraScript" in self._manifest.get("build", {}): + return self._manifest.get("build").get("extraScript") return LibBuilderBase.extra_script.fget(self) @property @@ -392,6 +396,14 @@ class PlatformIOLibBuilder(LibBuilderBase): ilist = [i.strip() for i in ilist.split(",")] return item.lower() in [i.lower() for i in ilist] + def get_inc_dirs(self, use_build_dir=False): + inc_dirs = LibBuilderBase.get_inc_dirs(self, use_build_dir) + for path in self.env['CPPPATH']: + if path not in self.envorigin['CPPPATH']: + inc_dirs.append( + path if use_build_dir else self.env.subst(path)) + return inc_dirs + def GetLibBuilders(env): items = tuple() From b364389541b02ad8f3e5437af549357776ce5849 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 30 Jul 2016 19:46:08 +0300 Subject: [PATCH 078/284] If platformio is installed via brew, show it for upgrade --- platformio/maintenance.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platformio/maintenance.py b/platformio/maintenance.py index c91857dc..ad190080 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -195,14 +195,16 @@ def check_platformio_upgrade(): click.secho("PlatformIO IDE Menu: Upgrade PlatformIO", fg="cyan", nl=False) click.secho("`.", fg="yellow") + elif join("Cellar", "platformio") in util.get_source_dir(): + click.secho("brew update && brew upgrade", fg="cyan", nl=False) + click.secho("` command.", fg="yellow") else: click.secho("platformio upgrade", fg="cyan", nl=False) click.secho("` or `", fg="yellow", nl=False) click.secho("pip install -U platformio", fg="cyan", nl=False) click.secho("` command.", fg="yellow") click.secho("Changes: ", fg="yellow", nl=False) - click.secho("http://docs.platformio.org/en/latest/history.html", - fg="cyan") + click.secho("http://docs.platformio.org/en/latest/history.html", fg="cyan") click.echo("*" * terminal_width) click.echo("") From 74af8a5c397f728b8d4337084affe73f4b950a8c Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 31 Jul 2016 00:00:58 +0300 Subject: [PATCH 079/284] Handle "dependencies" from library and project when build libraries // Issue #709 --- docs/faq.rst | 13 +++- docs/librarymanager/config.rst | 16 +++- platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 113 +++++++++++++++++++++-------- 4 files changed, 108 insertions(+), 36 deletions(-) diff --git a/docs/faq.rst b/docs/faq.rst index bd55be30..72b13163 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -39,10 +39,15 @@ How works Library Dependency Finder (LDF) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Library Dependency Finder is a part of PlatformIO Library Build System. It -operates with the header files (``*.h, *.hpp``) and looks for -``#include <...>`` directives. What is more, LDF interprets C Preprocessor -conditional macros (``#ifdef ...``, etc.). Library Dependency Finder starts -work from analyzing source files from :ref:`projectconf_pio_src_dir`. +operates with the C/C++ source files and looks for ``#include <...>`` +directives. Also, LDF interprets C Preprocessor conditional macros +(``#if``, ``ifdef``, etc.). Library Dependency Finder starts +work from analyzing source files from :ref:`projectconf_pio_src_dir` by default. + +If project or library contains own ``dependencies`` list (see +:ref:`libjson_dependencies`), the LDF will not looking for dependencies in +the source code. The specified libraries will be built automatically without +check. There are different library storages where Library Dependency Finder looks for dependencies. These storages/folders have priority. LDF operates in the next diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index 13c0745f..1c0e5354 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -381,6 +381,7 @@ A list of dependent libraries. They will be installed automatically with Allowed requirements for dependent library: * ``name`` | Type: ``String`` +* ``version`` | Type: ``String`` * ``authors`` | Type: ``String`` or ``Array`` * ``frameworks`` | Type: ``String`` or ``Array`` * ``platforms`` | Type: ``String`` or ``Array`` @@ -401,10 +402,23 @@ Example: }, { "name": "Library-Bar", - "frameworks": "FrameworkFoo, FrameworkBar" + "version": "~1.2.3" + }, + { + "name": "lib-from-repo", + "version": "https://github.com/user/package.git#1.2.3" } ] +A short definition of dependencies is allowed: + +.. code-block:: javascript + + "dependencies": { + "mylib": "1.2.3", + "lib-from-repo": "githubuser/package" + } + See more ``library.json`` :ref:`library_creating_examples`. diff --git a/platformio/__init__.py b/platformio/__init__.py index 735c7548..5f0228e9 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev13") +VERSION = (3, 0, "0.dev14") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index ebddb279..ce1a110a 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -82,8 +82,8 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes self.path = env.subst(path) self._manifest = self.load_manifest() self._is_dependent = False - self._deps = tuple() - self._scanner_visited = tuple() + self._depbuilders = tuple() + self._scanned_paths = tuple() self._built_node = None # process extra options and append to build environment @@ -103,6 +103,31 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes def version(self): return self._manifest.get("version") + @property + def dependencies(self): + deps = self._manifest.get("dependencies") + if not deps: + return deps + items = [] + if isinstance(deps, dict): + if "name" in deps: + items.append(deps) + else: + for name, version in deps.items(): + items.append({"name": name, "version": version}) + elif isinstance(deps, list): + items = [d for d in deps if "name" in d] + for item in items: + for k in ("frameworks", "platforms"): + if k not in item or isinstance(k, list): + continue + if item[k] == "*": + del item[k] + elif isinstance(item[k], basestring): + item[k] = [i.strip() for i in item[k].split(",") + if i.strip()] + return items + @property def src_filter(self): return piotool.SRC_FILTER_DEFAULT + [ @@ -136,8 +161,8 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes return True @property - def dependencies(self): - return self._deps + def depbuilders(self): + return self._depbuilders @property def dependent(self): @@ -171,20 +196,20 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes assert isinstance(search_paths, tuple) deep_search = self.env.get("LIB_DEEP_SEARCH", "true").lower() == "true" - if not self._scanner_visited and ( + if not self._scanned_paths and ( isinstance(self, ProjectAsLibBuilder) or deep_search): for item in self.env.MatchSourceFiles(self.src_dir, self.src_filter): path = join(self.src_dir, item) - if (path not in self._scanner_visited and + if (path not in self._scanned_paths and path not in search_paths): search_paths += (path, ) _search_paths = tuple() for path in search_paths: - if path not in self._scanner_visited: + if path not in self._scanned_paths: _search_paths += (path, ) - self._scanner_visited += (path, ) + self._scanned_paths += (path, ) return _search_paths @@ -207,16 +232,46 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes result += (inc, ) return result - def depends_on(self, lb): + def depend_recursive(self, lb, lib_builders, search_paths=None): assert isinstance(lb, LibBuilderBase) - if self in lb.dependencies: - sys.stderr.write("Warning! Circular dependencies detected " - "between `%s` and `%s`\n" % (self.path, lb.path)) - elif lb not in self._deps: - self._deps += (lb, ) + if self != lb: + if self in lb.depbuilders: + sys.stderr.write("Warning! Circular dependencies detected " + "between `%s` and `%s`\n" % + (self.path, lb.path)) + elif lb not in self._depbuilders: + self._depbuilders += (lb, ) + lb.search_deps_recursive(lib_builders, search_paths) - def search_dependencies(self, lib_builders, search_paths=None): + def search_deps_recursive(self, lib_builders, search_paths=None): self._is_dependent = True + + # if dependencies are specified, don't use automatic finder + if self.dependencies: + for item in self.dependencies: + found = False + for lb in lib_builders: + if item['name'] != lb.name: + continue + elif "frameworks" in item and \ + not any([lb.is_framework_compatible(f) + for f in item["frameworks"]]): + continue + elif "platforms" in item and \ + not any([lb.is_platform_compatible(p) + for p in item["platforms"]]): + continue + found = True + self.depend_recursive(lb, lib_builders) + break + + if not found: + sys.stderr.write( + "Error: Could not find `%s` dependency for `%s` " + "library\n" % (item['name'], self.name)) + self.env.Exit(2) + return + lib_inc_map = {} for inc in self._get_found_includes(lib_builders, search_paths): for lb in lib_builders: @@ -227,13 +282,11 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes break for lb, lb_src_files in lib_inc_map.items(): - if lb != self and lb not in self.dependencies: - self.depends_on(lb) - lb.search_dependencies(lib_builders, lb_src_files) + self.depend_recursive(lb, lib_builders, lb_src_files) def build(self): libs = [] - for lb in self.dependencies: + for lb in self.depbuilders: libs.extend(lb.build()) # copy shared information to self env for key in ("CPPPATH", "LIBPATH", "LIBS", "LINKFLAGS"): @@ -265,15 +318,15 @@ class ProjectAsLibBuilder(LibBuilderBase): # skip for project, options are already processed pass - def search_dependencies(self, lib_builders, search_paths=None): + def search_deps_recursive(self, lib_builders, search_paths=None): for lib_name in self.env.get("LIB_FORCE", []): for lb in lib_builders: - if lb.name == lib_name and lb not in self.dependencies: - self.depends_on(lb) - lb.search_dependencies(lib_builders) + if lb.name == lib_name: + if lb not in self.depbuilders: + self.depend_recursive(lb, lib_builders) break - return LibBuilderBase.search_dependencies(self, lib_builders, - search_paths) + return LibBuilderBase.search_deps_recursive(self, lib_builders, + search_paths) def build(self): # dummy mark that project is built @@ -422,7 +475,7 @@ def GetLibBuilders(env): lb = LibBuilderFactory.new(env, join(libs_dir, item)) if lb.name in env.get("LIB_IGNORE", []): if not env.GetOption("silent"): - print "Ignored library " + lb.path + sys.stderr.write("Ignored library %s\n" % lb.path) continue if compat_level > 1 and not lb.is_platform_compatible(env[ 'PIOPLATFORM']): @@ -444,14 +497,14 @@ def BuildDependentLibraries(env, src_dir): def print_deps_tree(root, level=0): margin = "| " * (level) - for lb in root.dependencies: + for lb in root.depbuilders: title = "<%s>" % lb.name if lb.version: title += " v%s" % lb.version if not env.GetOption("silent"): title += " (%s)" % lb.path print "%s|-- %s" % (margin, title) - if lb.dependencies: + if lb.depbuilders: print_deps_tree(lb, level + 1) lib_builders = env.GetLibBuilders() @@ -461,9 +514,9 @@ def BuildDependentLibraries(env, src_dir): project = ProjectAsLibBuilder(env, src_dir) project.env = env - project.search_dependencies(lib_builders) + project.search_deps_recursive(lib_builders) - if project.dependencies: + if project.depbuilders: print "Library Dependency Map" print_deps_tree(project) else: From 22e67e6fdd9186d3120210180426cfaf43bf8d76 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 31 Jul 2016 15:46:57 +0300 Subject: [PATCH 080/284] Rename "lib_compat_level" to "lib_compat_mode" --- HISTORY.rst | 2 +- docs/faq.rst | 4 ++-- docs/projectconf.rst | 14 +++++++------- platformio/builder/main.py | 2 +- platformio/builder/tools/piolib.py | 8 ++++---- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index b9a19c34..763eb9d3 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -20,7 +20,7 @@ PlatformIO 3.0 + Check library compatibility with project environment before building (`issue #415 `_) + Control Library Dependency Finder for compatibility using - `lib_compat_level `__ + `lib_compat_mode `__ option + Custom library storages/directories with `lib_extra_dirs `__ option diff --git a/docs/faq.rst b/docs/faq.rst index 72b13163..e8f650d5 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -57,12 +57,12 @@ order: 2. :ref:`projectconf_pio_lib_dir` 3. :ref:`projectconf_pio_home_dir`/lib -Library Dependency Finder has a few key factors from :ref:`projectconf`: +Library Dependency Finder has a few controls from :ref:`projectconf`: * :ref:`projectconf_lib_ignore` * :ref:`projectconf_lib_deep_search` * :ref:`projectconf_lib_extra_dirs` -* :ref:`projectconf_lib_compat_level` +* :ref:`projectconf_lib_compat_mode` Command completion in Terminal ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 6f5ae26f..3f4a9005 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -729,25 +729,25 @@ Example: [env:custom_lib_dirs] lib_extra_dirs = /path/to/private/dir1,/path/to/private/dir2 -.. _projectconf_lib_compat_level: +.. _projectconf_lib_compat_mode: -``lib_compat_level`` -^^^^^^^^^^^^^^^^^^^^ +``lib_compat_mode`` +^^^^^^^^^^^^^^^^^^^ Please make sure to read :ref:`faq_ldf` guides first. -Library compatibility level that allows to control Library Dependency Finder +Library compatibility mode that allows to control Library Dependency Finder strictness. If library contains manifest file (:ref:`library_config`, ``library.properties``, ``module.json``), then LDF check compatibility of this -library with real build environment. Available compatibility levels: +library with real build environment. Available compatibility modes: -* ``0`` - don't check for compatibility (disable) +* ``0`` - don't check for compatibility * ``1`` - check for the compatibility with :ref:`projectconf_env_framework` from build environment * ``2`` - check for the compatibility with :ref:`projectconf_env_framework` and :ref:`projectconf_env_platform` from build environment. -By default, this value is set to ``lib_compat_level = 1`` and means that LDF +By default, this value is set to ``lib_compat_mode = 1`` and means that LDF will check only for framework compatibility. ----------- diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 1fc1d079..40184898 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -45,7 +45,7 @@ commonvars.AddVariables( # library options ("LIB_DEEP_SEARCH",), - ("LIB_COMPAT_LEVEL",), + ("LIB_COMPAT_MODE",), ("LIB_IGNORE",), ("LIB_FORCE",), ("LIB_EXTRA_DIRS",), diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index ce1a110a..7e94f784 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -463,7 +463,7 @@ def GetLibBuilders(env): env_frameworks = [ f.lower().strip() for f in env.get("PIOFRAMEWORK", "").split(",") ] - compat_level = int(env.get("LIB_COMPAT_LEVEL", 1)) + compat_mode = int(env.get("LIB_COMPAT_MODE", 1)) for libs_dir in env['LIBSOURCE_DIRS']: libs_dir = env.subst(libs_dir) @@ -477,14 +477,14 @@ def GetLibBuilders(env): if not env.GetOption("silent"): sys.stderr.write("Ignored library %s\n" % lb.path) continue - if compat_level > 1 and not lb.is_platform_compatible(env[ + if compat_mode > 1 and not lb.is_platform_compatible(env[ 'PIOPLATFORM']): if not env.GetOption("silent"): sys.stderr.write("Platform incompatible library %s\n" % lb.path) continue - if compat_level > 0 and not any([lb.is_framework_compatible(f) - for f in env_frameworks]): + if compat_mode > 0 and not any([lb.is_framework_compatible(f) + for f in env_frameworks]): if not env.GetOption("silent"): sys.stderr.write("Framework incompatible library %s\n" % lb.path) From 513577958fe6c50434d2fc16f4f4d7c96e6a4371 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 1 Aug 2016 00:14:22 +0300 Subject: [PATCH 081/284] Introduce "Library Dependency Finder" --- docs/faq.rst | 31 ----- docs/index.rst | 1 + docs/librarymanager/ldf.rst | 171 +++++++++++++++++++++++ docs/platforms/unit_testing.rst | 2 + docs/projectconf.rst | 211 +++++++++++++++-------------- docs/userguide/cmd_test.rst | 2 + platformio/builder/main.py | 25 ++-- platformio/builder/tools/piolib.py | 6 +- platformio/exception.py | 2 +- platformio/util.py | 71 +++++----- 10 files changed, 337 insertions(+), 185 deletions(-) create mode 100644 docs/librarymanager/ldf.rst diff --git a/docs/faq.rst b/docs/faq.rst index e8f650d5..75ed3cfb 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -33,37 +33,6 @@ What is ``.pioenvs`` directory Please refer to :ref:`projectconf_pio_envs_dir`. -.. _faq_ldf: - -How works Library Dependency Finder (LDF) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Library Dependency Finder is a part of PlatformIO Library Build System. It -operates with the C/C++ source files and looks for ``#include <...>`` -directives. Also, LDF interprets C Preprocessor conditional macros -(``#if``, ``ifdef``, etc.). Library Dependency Finder starts -work from analyzing source files from :ref:`projectconf_pio_src_dir` by default. - -If project or library contains own ``dependencies`` list (see -:ref:`libjson_dependencies`), the LDF will not looking for dependencies in -the source code. The specified libraries will be built automatically without -check. - -There are different library storages where Library Dependency Finder looks for -dependencies. These storages/folders have priority. LDF operates in the next -order: - -1. :ref:`projectconf_lib_extra_dirs` -2. :ref:`projectconf_pio_lib_dir` -3. :ref:`projectconf_pio_home_dir`/lib - -Library Dependency Finder has a few controls from :ref:`projectconf`: - -* :ref:`projectconf_lib_ignore` -* :ref:`projectconf_lib_deep_search` -* :ref:`projectconf_lib_extra_dirs` -* :ref:`projectconf_lib_compat_mode` - Command completion in Terminal ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/index.rst b/docs/index.rst index 2db1a873..3b95e020 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -119,6 +119,7 @@ Contents Quickstart User Guide + librarymanager/ldf librarymanager/config librarymanager/creating diff --git a/docs/librarymanager/ldf.rst b/docs/librarymanager/ldf.rst new file mode 100644 index 00000000..c3526436 --- /dev/null +++ b/docs/librarymanager/ldf.rst @@ -0,0 +1,171 @@ +.. Copyright 2014-present Ivan Kravets + 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. + +.. _ldf: + +Library Dependency Finder (LDF) +=============================== + +.. versionadded:: 3.0 + +Library Dependency Finder is a core part of PlatformIO Build System that +operates with the C/C++ source files and looks for ``#include ...`` +directives. + +In spite of the fact that Library Dependency Finder is written in pure Python, +it interprets (emulates) :ref:`ldf_c_cond_syntax` (``#ifdef``, ``if``, ``defined``, +``else``, and ``elif``) without calling ``gcc -E``. This approach allows +significantly reduce total compilation time. + +Library Dependency Finder has controls that can be set up in :ref:`projectconf`: + +.. hlist:: + :columns: 3 + + * :ref:`projectconf_lib_extra_dirs` + * :ref:`projectconf_lib_force` + * :ref:`projectconf_lib_ignore` + * :ref:`projectconf_lib_compat_mode` + * :ref:`projectconf_lib_ldf_mode` + +----------- + +.. contents:: + +Storage +------- + +There are different storages/folders where Library Dependency Finder looks for +libraries. These folders/path have priority and LDF operates in the next order: + +1. :ref:`projectconf_lib_extra_dirs` - extra storages per build environment +2. :ref:`projectconf_pio_lib_dir` - own/private library storage per project +3. :ref:`projectconf_pio_piolibdeps_dir` - project dependencies storage used by + :ref:`librarymanager` +4. :ref:`projectconf_pio_home_dir`/lib - global storage per all projects. + +.. _ldf_mode: + +Dependency Finder Mode +---------------------- + +Library Dependency Finder starts work from analyzing source files of the +project (:ref:`projectconf_pio_src_dir`) and can work in the next modes: + +* ``0`` - "manual mode", does not process source files of a project and + dependent libraries. Builds only the libraries that are specified in + manifests (:ref:`library_config`, ``module.json``) or in the :ref:`projectconf`. +* ``1`` - parses ALL C/C++ source code of the project and follows only by + nested includes/chain (``#include ...``) from the libraries. +* ``2`` - **default** - parses ALL C/C++ source code of the project and parses + ALL C/C++ source code of the each dependent library (recursively). + +This mode can be changed using :ref:`projectconf_lib_ldf_mode` option in +:ref:`projectconf`. + +A difference between ``1`` and ``2`` modes. For example, there are 2 libraries: + +* Library "Foo" with files: + + - ``Foo/foo.h`` + - ``Foo/foo.cpp`` + +* Library "Bar" with files: + + - ``Bar/bar.h`` + - ``Bar/bar.cpp`` + +:Case 1: + + * ``lib_ldf_mode = 1`` + * ``Foo/foo.h`` depends on "Bar" library (contains ``#include ``) + * ``#include `` is located in one of the project source files + + Here are nested includes (``project file > foo.h > bar.h``) and ``LDF`` + will find both libraries "Foo" and "Bar". + +:Case 2: + + * ``lib_ldf_mode = 1`` + * ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include ``) + * ``#include `` is located in one of the project source files + + In this case, ``LDF`` will not find "Bar" library because it doesn't know + about CPP file (``Foo/foo.cpp``). + +:Case 3: + + * ``lib_ldf_mode = 2`` + * ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include ``) + * ``#include `` is located in one of the project source files + + Firstly, ``LDF`` finds "Foo" library, then it parses all sources from "Foo" + library and finds ``Foo/foo.cpp`` that depends on ``#include ``. + Secondly, it will parse all sources from "Bar" library and this operation + continues until all dependent libraries will not be parsed. + +.. _ldf_compat_mode: + +Compatibility Mode +------------------ + +Compatibility mode allows to control strictness of Library Dependency Finder. +If library contains one of manifest file (:ref:`library_config`, +``library.properties``, ``module.json``), then LDF check compatibility of this +library with real build environment. Available compatibility modes: + +* ``0`` - does not check for compatibility (is not recommended) +* ``1`` - **default** - checks for the compatibility with + :ref:`projectconf_env_framework` from build environment +* ``2`` - checks for the compatibility with :ref:`projectconf_env_framework` + and :ref:`projectconf_env_platform` from build environment. + +This mode can be changed using :ref:`projectconf_lib_compat_mode` option in +:ref:`projectconf`. + +Manual dependencies +------------------- + +If project or library contains own ``dependencies`` list (see +:ref:`libjson_dependencies`), the LDF will not looking for dependencies in +the source code. The specified libraries will be built automatically without +check. + +.. _ldf_c_cond_syntax: + +C Preprocessor conditional syntax +--------------------------------- + +In spite of the fact that Library Dependency Finder is written in pure Python, +it interprets (emulates) `C Preprocessor conditional syntax `_ +(``#ifdef``, ``if``, ``defined``, ``else``, and ``elif``) without calling +``gcc -E``. For example, + +``platformio.ini`` + +.. code-block:: ini + + [env:myenv] + build_flags = -D MY_PROJECT_VERSION=13 + +``mylib.h`` + +.. code-block:: c + + #ifdef PROJECT_VERSION + // include common file for the project + #include "my_common.h" + #endif + + #if PROJECT_VERSION < 10 + // this include will be ignored because does not satisfy condition above + #include "my_old.h" + #endif diff --git a/docs/platforms/unit_testing.rst b/docs/platforms/unit_testing.rst index 19f51e1c..809eb76c 100644 --- a/docs/platforms/unit_testing.rst +++ b/docs/platforms/unit_testing.rst @@ -14,6 +14,8 @@ Unit Testing ============ +.. versionadded:: 3.0 + `Unit Testing (wiki) `_ 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, diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 3f4a9005..748d0478 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -44,8 +44,8 @@ Options ``home_dir`` ^^^^^^^^^^^^ -Is used to store platform toolchains, frameworks, external libraries, -service data and etc. +Is used to store platform toolchains, frameworks, global libraries for +:ref: `ldf`, service data and etc. A default value is User's home directory: @@ -60,18 +60,59 @@ This option can be overridden by global environment variable ``lib_dir`` ^^^^^^^^^^^ -This directory is used to store external libraries downloaded by -:ref:`librarymanager`. +You can put here your own/private libraries. The source code of each library +should be placed in separate directory, like +``lib/private_lib/[here are source files]``. This directory has the highest +priority for :ref:`ldf`. -A default value is ``%home_dir%/lib``. +A default value is ``lib`` that means that folder is located in the root of +project. This option can be overridden by global environment variable :envvar:`PLATFORMIO_LIB_DIR`. -.. note:: - You can put here your own/private libraries. The source code of each - library should be placed in separate directory. For example, - ``%lib_dir%/private_lib/[here are source files]``. +For example, see how can be organized ``Foo`` and ``Bar`` libraries: + +.. code:: + + |--lib + | |--Bar + | | |--docs + | | |--examples + | | |--src + | | |- Bar.c + | | |- Bar.h + | |--Foo + | | |- Foo.c + | | |- Foo.h + |- platformio.ini + |--src + |- main.c + + +Then in ``src/main.c`` you should use: + +.. code-block:: c + + #include + #include + + // rest H/C/CPP code + +PlatformIO will find your libraries automatically, configure preprocessor's +include paths and build them. + +.. _projectconf_pio_piolibdeps_dir: + +``piolibdeps_dir`` +^^^^^^^^^^^^^^^^^^ + +Internal storage where :ref:`librarymanager` will install project dependencies. +A default value is ``.piolibdeps`` that means that folder is located in the root of +project. + +This option can be overridden by global environment variable +:envvar:`PLATFORMIO_PIOLIBDEPS_DIR`. .. _projectconf_pio_src_dir: @@ -79,10 +120,8 @@ This option can be overridden by global environment variable ^^^^^^^^^^^ A path to project's source directory. PlatformIO uses it for :ref:`cmd_run` -command. - -A default value is ``src`` which means that folder is located in the root of -project. +command. A default value is ``src`` that means that folder is located in the +root of project. This option can be overridden by global environment variable :envvar:`PLATFORMIO_SRC_DIR`. @@ -110,7 +149,7 @@ fast! then PlatformIO will remove this folder automatically. It will be created on the next build operation. -A default value is ``.pioenvs`` which means that folder is located in the root of +A default value is ``.pioenvs`` that means that folder is located in the root of project. This option can be overridden by global environment variable @@ -127,8 +166,7 @@ This option can be overridden by global environment variable ^^^^^^^^^^^^ Data directory to store contents and :ref:`platform_espressif_uploadfs`. - -A default value is ``data`` which means that folder is located in the root of +A default value is ``data`` that means that folder is located in the root of project. This option can be overridden by global environment variable @@ -139,9 +177,8 @@ This option can be overridden by global environment variable ``test_dir`` ^^^^^^^^^^^^ -Directory for :ref:`unit_testing`. - -A default value is ``test`` which means that folder is located in the root of +Directory where :ref:`unit_testing` engine will look for the tests. +A default value is ``test`` that means that folder is located in the root of project. This option can be overridden by global environment variable @@ -206,6 +243,9 @@ For example, ``[env:hello_world]``. General options ~~~~~~~~~~~~~~~ +.. contents:: + :local: + .. _projectconf_env_platform: ``platform`` @@ -265,6 +305,9 @@ using `PlatformIO Embedded Boards Explorer `_. Board options ~~~~~~~~~~~~~ +.. contents:: + :local: + ``board_mcu`` ^^^^^^^^^^^^^ @@ -309,8 +352,11 @@ This option isn't available for the all development platforms. The only Flash chip interface mode. This option isn't available for the all development platforms. The only :ref:`platform_espressif` supports it. -Building options -~~~~~~~~~~~~~~~~ +Build options +~~~~~~~~~~~~~ + +.. contents:: + :local: .. _projectconf_build_flags: @@ -456,7 +502,7 @@ be applied in theirs order. By default, ``src_filter`` is predefined to ``+<*> -<.git/> - - - - -``, -which means "includes ALL files, then +that means "includes ALL files, then exclude ``.git`` and ``svn`` repository folders, ``example`` ... folder. This option can be set by global environment variable @@ -529,8 +575,11 @@ The list with available targets is located in :option:`platformio run --target`. When no targets are defined, *PlatformIO* will build only sources by default. -Uploading options -~~~~~~~~~~~~~~~~~ +Upload options +~~~~~~~~~~~~~~ + +.. contents:: + :local: .. _projectconf_upload_port: @@ -587,6 +636,9 @@ development platforms. The only :ref:`platform_espressif` supports it. Library options ~~~~~~~~~~~~~~~ +.. contents:: + :local: + ``lib_install`` ^^^^^^^^^^^^^^^ @@ -603,12 +655,17 @@ Example: [env:depends_on_some_libs] lib_install = 1,13,19 +.. _projectconf_lib_force: + ``lib_force`` ^^^^^^^^^^^^^ -Force Library Build System to build specified libraries if they even are not -included in the project source code. Also, these libraries will be processed -in the first order. +.. seealso:: + Please make sure to read :ref:`ldf` guide first. + +Force Library Dependency Finder to depend on the specified libraries if +they even are not included in the project source code. Also, these +libraries will be processed in the first order. The correct value for this option is library name (not folder name). In the most cases, library name is pre-defined in manifest file @@ -627,7 +684,8 @@ Example: ``lib_ignore`` ^^^^^^^^^^^^^^ -Please make sure to read :ref:`faq_ldf` guides first. +.. seealso:: + Please make sure to read :ref:`ldf` guide first. Specify libraries which should be ignored by Library Dependency Finder. @@ -643,72 +701,14 @@ Example: [env:ignore_some_libs] lib_ignore = SPI, Ethernet -.. _projectconf_lib_deep_search: - -``lib_deep_search`` -^^^^^^^^^^^^^^^^^^^ - -Please make sure to read :ref:`faq_ldf` guides first. - -By default, this option is turned ON (``lib_deep_search = true``) and means -that Library Dependency Finder will analyze ALL source files from the library -and will try automatically find all dependencies. - -If you want to disable deep search, please set this option to ``false``. -Note! Some libraries depend on other libraries and the -``#include <...>`` directives for these libraries are not declared in the -"main" header file that is used by upper library. If LDF is turned OFF -(``lib_deep_search = false``), it will not handle these libraries automatically -because it doesn't analyze "each source file" of the nested libraries -(only "nested includes/chain"). - -For example, there are 2 libraries: - -* Library "Foo" with files: - - - ``Foo/foo.h`` - - ``Foo/foo.cpp`` - -* Library "Bar" with files: - - - ``Bar/bar.h`` - - ``Bar/bar.cpp`` - -:Case 1: - - * ``lib_deep_search = false`` - * ``Foo/foo.h`` depends on "Bar" library (contains ``#include ``) - * ``#include `` is located in one of the project source files - - Here are nested includes (``project file > foo.h > bar.h``) and ``LDF`` will - find both libraries "Foo" and "Bar". - -:Case 2: - - * ``lib_deep_search = false`` - * ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include ``) - * ``#include `` is located in one of the project source files - - In this case, ``LDF`` will not find "Bar" library because it doesn't know - about CPP file (``Foo/foo.cpp``). - -:Case 3: - - * ``lib_deep_search = true`` - * ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include ``) - * ``#include `` is located in one of the project source files - - Firstly, ``LDF`` finds "Foo" library, then it parses all sources from "Foo" - library and finds ``Foo/foo.cpp`` that depends on ``#include ``. - Secondly, it will parse all sources from "Bar" library and this operation - continues until all dependent libraries will not be parsed. - .. _projectconf_lib_extra_dirs: ``lib_extra_dirs`` ^^^^^^^^^^^^^^^^^^ -Please make sure to read :ref:`faq_ldf` guides first. +.. versionadded:: 3.0 +.. seealso:: + Please make sure to read :ref:`ldf` guide first. A list with extra directories/storages where Library Dependency Finder will look for dependencies. Multiple paths are allowed. Please separate them @@ -729,23 +729,34 @@ Example: [env:custom_lib_dirs] lib_extra_dirs = /path/to/private/dir1,/path/to/private/dir2 +.. _projectconf_lib_ldf_mode: + +``lib_ldf_mode`` +^^^^^^^^^^^^^^^^ + +.. versionadded:: 3.0 +.. seealso:: + Please make sure to read :ref:`ldf` guide first. + +Library Dependency Finder starts work from analyzing source files of the +project (:ref:`projectconf_pio_src_dir`) and can work in the different modes +(see :ref:`ldf_mode`). + +By default, this value is set to ``lib_ldf_mode = 2`` and means that LDF +will parse ALL C/C++ source code of the project and will parse ALL C/C++ +source code of the each dependent library (recursively). + .. _projectconf_lib_compat_mode: ``lib_compat_mode`` ^^^^^^^^^^^^^^^^^^^ -Please make sure to read :ref:`faq_ldf` guides first. +.. versionadded:: 3.0 +.. seealso:: + Please make sure to read :ref:`ldf` guide first. -Library compatibility mode that allows to control Library Dependency Finder -strictness. If library contains manifest file (:ref:`library_config`, -``library.properties``, ``module.json``), then LDF check compatibility of this -library with real build environment. Available compatibility modes: - -* ``0`` - don't check for compatibility -* ``1`` - check for the compatibility with :ref:`projectconf_env_framework` - from build environment -* ``2`` - check for the compatibility with :ref:`projectconf_env_framework` - and :ref:`projectconf_env_platform` from build environment. +Library compatibility mode allows to control strictness of Library Dependency +Finder. More details :ref:`ldf_compat_mode`. By default, this value is set to ``lib_compat_mode = 1`` and means that LDF will check only for framework compatibility. diff --git a/docs/userguide/cmd_test.rst b/docs/userguide/cmd_test.rst index 628be957..0749f6ec 100644 --- a/docs/userguide/cmd_test.rst +++ b/docs/userguide/cmd_test.rst @@ -14,6 +14,8 @@ platformio test =============== +.. versionadded:: 3.0 + .. contents:: Usage diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 40184898..493f1a22 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -44,7 +44,7 @@ commonvars.AddVariables( ("SRC_FILTER",), # library options - ("LIB_DEEP_SEARCH",), + ("LIB_LDF_MODE",), ("LIB_COMPAT_MODE",), ("LIB_IGNORE",), ("LIB_FORCE",), @@ -63,41 +63,35 @@ commonvars.AddVariables( ("UPLOAD_SPEED",), ("UPLOAD_FLAGS",), ("UPLOAD_RESETMETHOD",) -) +) # yapf: disable DefaultEnvironment( tools=[ "ar", "as", "gcc", "g++", "gnulink", "platformio", "devplatform", "piolib", "piotest", "pioupload", "pioar", "piomisc" - ], + ], # yapf: disable toolpath=[join(util.get_source_dir(), "builder", "tools")], variables=commonvars, # Propagating External Environment ENV=environ, - UNIX_TIME=int(time()), PROGNAME="program", - PIOHOME_DIR=util.get_home_dir(), PROJECT_DIR=util.get_project_dir(), - PROJECTLIB_DIR=util.get_projectlib_dir(), PROJECTSRC_DIR=util.get_projectsrc_dir(), PROJECTTEST_DIR=util.get_projecttest_dir(), PROJECTDATA_DIR=util.get_projectdata_dir(), - PIOENVS_DIR=util.get_pioenvs_dir(), - - BUILD_DIR=join("$PIOENVS_DIR", "$PIOENV"), + PROJECTPIOENVS_DIR=util.get_projectpioenvs_dir(), + BUILD_DIR=join("$PROJECTPIOENVS_DIR", "$PIOENV"), BUILDSRC_DIR=join("$BUILD_DIR", "src"), BUILDTEST_DIR=join("$BUILD_DIR", "test"), LIBSOURCE_DIRS=[ - "$PROJECTLIB_DIR", - util.get_lib_dir() + util.get_projectlib_dir(), util.get_projectlibdeps_dir(), + join("$PIOHOME_DIR", "lib") ], - - PYTHONEXE=normpath(sys.executable) -) + PYTHONEXE=normpath(sys.executable)) env = DefaultEnvironment() @@ -126,10 +120,9 @@ env.Prepend(LIBSOURCE_DIRS=env.get("LIB_EXTRA_DIRS", [])) env.LoadDevPlatform(commonvars) env.SConscriptChdir(0) -env.SConsignFile(join("$PIOENVS_DIR", ".sconsign.dblite")) +env.SConsignFile(join("$PROJECTPIOENVS_DIR", ".sconsign.dblite")) env.SConscript("$BUILD_SCRIPT") - if "UPLOAD_FLAGS" in env: env.Append(UPLOADERFLAGS=["$UPLOAD_FLAGS"]) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 7e94f784..bfa941da 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -194,7 +194,7 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes if not search_paths: search_paths = tuple() assert isinstance(search_paths, tuple) - deep_search = self.env.get("LIB_DEEP_SEARCH", "true").lower() == "true" + deep_search = int(self.env.get("LIB_LDF_MODE", 2)) == 2 if not self._scanned_paths and ( isinstance(self, ProjectAsLibBuilder) or deep_search): @@ -270,6 +270,10 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes "Error: Could not find `%s` dependency for `%s` " "library\n" % (item['name'], self.name)) self.env.Exit(2) + + # when LDF is disabled + if "LIB_LDF_MODE" in self.env and \ + int(self.env.get("LIB_LDF_MODE")) == 0: return lib_inc_map = {} diff --git a/platformio/exception.py b/platformio/exception.py index 9b117740..33a49e77 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -109,7 +109,7 @@ class FDSHASumMismatch(PlatformioException): "is not equal to remote '{2}'" -class NotPlatformProject(PlatformioException): +class NotPlatformIOProject(PlatformioException): MESSAGE = "Not a PlatformIO project. `platformio.ini` file has not been "\ "found in current working directory ({0}). To initialize new project "\ diff --git a/platformio/util.py b/platformio/util.py index 8cc9645b..2eeaec55 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -156,7 +156,7 @@ def _get_projconf_option_dir(name, default=None): if option_dir.startswith("~"): option_dir = expanduser(option_dir) return abspath(option_dir) - except exception.NotPlatformProject: + except exception.NotPlatformIOProject: pass return default @@ -180,13 +180,6 @@ def get_home_dir(): return home_dir -def get_lib_dir(): - return _get_projconf_option_dir( - "lib_dir", - join(get_home_dir(), "lib") - ) - - def get_source_dir(): curpath = abspath(__file__) if not isfile(curpath): @@ -201,29 +194,33 @@ def get_project_dir(): return os.getcwd() -def get_projectsrc_dir(): - return _get_projconf_option_dir( - "src_dir", - join(get_project_dir(), "src") - ) - - -def get_projecttest_dir(): - return _get_projconf_option_dir( - "test_dir", - join(get_project_dir(), "test") - ) +def is_platformio_project(project_dir=None): + if not project_dir: + project_dir = get_project_dir() + return isfile(join(project_dir, "platformio.ini")) def get_projectlib_dir(): - return join(get_project_dir(), "lib") + return _get_projconf_option_dir("lib_dir", join(get_project_dir(), "lib")) -def get_pioenvs_dir(): - path = _get_projconf_option_dir( - "envs_dir", - join(get_project_dir(), ".pioenvs") - ) +def get_projectlibdeps_dir(): + return _get_projconf_option_dir("libdeps_dir", + join(get_project_dir(), ".piolibdeps")) + + +def get_projectsrc_dir(): + return _get_projconf_option_dir("src_dir", join(get_project_dir(), "src")) + + +def get_projecttest_dir(): + return _get_projconf_option_dir("test_dir", join(get_project_dir(), + "test")) + + +def get_projectpioenvs_dir(): + path = _get_projconf_option_dir("envs_dir", + join(get_project_dir(), ".pioenvs")) if not isdir(path): os.makedirs(path) dontmod_path = join(path, "do-not-modify-files-here.url") @@ -247,18 +244,12 @@ def load_project_config(project_dir=None): if not project_dir: project_dir = get_project_dir() if not is_platformio_project(project_dir): - raise exception.NotPlatformProject(project_dir) + raise exception.NotPlatformIOProject(project_dir) cp = ConfigParser() cp.read(join(project_dir, "platformio.ini")) return cp -def is_platformio_project(project_dir=None): - if not project_dir: - project_dir = get_project_dir() - return isfile(join(project_dir, "platformio.ini")) - - def change_filemtime(path, time): os.utime(path, (time, time)) @@ -358,6 +349,12 @@ def get_request_defheaders(): )} +@memoized +def _api_request_session(): + import requests + return requests.Session() + + def get_api_result(path, params=None, data=None, skipdns=False): import requests result = None @@ -371,12 +368,14 @@ def get_api_result(path, params=None, data=None, skipdns=False): try: if data: - r = requests.post( + r = _api_request_session().post( url + path, params=params, data=data, headers=headers) else: - r = requests.get(url + path, params=params, headers=headers) - r.raise_for_status() + r = _api_request_session().get(url + path, + params=params, + headers=headers) result = r.json() + r.raise_for_status() except requests.exceptions.HTTPError as e: if result and "errors" in result: raise exception.APIRequestError(result['errors'][0]['title']) From e49994e205862eb1d11ad7fca7918e716b65dbfb Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 1 Aug 2016 00:16:52 +0300 Subject: [PATCH 082/284] Fix PyLint warning --- platformio/builder/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 493f1a22..714d7ca7 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -70,7 +70,7 @@ DefaultEnvironment( "ar", "as", "gcc", "g++", "gnulink", "platformio", "devplatform", "piolib", "piotest", "pioupload", "pioar", "piomisc" - ], # yapf: disable + ], # yapf: disable toolpath=[join(util.get_source_dir(), "builder", "tools")], variables=commonvars, From 34231327b73bf45d93e04f680f17bc604db8266a Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 1 Aug 2016 00:19:43 +0300 Subject: [PATCH 083/284] Minor fixes --- platformio/__init__.py | 2 +- platformio/commands/run.py | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 5f0228e9..6ac5d903 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev14") +VERSION = (3, 0, "0.dev15") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 9aaa9912..f29e053e 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -46,14 +46,13 @@ def cli(ctx, environment, target, upload_port, # pylint: disable=R0913,R0914 # clean obsolete .pioenvs dir if not disable_auto_clean: try: - _clean_pioenvs_dir(util.get_pioenvs_dir()) + _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_pioenvs_dir(), - fg="yellow" - ) + "build issues" % util.get_projectpioenvs_dir(), + fg="yellow") config = util.load_project_config() env_default = None @@ -105,8 +104,7 @@ class EnvironmentProcessor(object): RENAMED_OPTIONS = { "INSTALL_LIBS": "LIB_INSTALL", "IGNORE_LIBS": "LIB_IGNORE", - "LIB_USE": "LIB_FORCE", - "LIB_DFCYCLIC": "LIB_DEEP_SEARCH" + "LIB_USE": "LIB_FORCE" } def __init__(self, cmd_ctx, name, options, # pylint: disable=R0913 From ef535e399e24233f110976079dc615d385234973 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 1 Aug 2016 00:21:52 +0300 Subject: [PATCH 084/284] Cleanup docs --- docs/librarymanager/ldf.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/docs/librarymanager/ldf.rst b/docs/librarymanager/ldf.rst index c3526436..c1a8d79b 100644 --- a/docs/librarymanager/ldf.rst +++ b/docs/librarymanager/ldf.rst @@ -131,14 +131,6 @@ library with real build environment. Available compatibility modes: This mode can be changed using :ref:`projectconf_lib_compat_mode` option in :ref:`projectconf`. -Manual dependencies -------------------- - -If project or library contains own ``dependencies`` list (see -:ref:`libjson_dependencies`), the LDF will not looking for dependencies in -the source code. The specified libraries will be built automatically without -check. - .. _ldf_c_cond_syntax: C Preprocessor conditional syntax From e5b76687a8948698eb8ee1921350f4ca36a61cb1 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 1 Aug 2016 00:32:38 +0300 Subject: [PATCH 085/284] Minor changes for PyLint --- platformio/builder/tools/piolib.py | 55 ++++++++++++++++-------------- platformio/libmanager.py | 2 +- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index bfa941da..6249107f 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -144,6 +144,9 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes def build_dir(self): return join("$BUILD_DIR", "lib", self.name) + def get_inc_dirs(self, use_build_dir=False): + return [self.build_dir if use_build_dir else self.src_dir] + @property def build_flags(self): return None @@ -187,8 +190,31 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes exports={"env": self.env, "pio_lib_builder": self}) - def get_inc_dirs(self, use_build_dir=False): - return [self.build_dir if use_build_dir else self.src_dir] + def _process_dependencies(self, lib_builders): + if not self.dependencies: + return + for item in self.dependencies: + found = False + for lb in lib_builders: + if item['name'] != lb.name: + continue + elif "frameworks" in item and \ + not any([lb.is_framework_compatible(f) + for f in item["frameworks"]]): + continue + elif "platforms" in item and \ + not any([lb.is_platform_compatible(p) + for p in item["platforms"]]): + continue + found = True + self.depend_recursive(lb, lib_builders) + break + + if not found: + sys.stderr.write( + "Error: Could not find `%s` dependency for `%s` " + "library\n" % (item['name'], self.name)) + self.env.Exit(2) def _validate_search_paths(self, search_paths=None): if not search_paths: @@ -246,30 +272,7 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes def search_deps_recursive(self, lib_builders, search_paths=None): self._is_dependent = True - # if dependencies are specified, don't use automatic finder - if self.dependencies: - for item in self.dependencies: - found = False - for lb in lib_builders: - if item['name'] != lb.name: - continue - elif "frameworks" in item and \ - not any([lb.is_framework_compatible(f) - for f in item["frameworks"]]): - continue - elif "platforms" in item and \ - not any([lb.is_platform_compatible(p) - for p in item["platforms"]]): - continue - found = True - self.depend_recursive(lb, lib_builders) - break - - if not found: - sys.stderr.write( - "Error: Could not find `%s` dependency for `%s` " - "library\n" % (item['name'], self.name)) - self.env.Exit(2) + self._process_dependencies(lib_builders) # when LDF is disabled if "LIB_LDF_MODE" in self.env and \ diff --git a/platformio/libmanager.py b/platformio/libmanager.py index 964b10d0..8235d102 100644 --- a/platformio/libmanager.py +++ b/platformio/libmanager.py @@ -29,7 +29,7 @@ class LibraryManager(object): CONFIG_NAME = ".library.json" def __init__(self, lib_dir=None): - self.lib_dir = lib_dir or util.get_lib_dir() + self.lib_dir = lib_dir or join(util.get_home_dir(), "lib") @staticmethod def download(url, dest_dir): From c728b91914cc519940e8d0bb912a778db4f4108d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 1 Aug 2016 14:25:11 +0300 Subject: [PATCH 086/284] Check development version automatically --- platformio/commands/upgrade.py | 60 +++++++++++++++++++++++++--------- platformio/maintenance.py | 11 ++++--- platformio/util.py | 4 +++ 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/platformio/commands/upgrade.py b/platformio/commands/upgrade.py index 44e3b8ea..4f1f9b8e 100644 --- a/platformio/commands/upgrade.py +++ b/platformio/commands/upgrade.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,19 +13,20 @@ # limitations under the License. import os +import re import sys import click import requests -from platformio import __version__, exception, util +from platformio import VERSION, __version__, exception, util @click.command("upgrade", short_help="Upgrade PlatformIO to the latest version") def cli(): - last = get_latest_version() - if __version__ == last: + latest = get_latest_version() + if __version__ == latest: return click.secho( "You're up-to-date!\nPlatformIO %s is currently the " "newest version available." % __version__, fg="green" @@ -34,13 +35,7 @@ def cli(): click.secho("Please wait while upgrading PlatformIO ...", fg="yellow") - to_develop = False - try: - from pkg_resources import parse_version - to_develop = parse_version(last) < parse_version(__version__) - except ImportError: - pass - + to_develop = not all([c.isdigit() for c in latest if c != "."]) cmds = ( ["pip", "install", "--upgrade", "https://github.com/platformio/platformio/archive/develop.zip" @@ -100,10 +95,43 @@ WARNING! Don't use `sudo` for the rest PlatformIO commands. def get_latest_version(): try: - pkgdata = requests.get( - "https://pypi.python.org/pypi/platformio/json", - headers=util.get_request_defheaders() - ).json() - return pkgdata['info']['version'] + if not isinstance(VERSION[2], int): + try: + return get_develop_latest_version() + except: # pylint: disable=bare-except + pass + return get_pypi_latest_version() except: raise exception.GetLatestVersionError() + + +def get_develop_latest_version(): + version = None + r = requests.get( + "https://raw.githubusercontent.com/platformio/platformio" + "/develop/platformio/__init__.py", + headers=util.get_request_defheaders() + ) + r.raise_for_status() + for line in r.text.split("\n"): + line = line.strip() + if not line.startswith("VERSION"): + continue + match = re.match(r"VERSION\s*=\s*\(([^\)]+)\)", line) + if not match: + continue + version = match.group(1) + for c in (" ", "'", '"'): + version = version.replace(c, "") + version = ".".join(version.split(",")) + assert version + return version + + +def get_pypi_latest_version(): + r = requests.get( + "https://pypi.python.org/pypi/platformio/json", + headers=util.get_request_defheaders() + ) + r.raise_for_status() + return r.json()['info']['version'] diff --git a/platformio/maintenance.py b/platformio/maintenance.py index ad190080..5bc31f2c 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -67,8 +67,10 @@ def on_platformio_exception(e): class Upgrader(object): def __init__(self, from_version, to_version): - self.from_version = semantic_version.Version.coerce(from_version) - self.to_version = semantic_version.Version.coerce(to_version) + self.from_version = semantic_version.Version.coerce( + util.pepver_to_semver(from_version)) + self.to_version = semantic_version.Version.coerce( + util.pepver_to_semver(to_version)) self._upgraders = [ (semantic_version.Version("3.0.0"), self._upgrade_to_3_0_0) @@ -180,8 +182,9 @@ def check_platformio_upgrade(): app.set_state_item("last_check", last_check) latest_version = get_latest_version() - if (semantic_version.Version.coerce(latest_version) <= - semantic_version.Version.coerce(__version__)): + if semantic_version.Version.coerce(util.pepver_to_semver( + latest_version)) <= semantic_version.Version.coerce( + util.pepver_to_semver(__version__)): return terminal_width, _ = click.get_terminal_size() diff --git a/platformio/util.py b/platformio/util.py index 2eeaec55..d3ac1980 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -461,3 +461,7 @@ def where_is_program(program, envpath=None): return join(bin_dir, "%s.exe" % program) return program + + +def pepver_to_semver(pepver): + return re.sub(r"(\.\d+)\.?(dev|a|b|rc|post)", r"\1-\2", pepver, 1) From e3bf12f65ce63a4e91b131b868638d881cced047 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 1 Aug 2016 14:50:03 +0300 Subject: [PATCH 087/284] Rename test for platform command --- tests/commands/{test_platforms.py => test_platform.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/commands/{test_platforms.py => test_platform.py} (100%) diff --git a/tests/commands/test_platforms.py b/tests/commands/test_platform.py similarity index 100% rename from tests/commands/test_platforms.py rename to tests/commands/test_platform.py From e60c2a6ba1515a3fc8560cb6e921fb294204df8a Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 1 Aug 2016 17:05:48 +0300 Subject: [PATCH 088/284] Improve base package manager; VCS and package ID support --- docs/userguide/platforms/cmd_install.rst | 60 +-- docs/userguide/platforms/cmd_uninstall.rst | 6 +- docs/userguide/platforms/cmd_update.rst | 77 ++-- platformio/commands/platform.py | 99 ++--- platformio/commands/run.py | 8 +- platformio/commands/test.py | 6 +- platformio/exception.py | 18 +- platformio/maintenance.py | 8 +- platformio/managers/package.py | 448 ++++++++++++--------- platformio/managers/platform.py | 94 +++-- platformio/vcsclient.py | 122 ++++-- tests/commands/test_platform.py | 89 +++- tests/test_managers.py | 66 +++ 13 files changed, 668 insertions(+), 433 deletions(-) create mode 100644 tests/test_managers.py diff --git a/docs/userguide/platforms/cmd_install.rst b/docs/userguide/platforms/cmd_install.rst index c43c3123..3ada1992 100644 --- a/docs/userguide/platforms/cmd_install.rst +++ b/docs/userguide/platforms/cmd_install.rst @@ -22,7 +22,7 @@ Usage .. code-block:: bash # install platform by name - platformio platform install [OPTIONS] PLATFORM + platformio platform install [OPTIONS] [PLATFORM...] # install specific platform version using Semantic Versioning platformio platform install [OPTIONS] PLATFORM@X.Y.Z @@ -45,10 +45,16 @@ There are several predefined aliases for packages, such as: Local ~~~~~ -PlatformIO supports installing development platform from local directory. Here -is supported form: +PlatformIO supports installing development platform from local directory or +archive. Need to use ``file://`` prefix before local path. Also, platform +directory or archive should contain ``platform.json`` manifest. * ``file:///local/path/to/the/platform/dir`` +* ``file:///local/path/to/the/platform.zip`` +* ``file:///local/path/to/the/platform.tar.gz`` + +Remote +~~~~~~ VCS ~~~ @@ -135,34 +141,38 @@ Examples .. code-block:: bash $ platformio platform install atmelavr - Installing platform atmelavr @ latest: + PlatformManager: Installing atmelavr Downloading... Unpacking [####################################] 100% - Installing package tool-scons @ >=2.3.0,<2.6.0: + atmelavr @ 0.0.0 has been successfully installed! + PackageManager: Installing tool-scons @ >=2.3.0,<2.6.0 Downloading [####################################] 100% Unpacking [####################################] 100% - Installing package toolchain-atmelavr @ ~1.40801.0: + tool-scons @ 2.4.1 has been successfully installed! + PackageManager: Installing toolchain-atmelavr @ ~1.40801.0 Downloading [####################################] 100% Unpacking [####################################] 100% + toolchain-atmelavr @ 1.40801.0 has been successfully installed! The platform 'atmelavr' has been successfully installed! The rest of packages will be installed automatically depending on your build environment. - 2. Install :ref:`platform_atmelavr` with ``uploader`` utility only and skip default packages .. code-block:: bash - $ platformio platform install atmelavr --skip-default-package --with-package=uploader - Installing platform atmelavr @ latest: + PlatformManager: Installing atmelavr Downloading [####################################] 100% Unpacking [####################################] 100% - Installing package tool-micronucleus @ ~1.200.0: + atmelavr @ 0.0.0 has been successfully installed! + PackageManager: Installing tool-micronucleus @ ~1.200.0 Downloading [####################################] 100% Unpacking [####################################] 100% - Installing package tool-avrdude @ >=1.60001.0,<1.60101.0: + tool-micronucleus @ 1.200.0 has been successfully installed! + PackageManager: Installing tool-avrdude @ ~1.60001.0 Downloading [####################################] 100% Unpacking [####################################] 100% + tool-avrdude @ 1.60001.1 has been successfully installed! The platform 'atmelavr' has been successfully installed! The rest of packages will be installed automatically depending on your build environment. @@ -171,27 +181,31 @@ Examples .. code-block:: bash $ platformio platform install https://github.com/platformio/platform-atmelavr.git - Installing platform https://github.com/platformio/platform-atmelavr.git @ latest: + + PlatformManager: Installing platform-atmelavr git version 2.7.4 (Apple Git-66) - Cloning into '/Users/ikravets/.platformio/platforms/installing-XMIsAE-package'... - remote: Counting objects: 172, done. - remote: Compressing objects: 100% (51/51), done. - remote: Total 172 (delta 109), reused 168 (delta 109), pack-reused 0 - Receiving objects: 100% (172/172), 38.18 KiB | 0 bytes/s, done. - Resolving deltas: 100% (109/109), done. + Cloning into '/Volumes/MEDIA/tmp/pio3_test_projects/arduino-digihead-master/home_dir/platforms/installing-U3ucN0-package'... + remote: Counting objects: 176, done. + remote: Compressing objects: 100% (55/55), done. + remote: Total 176 (delta 114), reused 164 (delta 109), pack-reused 0 + Receiving objects: 100% (176/176), 38.86 KiB | 0 bytes/s, done. + Resolving deltas: 100% (114/114), done. Checking connectivity... done. Submodule 'examples/arduino-external-libs/lib/OneWire' (https://github.com/PaulStoffregen/OneWire.git) registered for path 'examples/arduino-external-libs/lib/OneWire' Cloning into 'examples/arduino-external-libs/lib/OneWire'... - remote: Counting objects: 87, done. - remote: Total 87 (delta 0), reused 0 (delta 0), pack-reused 87 - Unpacking objects: 100% (87/87), done. + remote: Counting objects: 91, done. + remote: Total 91 (delta 0), reused 0 (delta 0), pack-reused 91 + Unpacking objects: 100% (91/91), done. Checking connectivity... done. Submodule path 'examples/arduino-external-libs/lib/OneWire': checked out '57c18c6de80c13429275f70875c7c341f1719201' - Installing package tool-scons @ >=2.3.0,<2.6.0: + atmelavr @ 0.0.0 has been successfully installed! + PackageManager: Installing tool-scons @ >=2.3.0,<2.6.0 Downloading [####################################] 100% Unpacking [####################################] 100% - Installing package toolchain-atmelavr @ ~1.40801.0: + tool-scons @ 2.4.1 has been successfully installed! + PackageManager: Installing toolchain-atmelavr @ ~1.40801.0 Downloading [####################################] 100% Unpacking [####################################] 100% + toolchain-atmelavr @ 1.40801.0 has been successfully installed! The platform 'https://github.com/platformio/platform-atmelavr.git' has been successfully installed! The rest of packages will be installed automatically depending on your build environment. diff --git a/docs/userguide/platforms/cmd_uninstall.rst b/docs/userguide/platforms/cmd_uninstall.rst index f1375d5e..3292f147 100644 --- a/docs/userguide/platforms/cmd_uninstall.rst +++ b/docs/userguide/platforms/cmd_uninstall.rst @@ -21,7 +21,7 @@ Usage .. code-block:: bash - platformio platform uninstall PLATFORM + platformio platform uninstall [PLATFORM...] # uninstall specific platform version using Semantic Versioning platformio platform uninstall PLATFORM@X.Y.Z @@ -39,7 +39,7 @@ Examples .. code-block:: bash $ platformio platform uninstall atmelavr - Uninstalling platform atmelavr @ latest: [OK] - Uninstalling package tool-scons @ 2.5.0: [OK] + Uninstalling platform atmelavr @ 0.0.0: [OK] + Uninstalling package tool-scons @ 2.4.1: [OK] Uninstalling package toolchain-atmelavr @ 1.40801.0: [OK] The platform 'atmelavr' has been successfully uninstalled! diff --git a/docs/userguide/platforms/cmd_update.rst b/docs/userguide/platforms/cmd_update.rst index 918aca8a..c48f802b 100644 --- a/docs/userguide/platforms/cmd_update.rst +++ b/docs/userguide/platforms/cmd_update.rst @@ -21,7 +21,10 @@ Usage .. code-block:: bash - platformio platform update + platformio platform update [OPTIONS] [PLATFORM...] + + # update specific platform version using Semantic Versioning + platformio platform update PLATFORM@X.Y.Z Description @@ -35,64 +38,48 @@ Options .. program:: platformio platform update .. option:: - --only-packages + -p, --only-packages Update only platform related packages. Do not update development platform build scripts, board configs and etc. +.. option:: + -c, --only-check + +Do not update, only check for new version + Examples -------- .. code-block:: bash $ platformio platform update - Platform atmelavr @ 0.0.0 + Platform atmelavr -------- - Updating platform atmelavr @ latest: - Versions: Current=0.0.0, Latest=0.0.0 [Up-to-date] - Updating package framework-arduinoavr @ ~1.10608.0: - Versions: Current=1.10608.0, Latest=1.10608.0 [Up-to-date] - Updating package toolchain-atmelavr @ ~1.40801.0: - Versions: Current=1.40801.0, Latest=1.40801.0 [Up-to-date] - Updating package framework-simba @ ~1.500.0: - Versions: Current=1.500.0, Latest=1.500.0 [Up-to-date] - Updating package tool-scons @ >=2.3.0,<2.6.0: - Versions: Current=2.5.0, Latest=2.5.0 [Up-to-date] + Updating atmelavr @ 0.0.0: [Up-to-date] + Updating framework-arduinoavr @ 1.10608.1: [Up-to-date] + Updating tool-avrdude @ 1.60001.1: [Up-to-date] + Updating toolchain-atmelavr @ 1.40801.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] - Platform atmelsam @ 0.0.0 + Platform espressif -------- - Updating platform atmelsam @ latest: - Versions: Current=0.0.0, Latest=0.0.0 [Up-to-date] - Updating package toolchain-gccarmnoneeabi @ >=1.40803.0,<1.40805.0: - Versions: Current=1.40804.0, Latest=1.40804.0 [Up-to-date] - Updating package framework-arduinosam @ ~1.10607.0: - Versions: Current=1.10607.0, Latest=1.10607.0 [Up-to-date] - Updating package framework-simba @ ~1.500.0: - Versions: Current=1.500.0, Latest=1.500.0 [Up-to-date] - Updating package framework-mbed @ ~1.117.0: - Versions: Current=1.117.0, Latest=1.117.0 [Up-to-date] - Updating package tool-scons @ >=2.3.0,<2.6.0: - Versions: Current=2.5.0, Latest=2.5.0 [Up-to-date] - Updating package tool-bossac @ ~1.10500.0: - Versions: Current=1.10500.0, Latest=1.10500.0 [Up-to-date] + Updating espressif @ 0.0.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + Updating toolchain-xtensa @ 1.40802.0: [Up-to-date] + Updating tool-esptool @ 1.409.0: [Up-to-date] + Updating tool-mkspiffs @ 1.102.0: [Up-to-date] + Updating framework-arduinoespressif @ 1.20300.0: [Up-to-date] + Updating sdk-esp8266 @ 1.10502.0: [Up-to-date] - Platform espressif @ 0.0.0 + Platform teensy -------- - Updating platform espressif @ latest: - Versions: Current=0.0.0, Latest=0.0.0 [Up-to-date] - Updating package tool-scons @ >=2.3.0,<2.6.0: - Versions: Current=2.5.0, Latest=2.5.0 [Up-to-date] - Updating package toolchain-xtensa @ ~1.40802.0: - Versions: Current=1.40802.0, Latest=1.40802.0 [Up-to-date] - Updating package framework-simba @ ~1.500.0: - Versions: Current=1.500.0, Latest=1.500.0 [Up-to-date] - Updating package tool-esptool @ ~1.408.0: - Versions: Current=1.408.0, Latest=1.408.0 [Up-to-date] - Updating package tool-mkspiffs @ ~1.102.0: - Versions: Current=1.102.0, Latest=1.102.0 [Up-to-date] - Updating package framework-arduinoespressif @ ~1.20200.0: - Versions: Current=1.20200.0, Latest=1.20200.0 [Up-to-date] - Updating package sdk-esp8266 @ ~1.10502.0: - Versions: Current=1.10502.0, Latest=1.10502.0 [Up-to-date] + Updating teensy @ 0.0.0: [Up-to-date] + Updating framework-arduinoteensy @ 1.128.0: [Up-to-date] + Updating tool-teensy @ 1.1.0: [Up-to-date] + Updating framework-mbed @ 1.121.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + Updating toolchain-atmelavr @ 1.40801.0: [Up-to-date] + Updating toolchain-gccarmnoneeabi @ 1.40804.0: [Up-to-date] ... diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index eb81ddac..9a6d7704 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -13,7 +13,6 @@ # limitations under the License. import json -from os.path import basename import click @@ -29,13 +28,14 @@ def cli(): def _print_platforms(platforms): for platform in platforms: click.echo("{name} ~ {title}".format( - name=click.style(platform['name'], fg="cyan"), + name=click.style( + platform['name'], fg="cyan"), title=platform['title'])) click.echo("=" * (3 + len(platform['name'] + platform['title']))) click.echo(platform['description']) click.echo() - click.echo("Home: %s" % - "http://platformio.org/platforms/" + platform['name']) + click.echo("Home: %s" % "http://platformio.org/platforms/" + platform[ + 'name']) if platform['packages']: click.echo("Packages: %s" % ", ".join(platform['packages'])) if "version" in platform: @@ -71,22 +71,19 @@ def platform_search(query, json_output): @cli.command("install", short_help="Install new platforms") -@click.argument("platforms", nargs=-1, required=True) +@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) def platform_install(platforms, with_package, without_package, skip_default_package): + pm = PlatformManager() for platform in platforms: - _platform = platform - _version = None - if any([s in platform for s in ("\\", "/")]): - _platform = basename(platform) - _version = platform - elif "@" in platform: - _platform, _version = platform.rsplit("@", 1) - if PlatformManager().install(_platform, _version, with_package, - without_package, skip_default_package): + 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 " @@ -94,12 +91,49 @@ def platform_install(platforms, with_package, without_package, fg="green") +@cli.command("uninstall", short_help="Uninstall platforms") +@click.argument("platforms", nargs=-1, required=True, metavar="[PLATFORM...]") +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") + + +@cli.command("update", short_help="Update installed Platforms") +@click.argument("platforms", nargs=-1, required=False, metavar="[PLATFORM...]") +@click.option( + "-p", + "--only-packages", + is_flag=True, + help="Update only platform packages") +@click.option( + "-c", + "--only-check", + is_flag=True, + help="Do not update, only check for new version") +def platform_update(platforms, only_packages, only_check): + pm = PlatformManager() + if not platforms: + platforms = set([m['name'] for m in pm.get_installed()]) + for platform in platforms: + click.echo("Platform %s" % click.style(platform, fg="cyan")) + click.echo("--------") + pm.update(platform, only_packages=only_packages, only_check=only_check) + click.echo() + + @cli.command("list", short_help="List installed platforms") @click.option("--json-output", is_flag=True) def platform_list(json_output): platforms = [] - for manifest in PlatformManager().get_installed(): - p = PlatformFactory.newPlatform(manifest['_manifest_path']) + pm = PlatformManager() + for manifest in pm.get_installed(): + p = PlatformFactory.newPlatform( + pm.get_manifest_path(manifest['__pkg_dir'])) platforms.append({ "name": p.name, "title": p.title, @@ -129,7 +163,8 @@ def platform_show(ctx, platform): raise exception.PlatformNotInstalledYet(platform) click.echo("{name} ~ {title}".format( - name=click.style(p.name, fg="cyan"), title=p.title)) + name=click.style( + p.name, fg="cyan"), title=p.title)) click.echo("=" * (3 + len(p.name + p.title))) click.echo(p.description) click.echo() @@ -152,35 +187,9 @@ def platform_show(ctx, platform): if p.get_package_type(name): click.echo("Type: %s" % p.get_package_type(name)) click.echo("Requirements: %s" % opts.get("version")) - click.echo("Installed: %s" % ( - "Yes" if name in installed_pkgs else "No (optional)")) + click.echo("Installed: %s" % ("Yes" if name in installed_pkgs else + "No (optional)")) if name in installed_pkgs: for key, value in installed_pkgs[name].items(): if key in ("url", "version", "description"): click.echo("%s: %s" % (key.title(), value)) - - -@cli.command("uninstall", short_help="Uninstall platforms") -@click.argument("platforms", nargs=-1, required=True) -def platform_uninstall(platforms): - for platform in platforms: - _platform = platform - _version = None - if "@" in platform: - _platform, _version = platform.rsplit("@", 1) - if PlatformManager().uninstall(_platform, _version): - click.secho("The platform '%s' has been successfully " - "uninstalled!" % platform, fg="green") - - -@cli.command("update", short_help="Update installed Platforms") -@click.option("--only-packages", is_flag=True) -def platform_update(only_packages): - pm = PlatformManager() - for manifest in pm.get_installed(): - click.echo("Platform %s @ %s" % ( - click.style(manifest['name'], fg="cyan"), manifest['version'])) - click.echo("--------") - pm.update(manifest['name'], manifest['version'], - only_packages=only_packages) - click.echo() diff --git a/platformio/commands/run.py b/platformio/commands/run.py index f29e053e..53fc96de 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -190,17 +190,13 @@ class EnvironmentProcessor(object): if "lib_install" in self.options: _autoinstall_libs(self.cmd_ctx, self.options['lib_install']) - platform = self.options['platform'] - version = None - if "@" in platform: - platform, version = platform.rsplit("@", 1) try: - p = PlatformFactory.newPlatform(platform, version) + p = PlatformFactory.newPlatform(self.options['platform']) except exception.UnknownPlatform: self.cmd_ctx.invoke( cmd_platform_install, platforms=[self.options['platform']]) - p = PlatformFactory.newPlatform(platform, version) + p = PlatformFactory.newPlatform(self.options['platform']) return p.run(build_vars, build_targets, self.verbose) diff --git a/platformio/commands/test.py b/platformio/commands/test.py index 55ea49df..31811afd 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -174,11 +174,7 @@ class TestProcessor(object): if self.options.get("upload_port", envdata.get("upload_port")): return self.options.get("upload_port", envdata.get("upload_port")) - platform = envdata['platform'] - version = None - if "@" in platform: - platform, version = platform.rsplit("@", 1) - p = PlatformFactory.newPlatform(platform, version) + p = PlatformFactory.newPlatform(envdata['platform']) bconfig = p.board_config(envdata['board']) port = None diff --git a/platformio/exception.py b/platformio/exception.py index 33a49e77..197ec0f9 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -72,24 +72,14 @@ class UnknownPackage(PlatformioException): class UndefinedPackageVersion(PlatformioException): - MESSAGE = "Can not find package '{0}' with version requirements '{1}'"\ - " for your system '{2}'" - - -class UndefinedPlatformVersion(PlatformioException): - - MESSAGE = "Can not find platform '{0}' with version requirements '{1}'" + MESSAGE = "Could not find a version that satisfies the requirement '{0}'"\ + " for your system '{1}'" class PackageInstallError(PlatformioException): - MESSAGE = "Can not install package '{0}' with version requirements '{1}' "\ - "for your system '{2}'" - - -class NonSystemPackage(PlatformioException): - - MESSAGE = "The package '{0}' is not available for your system '{1}'" + MESSAGE = "Can not install '{0}' with version requirements '{1}' "\ + "for your system '{2}'" class FDUnrecognizedStatusCode(PlatformioException): diff --git a/platformio/maintenance.py b/platformio/maintenance.py index 5bc31f2c..ccea3cd1 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -130,7 +130,7 @@ def after_upgrade(ctx): # patch development platforms pm = PlatformManager() for manifest in pm.get_installed(): - pm.update(manifest['name'], "~" + manifest['version']) + pm.update(manifest['name'], "^" + manifest['version']) click.secho("PlatformIO has been successfully upgraded to %s!\n" % __version__, fg="green") @@ -225,9 +225,9 @@ def check_internal_updates(ctx, what): if what == "platforms": pm = PlatformManager() for manifest in pm.get_installed(): - if pm.is_outdated(manifest['name'], manifest['version']): - outdated_items.append( - "%s@%s" % (manifest['name'], manifest['version'])) + if manifest['name'] not in outdated_items and \ + pm.is_outdated(manifest['name']): + outdated_items.append(manifest['name']) elif what == "libraries": lm = LibraryManager() outdated_items = lm.get_outdated() diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 352c0d00..45e3e174 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -14,7 +14,7 @@ import json import os -from os.path import dirname, isdir, isfile, islink, join +from os.path import basename, dirname, isdir, isfile, islink, join from shutil import copyfile, copytree, rmtree from tempfile import mkdtemp @@ -75,18 +75,21 @@ class PkgRepoMixin(object): def max_satisfying_repo_version(versions, requirements=None): item = None systype = util.get_systype() - if requirements is not None: - requirements = str(requirements) + reqspec = None + if requirements: + try: + reqspec = semantic_version.Spec(requirements) + except ValueError: + pass + for v in versions: - if isinstance(v['version'], int): + if ("system" in v and v['system'] not in ("all", "*") and + systype not in v['system']): continue - if v['system'] not in ("all", "*") and systype not in v['system']: + specver = semantic_version.Version(v['version']) + if reqspec and specver not in reqspec: continue - if requirements and not semantic_version.match( - requirements, v['version']): - continue - if item is None or semantic_version.compare( - v['version'], item['version']) == 1: + if not item or semantic_version.Version(item['version']) < specver: item = v return item @@ -96,8 +99,8 @@ class PkgRepoMixin(object): pkgdata = self.max_satisfying_repo_version(versions, requirements) if not pkgdata: continue - if (not version or semantic_version.compare( - pkgdata['version'], version) == 1): + if not version or semantic_version.compare(pkgdata['version'], + version) == 1: version = pkgdata['version'] return version @@ -126,77 +129,11 @@ class PkgInstallerMixin(object): manifest_path = self.get_manifest_path(pkg_dir) if manifest_path: manifest = util.load_json(manifest_path) - manifest['_manifest_path'] = manifest_path manifest['__pkg_dir'] = pkg_dir return manifest return None - def _install_from_piorepo(self, name, requirements): - pkg_dir = None - pkgdata = None - versions = None - for versions in PackageRepoIterator(name, self.repositories): - pkgdata = self.max_satisfying_repo_version(versions, requirements) - if not pkgdata: - continue - try: - pkg_dir = self._install_from_url( - name, pkgdata['url'], requirements, pkgdata.get("sha1")) - break - except Exception as e: # pylint: disable=broad-except - click.secho("Warning! Package Mirror: %s" % e, fg="yellow") - click.secho("Looking for another mirror...", fg="yellow") - - if versions is None: - raise exception.UnknownPackage(name) - elif not pkgdata: - if "platform" in self.manifest_name: - raise exception.UndefinedPlatformVersion( - name, requirements or "latest") - else: - raise exception.UndefinedPackageVersion( - name, requirements or "latest", util.get_systype()) - return pkg_dir - - def _install_from_url(self, name, url, requirements=None, sha1=None): - pkg_dir = None - tmp_dir = mkdtemp("-package", "installing-", self.package_dir) - - # Handle GitHub URL (https://github.com/user/repo.git) - if url.endswith(".git") and not url.startswith("git"): - url = "git+" + url - - try: - if url.startswith("file://"): - url = url[7:] - if isfile(url): - self.unpack(url, tmp_dir) - else: - rmtree(tmp_dir) - copytree(url, tmp_dir) - elif url.startswith(("http://", "https://", "ftp://")): - dlpath = self.download(url, tmp_dir, sha1) - assert isfile(dlpath) - self.unpack(dlpath, tmp_dir) - os.remove(dlpath) - else: - vcs = VCSClientFactory.newClient(tmp_dir, url) - assert vcs.export() - with open(join(vcs.storage_dir, - self.VCS_MANIFEST_NAME), "w") as fp: - json.dump({ - "name": name, - "version": "0.0.0+rev%s" % vcs.get_latest_revision(), - "url": url}, fp) - - self._check_pkg_structure(tmp_dir) - pkg_dir = self._install_from_tmp_dir(tmp_dir, requirements) - finally: - if isdir(tmp_dir): - rmtree(tmp_dir) - return pkg_dir - - def _check_pkg_structure(self, pkg_dir): + def check_pkg_structure(self, pkg_dir): if self.manifest_exists(pkg_dir): return True @@ -225,28 +162,98 @@ class PkgInstallerMixin(object): "Could not find '%s' manifest file in the package" % self.manifest_name) + def _install_from_piorepo(self, name, requirements): + pkg_dir = None + pkgdata = None + versions = None + for versions in PackageRepoIterator(name, self.repositories): + pkgdata = self.max_satisfying_repo_version(versions, requirements) + if not pkgdata: + continue + try: + pkg_dir = self._install_from_url( + name, pkgdata['url'], requirements, pkgdata.get("sha1")) + break + except Exception as e: # pylint: disable=broad-except + click.secho("Warning! Package Mirror: %s" % e, fg="yellow") + click.secho("Looking for the another mirror...", fg="yellow") + + if versions is None: + raise exception.UnknownPackage(name) + elif not pkgdata: + raise exception.UndefinedPackageVersion(requirements or "latest", + util.get_systype()) + return pkg_dir + + def _install_from_url(self, name, url, requirements=None, sha1=None): + pkg_dir = None + tmp_dir = mkdtemp("-package", "installing-", self.package_dir) + + try: + if url.startswith("file://"): + url = url[7:] + if isfile(url): + self.unpack(url, tmp_dir) + else: + rmtree(tmp_dir) + copytree(url, tmp_dir) + elif url.startswith(("http://", "https://")): + dlpath = self.download(url, tmp_dir, sha1) + assert isfile(dlpath) + self.unpack(dlpath, tmp_dir) + os.remove(dlpath) + else: + vcs = VCSClientFactory.newClient(tmp_dir, url) + assert vcs.export() + with open(join(vcs.storage_dir, self.VCS_MANIFEST_NAME), + "w") as fp: + json.dump({ + "name": name, + "version": vcs.get_current_revision(), + "url": url, + "requirements": requirements + }, fp) + + self.check_pkg_structure(tmp_dir) + pkg_dir = self._install_from_tmp_dir(tmp_dir, requirements) + finally: + if isdir(tmp_dir): + rmtree(tmp_dir) + return pkg_dir + def _install_from_tmp_dir(self, tmp_dir, requirements=None): tmpmanifest = self.load_manifest(tmp_dir) assert set(["name", "version"]) <= set(tmpmanifest.keys()) name = tmpmanifest['name'] pkg_dir = join(self.package_dir, name) + if "id" in tmpmanifest: + name += "_ID%d" % tmpmanifest['id'] + pkg_dir = join(self.package_dir, name) # package should satisfy requirements if requirements: - assert semantic_version.match( - requirements, tmpmanifest['version']) + mismatch_error = ( + "Package version %s doesn't satisfy requirements %s" % ( + tmpmanifest['version'], requirements)) + try: + reqspec = semantic_version.Spec(requirements) + tmpmanver = semantic_version.Version( + tmpmanifest['version'], partial=True) + assert tmpmanver in reqspec, mismatch_error - if self.manifest_exists(pkg_dir): - manifest = self.load_manifest(pkg_dir) - cmp_result = semantic_version.compare( - tmpmanifest['version'], manifest['version']) - if cmp_result == 1: - # if main package version < new package, backup it - os.rename(pkg_dir, join( - self.package_dir, "%s@%s" % (name, manifest['version']))) - elif cmp_result == -1: - pkg_dir = join( - self.package_dir, "%s@%s" % (name, tmpmanifest['version'])) + if self.manifest_exists(pkg_dir): + curmanifest = self.load_manifest(pkg_dir) + curmanver = semantic_version.Version( + curmanifest['version'], partial=True) + # if current package version < new package, backup it + if tmpmanver > curmanver: + os.rename(pkg_dir, join(self.package_dir, "%s@%s" % ( + name, curmanifest['version']))) + elif tmpmanver < curmanver: + pkg_dir = join(self.package_dir, "%s@%s" % + (name, tmpmanifest['version'])) + except ValueError: + assert tmpmanifest['version'] == requirements, mismatch_error # remove previous/not-satisfied package if isdir(pkg_dir): @@ -291,6 +298,50 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): def print_message(self, message, nl=True): click.echo("%s: %s" % (self.__class__.__name__, message), nl=nl) + @staticmethod + def parse_pkg_name( # pylint: disable=too-many-branches + text, requirements=None): + text = str(text) + if not requirements and "@" in text and not text.startswith("git@"): + text, requirements = text.rsplit("@", 1) + if text.isdigit(): + text = "id=" + text + + url_marker = "://" + name, url = (None, text) + if "=" in text and not text.startswith("id="): + name, url = text.split("=", 1) + + # Handle GitHub URL (https://github.com/user/package.git) + if url.startswith("https://github.com/") and \ + not url.endswith((".zip", ".tar.gz")): + url = "git+" + url + # Handle Developer Mbed URL + # (https://developer.mbed.org/users/user/code/package/) + if url.startswith("https://developer.mbed.org"): + url = "hg+" + url + + # git@github.com:user/package.git + if url.startswith("git@"): + url_marker = "git@" + + if any([s in url for s in ("\\", "/")]) and url_marker not in url: + if isfile(url) or isdir(url): + url = "file://" + url + elif url.count("/") == 1 and not url.startswith("git@"): + url = "git+https://github.com/" + url + if url_marker in url and not name: + _url = url.split("#", 1)[0] if "#" in url else url + if _url.endswith(("\\", "/")): + _url = _url[:-1] + name = basename(_url) + if "." in name and not name.startswith("."): + name = name.split(".", 1)[0] + + if url_marker not in url: + url = None + return (name or text, requirements, url) + def get_installed(self): if self.package_dir in BasePkgManager._INSTALLED_CACHE: return BasePkgManager._INSTALLED_CACHE[self.package_dir] @@ -304,26 +355,8 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): BasePkgManager._INSTALLED_CACHE[self.package_dir] = items return items - def is_installed(self, name, requirements=None): - installed = self.get_installed() - reqspec = None - if requirements: - try: - reqspec = semantic_version.Spec(requirements) - except ValueError: - pass - - if not reqspec: - return any([p['name'] == name for p in installed]) - - for p in installed: - if p['name'] != name: - continue - elif reqspec.match(semantic_version.Version(p['version'])): - return True - return None - - def max_installed_version(self, name, requirements=None): + def get_installed_dir(self, name, requirements=None, url=None): + pkg_id = int(name[3:]) if name.startswith("id=") else 0 best = None reqspec = None if requirements: @@ -333,123 +366,152 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): pass for manifest in self.get_installed(): - if manifest['name'] != name: + if pkg_id and manifest.get("id") != pkg_id: continue - elif reqspec and not reqspec.match( - semantic_version.Version(manifest['version'])): + elif not pkg_id and manifest['name'] != name: continue - elif (not best or semantic_version.compare( - manifest['version'], best['version']) == 1): - best = manifest - + elif not reqspec and requirements: + if requirements == manifest['version']: + best = manifest + break + continue + try: + if reqspec and not reqspec.match( + semantic_version.Version( + manifest['version'], partial=True)): + continue + elif not best or (semantic_version.Version( + manifest['version'], partial=True) > + semantic_version.Version( + best['version'], partial=True)): + best = manifest + except ValueError: + pass if best: + # check that URL is the same in installed package (VCS) + if url and best.get("url") != url: + return None return best.get("__pkg_dir") return None - def install(self, name, requirements, silent=False, trigger_event=True): - installed = self.is_installed(name, requirements) - if not installed or not silent: - self.print_message("Installing %s @ %s:" % ( - click.style(name, fg="cyan"), - requirements if requirements else "latest")) - if installed: - if not silent: - click.secho("Already installed", fg="yellow") - return self.max_installed_version( - name, requirements) + def install(self, name, requirements=None, quiet=False, + trigger_event=True): + name, requirements, url = self.parse_pkg_name(name, requirements) + installed_dir = self.get_installed_dir(name, requirements, url) - if (requirements and any([s in requirements for s in ("\\", "/")]) and - "://" not in requirements and ( - isfile(requirements) or isdir(requirements))): - requirements = "file://" + requirements + if not installed_dir or not quiet: + msg = "Installing " + click.style(name, fg="cyan") + if requirements: + msg += " @ " + requirements + self.print_message(msg) + if installed_dir: + if not quiet: + click.secho( + "{name} @ {version} is already installed".format( + **self.load_manifest(installed_dir)), + fg="yellow") + return installed_dir - if requirements and "://" in requirements: - pkg_dir = self._install_from_url(name, requirements) + if url: + pkg_dir = self._install_from_url(name, url, requirements) else: pkg_dir = self._install_from_piorepo(name, requirements) if not pkg_dir or not self.manifest_exists(pkg_dir): - raise exception.PackageInstallError( - name, requirements or "latest", util.get_systype()) + raise exception.PackageInstallError(name, requirements or "*", + util.get_systype()) self.reset_cache() + manifest = self.load_manifest(pkg_dir) + if trigger_event: telemetry.on_event( category=self.__class__.__name__, - action="Install", label=name) + action="Install", + label=manifest['name']) + + click.secho( + "{name} @ {version} has been successfully installed!".format( + **manifest), + fg="green") return pkg_dir def uninstall(self, name, requirements=None, trigger_event=True): - self.print_message("Uninstalling %s @ %s: \t" % ( - click.style(name, fg="cyan"), - requirements if requirements else "latest"), nl=False) - found = False - for manifest in self.get_installed(): - if manifest['name'] != name: - continue - if (requirements and not semantic_version.match( - requirements, manifest['version'])): - continue - found = True - if isdir(manifest['__pkg_dir']): - if islink(manifest['__pkg_dir']): - os.unlink(manifest['__pkg_dir']) - else: - rmtree(manifest['__pkg_dir']) + name, requirements, url = self.parse_pkg_name(name, requirements) + installed_dir = self.get_installed_dir(name, requirements, url) + if not installed_dir: + click.secho( + "%s @ %s is not installed" % (name, requirements or "*"), + fg="yellow") + return - if not found: - click.secho("Not installed", fg="yellow") - return False - else: - click.echo("[%s]" % click.style("OK", fg="green")) + manifest = self.load_manifest(installed_dir) + click.echo( + "Uninstalling %s @ %s: \t" % (click.style( + manifest['name'], fg="cyan"), manifest['version']), + nl=False) + + if isdir(installed_dir): + if islink(installed_dir): + os.unlink(installed_dir) + else: + rmtree(installed_dir) + + click.echo("[%s]" % click.style("OK", fg="green")) self.reset_cache() if trigger_event: telemetry.on_event( category=self.__class__.__name__, - action="Uninstall", label=name) + action="Uninstall", + label=manifest['name']) + return True - def update(self, name, requirements=None): - self.print_message("Updating %s @ %s:" % ( - click.style(name, fg="yellow"), - requirements if requirements else "latest")) - - latest_version = self.get_latest_repo_version(name, requirements) - if latest_version is None: + def update(self, name, requirements=None, only_check=False): + name, requirements, url = self.parse_pkg_name(name, requirements) + installed_dir = self.get_installed_dir(name, requirements, url) + if not installed_dir: click.secho( - "Ignored! '%s' is not listed in registry" % name, + "%s @ %s is not installed" % (name, requirements or "*"), fg="yellow") return - current = None - for manifest in self.get_installed(): - if manifest['name'] != name: - continue - if (requirements and not semantic_version.match( - requirements, manifest['version'])): - continue - if (not current or semantic_version.compare( - manifest['version'], current['version']) == 1): - current = manifest - - if current is None: - return - - current_version = current['version'] - click.echo("Versions: Current=%s, Latest=%s \t " % - (current_version, latest_version), nl=False) - - if current_version == latest_version: - click.echo("[%s]" % (click.style("Up-to-date", fg="green"))) - return True + manifest = self.load_manifest(installed_dir) + click.echo( + "Updating %s @ %s: \t" % (click.style( + manifest['name'], fg="cyan"), manifest['version']), + nl=False) + manifest_path = self.get_manifest_path(installed_dir) + if manifest_path.endswith(self.VCS_MANIFEST_NAME): + if only_check: + click.echo("[%s]" % (click.style("Skip", fg="yellow"))) + return + click.echo("[%s]" % (click.style("Checking", fg="yellow"))) + vcs = VCSClientFactory.newClient(installed_dir, manifest['url']) + if not vcs.can_be_updated: + click.secho( + "Skip update because repository is fixed " + "to %s revision" % manifest['version'], + fg="yellow") + return + assert vcs.update() + with open(manifest_path, "w") as fp: + manifest['version'] = vcs.get_current_revision() + json.dump(manifest, fp) else: + latest_version = self.get_latest_repo_version(name, requirements) + if manifest['version'] == latest_version: + click.echo("[%s]" % (click.style("Up-to-date", fg="green"))) + return click.echo("[%s]" % (click.style("Out-of-date", fg="red"))) - - self.install(name, latest_version, trigger_event=False) + if only_check: + return + self.install(name, latest_version, trigger_event=False) telemetry.on_event( category=self.__class__.__name__, - action="Update", label=name) + action="Update", + label=manifest['name']) return True diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index db7ea51a..2a485f07 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -26,17 +26,17 @@ import semantic_version from platformio import app, exception, util from platformio.managers.package import BasePkgManager, PackageManager -PLATFORMS_DIR = join(util.get_home_dir(), "platforms") -PACKAGES_DIR = join(util.get_home_dir(), "packages") - class PlatformManager(BasePkgManager): def __init__(self, package_dir=None, repositories=None): if not repositories: - repositories = ["http://dl.platformio.org/platforms/manifest.json"] - BasePkgManager.__init__( - self, package_dir or PLATFORMS_DIR, repositories) + repositories = [ + "https://dl.platformio.org/platforms/manifest.json" + ] + BasePkgManager.__init__(self, package_dir or + join(util.get_home_dir(), "platforms"), + repositories) @property def manifest_name(self): @@ -44,27 +44,29 @@ class PlatformManager(BasePkgManager): def install(self, # pylint: disable=too-many-arguments,arguments-differ name, requirements=None, with_packages=None, - without_packages=None, skip_default_packages=False): + without_packages=None, skip_default_package=False): platform_dir = BasePkgManager.install(self, name, requirements) p = PlatformFactory.newPlatform(self.get_manifest_path(platform_dir)) - p.install_packages( - with_packages, without_packages, skip_default_packages) + p.install_packages(with_packages, without_packages, + skip_default_package) self.cleanup_packages(p.packages.keys()) return True - def uninstall(self, # pylint: disable=arguments-differ - name, requirements=None): + def uninstall( # pylint: disable=arguments-differ + self, name, requirements=None): + name, requirements, _ = self.parse_pkg_name(name, requirements) p = PlatformFactory.newPlatform(name, requirements) BasePkgManager.uninstall(self, name, requirements) self.cleanup_packages(p.packages.keys()) return True def update(self, # pylint: disable=arguments-differ - name, requirements=None, only_packages=False): + name, requirements=None, only_packages=False, only_check=False): + name, requirements, _ = self.parse_pkg_name(name, requirements) if not only_packages: - BasePkgManager.update(self, name, requirements) + BasePkgManager.update(self, name, requirements, only_check) p = PlatformFactory.newPlatform(name, requirements) - p.update_packages() + p.update_packages(only_check) self.cleanup_packages(p.packages.keys()) return True @@ -77,14 +79,14 @@ class PlatformManager(BasePkgManager): self.reset_cache() deppkgs = {} for manifest in PlatformManager().get_installed(): - p = PlatformFactory.newPlatform( - manifest['name'], manifest['version']) + p = PlatformFactory.newPlatform(manifest['name'], + manifest['version']) for pkgname, pkgmanifest in p.get_installed_packages().items(): if pkgname not in deppkgs: deppkgs[pkgname] = set() deppkgs[pkgname].add(pkgmanifest['version']) - pm = PackageManager(PACKAGES_DIR) + pm = PackageManager(join(util.get_home_dir(), "packages")) for manifest in pm.get_installed(): if manifest['name'] not in names: continue @@ -126,35 +128,36 @@ class PlatformFactory(object): def load_module(name, path): module = None try: - module = load_source( - "platformio.managers.platform.%s" % name, path) + module = load_source("platformio.managers.platform.%s" % name, + path) except ImportError: raise exception.UnknownPlatform(name) return module @classmethod def newPlatform(cls, name, requirements=None): + if not requirements and "@" in name: + name, requirements = name.rsplit("@", 1) platform_dir = None if name.endswith("platform.json") and isfile(name): platform_dir = dirname(name) name = util.load_json(name)['name'] else: - platform_dir = PlatformManager().max_installed_version( - name, requirements) + platform_dir = PlatformManager().get_installed_dir(name, + requirements) if not platform_dir: - raise exception.UnknownPlatform( - name if not requirements else "%s@%s" % (name, requirements)) + raise exception.UnknownPlatform(name if not requirements else + "%s@%s" % (name, requirements)) platform_cls = None if isfile(join(platform_dir, "platform.py")): platform_cls = getattr( cls.load_module(name, join(platform_dir, "platform.py")), - cls.get_clsname(name) - ) + cls.get_clsname(name)) else: platform_cls = type( - str(cls.get_clsname(name)), (PlatformBase,), {}) + str(cls.get_clsname(name)), (PlatformBase, ), {}) _instance = platform_cls(join(platform_dir, "platform.json")) assert isinstance(_instance, PlatformBase) @@ -187,12 +190,13 @@ class PlatformPackagesMixin(object): items[name] = manifest return items - def install_packages(self, with_packages=None, without_packages=None, - skip_default_packages=False, silent=False): - with_packages = set( - self.pkg_types_to_names(with_packages or [])) - without_packages = set( - self.pkg_types_to_names(without_packages or [])) + def install_packages(self, + with_packages=None, + without_packages=None, + skip_default_package=False, + quiet=False): + with_packages = set(self.pkg_types_to_names(with_packages or [])) + without_packages = set(self.pkg_types_to_names(without_packages or [])) upkgs = with_packages | without_packages ppkgs = set(self.packages.keys()) @@ -203,14 +207,18 @@ class PlatformPackagesMixin(object): if name in without_packages: continue elif (name in with_packages or - not (skip_default_packages or opts.get("optional", False))): - self.pm.install(name, opts.get("version"), silent=silent) + not (skip_default_package or opts.get("optional", False))): + if any([s in opts.get("version", "") for s in ("\\", "/")]): + self.pm.install( + "%s=%s" % (name, opts['version']), quiet=quiet) + else: + self.pm.install(name, opts.get("version"), quiet=quiet) return True - def update_packages(self): + def update_packages(self, only_check=False): for name in self.get_installed_packages(): - self.pm.update(name, self.packages[name]['version']) + self.pm.update(name, self.packages[name]['version'], only_check) def are_outdated_packages(self): for name, opts in self.get_installed_packages().items(): @@ -229,7 +237,7 @@ class PlatformRunMixin(object): assert isinstance(targets, list) self.configure_default_packages(variables, targets) - self.install_packages(silent=True) + self.install_packages(quiet=True) self._verbose = verbose or app.get_setting("force_verbose") @@ -261,10 +269,8 @@ class PlatformRunMixin(object): cmd = [ os.path.normpath(sys.executable), - join(self.get_package_dir("tool-scons"), "script", "scons"), - "-Q", - "-j %d" % self.get_job_nums(), - "--warn=no-no-parallel-support", + join(self.get_package_dir("tool-scons"), "script", "scons"), "-Q", + "-j %d" % self.get_job_nums(), "--warn=no-no-parallel-support", "-f", join(util.get_source_dir(), "builder", "main.py") ] if not self._verbose and "-c" not in targets: @@ -278,8 +284,7 @@ class PlatformRunMixin(object): result = util.exec_command( cmd, stdout=util.AsyncPipe(self.on_run_out), - stderr=util.AsyncPipe(self.on_run_err) - ) + stderr=util.AsyncPipe(self.on_run_err)) return result def on_run_out(self, line): @@ -315,7 +320,8 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): self._manifest = util.load_json(manifest_path) self.pm = PackageManager( - PACKAGES_DIR, self._manifest.get("packageRepositories")) + join(util.get_home_dir(), "packages"), + self._manifest.get("packageRepositories")) self._verbose = False diff --git a/platformio/vcsclient.py b/platformio/vcsclient.py index f915e0e3..fffd6792 100644 --- a/platformio/vcsclient.py +++ b/platformio/vcsclient.py @@ -12,12 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from os import listdir -from os.path import isdir, join -from platform import system +import re +from os.path import join from subprocess import check_call from sys import modules -from urlparse import urlsplit, urlunsplit +from urlparse import urlparse from platformio import util from platformio.exception import PlatformioException @@ -26,28 +25,16 @@ from platformio.exception import PlatformioException class VCSClientFactory(object): @staticmethod - def newClient(src_dir, remote_url=None, branch=None): - clsnametpl = "%sClient" - vcscls = None - type_ = None - if remote_url: - scheme, netloc, path, query, branch = urlsplit(remote_url) - type_ = scheme - if "+" in type_: - type_, scheme = type_.split("+", 1) - remote_url = urlunsplit((scheme, netloc, path, query, None)) - vcscls = getattr(modules[__name__], clsnametpl % type_.title()) - elif isdir(src_dir): - for item in listdir(src_dir): - if not isdir(join(src_dir, item)) or not item.startswith("."): - continue - try: - vcscls = getattr( - modules[__name__], clsnametpl % item[1:].title()) - except AttributeError: - pass - assert vcscls - obj = vcscls(src_dir, remote_url, branch) + def newClient(src_dir, remote_url): + result = urlparse(remote_url) + type_ = result.scheme + if "+" in result.scheme: + type_, _ = result.scheme.split("+", 1) + remote_url = remote_url[len(type_) + 1:] + if result.fragment: + remote_url = remote_url.rsplit("#", 1)[0] + obj = getattr(modules[__name__], "%sClient" % type_.title())( + src_dir, remote_url, result.fragment) assert isinstance(obj, VCSClientBase) return obj @@ -79,19 +66,29 @@ class VCSClientBase(object): def export(self): raise NotImplementedError - def get_latest_revision(self): + def update(self): + raise NotImplementedError + + @property + def can_be_updated(self): + return not self.branch + + def get_current_revision(self): raise NotImplementedError def run_cmd(self, args, **kwargs): args = [self.command] + args - kwargs['shell'] = system() == "Windows" + if "cwd" not in kwargs: + kwargs['cwd'] = self.src_dir return check_call(args, **kwargs) == 0 def get_cmd_output(self, args, **kwargs): args = [self.command] + args + if "cwd" not in kwargs: + kwargs['cwd'] = self.src_dir result = util.exec_command(args, **kwargs) if result['returncode'] == 0: - return result['out'] + return result['out'].strip() raise PlatformioException( "VCS: Could not receive an output from `%s` command (%s)" % ( args, result)) @@ -101,16 +98,42 @@ class GitClient(VCSClientBase): command = "git" + def get_branches(self): + output = self.get_cmd_output(["branch"]) + output = output.replace("*", "") # fix active branch + return [b.strip() for b in output.split("\n")] + + def get_tags(self): + output = self.get_cmd_output(["tag", "-l"]) + return [t.strip() for t in output.split("\n")] + + @staticmethod + def is_commit_id(text): + return text and re.match(r"[0-9a-f]{7,}$", text) is not None + + @property + def can_be_updated(self): + return not self.branch or not self.is_commit_id(self.branch) + def export(self): - args = ["clone", "--recursive", "--depth", "1"] - if self.branch: - args.extend(["--branch", self.branch]) - args.extend([self.remote_url, self.src_dir]) + is_commit = self.is_commit_id(self.branch) + args = ["clone", "--recursive"] + if not self.branch or not is_commit: + args += ["--depth", "1"] + if self.branch: + args += ["--branch", self.branch] + args += [self.remote_url, self.src_dir] + assert self.run_cmd(args) + if is_commit: + return self.run_cmd(["reset", "--hard", self.branch]) + return True + + def update(self): + args = ["pull"] return self.run_cmd(args) - def get_latest_revision(self): - return self.get_cmd_output(["rev-parse", "--short", "HEAD"], - cwd=self.src_dir).strip() + def get_current_revision(self): + return self.get_cmd_output(["rev-parse", "--short", "HEAD"]) class HgClient(VCSClientBase): @@ -124,9 +147,12 @@ class HgClient(VCSClientBase): args.extend([self.remote_url, self.src_dir]) return self.run_cmd(args) - def get_latest_revision(self): - return self.get_cmd_output(["identify", "--id"], - cwd=self.src_dir).strip() + def update(self): + args = ["pull", "--update"] + return self.run_cmd(args) + + def get_current_revision(self): + return self.get_cmd_output(["identify", "--id"]) class SvnClient(VCSClientBase): @@ -134,12 +160,22 @@ class SvnClient(VCSClientBase): command = "svn" def export(self): - args = ["export", "--force"] + args = ["checkout"] if self.branch: args.extend(["--revision", self.branch]) args.extend([self.remote_url, self.src_dir]) return self.run_cmd(args) - def get_latest_revision(self): - return self.get_cmd_output(["info", "-r", "HEAD"], - cwd=self.src_dir).strip() + def update(self): + + args = ["update"] + return self.run_cmd(args) + + def get_current_revision(self): + output = self.get_cmd_output(["info", "--non-interactive", + "--trust-server-cert", "-r", "HEAD"]) + for line in output.split("\n"): + line = line.strip() + if line.startswith("Revision:"): + return line.split(":", 1)[1].strip() + raise PlatformioException("Could not detect current SVN revision") diff --git a/tests/commands/test_platform.py b/tests/commands/test_platform.py index db4d735e..bd96230e 100644 --- a/tests/commands/test_platform.py +++ b/tests/commands/test_platform.py @@ -13,15 +13,15 @@ # limitations under the License. import json +import os +from os.path import join -from platformio.commands.platform import \ - platform_list as cmd_platform_list -from platformio.commands.platform import \ - platform_search as cmd_platform_search +from platformio.commands import platform as cli_platform +from platformio import exception, util def test_list_json_output(clirunner, validate_cliresult): - result = clirunner.invoke(cmd_platform_list, ["--json-output"]) + result = clirunner.invoke(cli_platform.platform_list, ["--json-output"]) validate_cliresult(result) list_result = json.loads(result.output) assert isinstance(list_result, list) @@ -31,13 +31,13 @@ def test_list_json_output(clirunner, validate_cliresult): def test_list_raw_output(clirunner, validate_cliresult): - result = clirunner.invoke(cmd_platform_list) + result = clirunner.invoke(cli_platform.platform_list) validate_cliresult(result) assert "teensy" in result.output def test_search_json_output(clirunner, validate_cliresult): - result = clirunner.invoke(cmd_platform_search, + result = clirunner.invoke(cli_platform.platform_search, ["arduino", "--json-output"]) validate_cliresult(result) search_result = json.loads(result.output) @@ -48,6 +48,79 @@ def test_search_json_output(clirunner, validate_cliresult): def test_search_raw_output(clirunner, validate_cliresult): - result = clirunner.invoke(cmd_platform_search, ["arduino"]) + result = clirunner.invoke(cli_platform.platform_search, ["arduino"]) validate_cliresult(result) assert "teensy" in result.output + + +def test_install_uknown_from_registry(clirunner, validate_cliresult): + result = clirunner.invoke(cli_platform.platform_install, + ["uknown-platform"]) + assert result.exit_code == -1 + assert isinstance(result.exception, exception.UnknownPackage) + + +def test_install_uknown_version(clirunner, validate_cliresult): + result = clirunner.invoke(cli_platform.platform_install, + ["atmelavr@99.99.99"]) + assert result.exit_code == -1 + assert isinstance(result.exception, exception.UndefinedPackageVersion) + + +def test_complex(clirunner, validate_cliresult): + items = [ + "teensy", + "https://github.com/platformio/platform-teensy/archive/develop.zip", + "https://github.com/platformio/platform-teensy.git", + "platformio/platform-teensy", + ] + for item in items: + with clirunner.isolated_filesystem(): + os.environ["PLATFORMIO_HOME_DIR"] = os.getcwd() + try: + result = clirunner.invoke(cli_platform.platform_install, + [item]) + validate_cliresult(result) + assert all([ + s in result.output + for s in ("teensy", "Downloading", "Unpacking", + "tool-scons") + ]) + + # show platform information + result = clirunner.invoke(cli_platform.platform_show, + ["teensy"]) + validate_cliresult(result) + assert "teensy" in result.output + + # list platforms + result = clirunner.invoke(cli_platform.platform_list, + ["--json-output"]) + validate_cliresult(result) + list_result = json.loads(result.output) + assert isinstance(list_result, list) + assert len(list_result) == 1 + assert list_result[0]["name"] == "teensy" + assert list_result[0]["packages"] == ["tool-scons"] + + # try to install again + result = clirunner.invoke(cli_platform.platform_install, + ["teensy"]) + validate_cliresult(result) + assert "is already installed" in result.output + + # try to update + result = clirunner.invoke(cli_platform.platform_update) + validate_cliresult(result) + assert "teensy" in result.output + assert "Up-to-date" in result.output + + # try to uninstall + result = clirunner.invoke(cli_platform.platform_uninstall, + ["teensy"]) + validate_cliresult(result) + for folder in ("platforms", "packages"): + assert len(os.listdir(join(util.get_home_dir(), + folder))) == 0 + finally: + del os.environ["PLATFORMIO_HOME_DIR"] diff --git a/tests/test_managers.py b/tests/test_managers.py new file mode 100644 index 00000000..abed10a1 --- /dev/null +++ b/tests/test_managers.py @@ -0,0 +1,66 @@ +# Copyright 2014-present Ivan Kravets +# +# 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 util +from platformio.managers.package import BasePkgManager + + +def test_pkg_name_parser(): + items = [ + ["PkgName", ("PkgName", None, None)], + [("PkgName", "!=1.2.3,<2.0"), ("PkgName", "!=1.2.3,<2.0", None)], + ["PkgName@1.2.3", ("PkgName", "1.2.3", None)], + [("PkgName@1.2.3", "1.2.5"), ("PkgName@1.2.3", "1.2.5", None)], + ["id:13", ("id:13", None, None)], + ["id:13@~1.2.3", ("id:13", "~1.2.3", None)], + [util.get_home_dir(), + (".platformio", None, "file://" + util.get_home_dir())], + ["LocalName=" + util.get_home_dir(), + ("LocalName", None, "file://" + util.get_home_dir())], + ["https://github.com/user/package.git", + ("package", None, "git+https://github.com/user/package.git")], + ["https://github.com/user/package/archive/branch.zip", + ("branch", None, + "https://github.com/user/package/archive/branch.zip")], + ["https://github.com/user/package/archive/branch.tar.gz", + ("branch", None, + "https://github.com/user/package/archive/branch.tar.gz")], + ["https://developer.mbed.org/users/user/code/package/", + ("package", None, + "hg+https://developer.mbed.org/users/user/code/package/")], + ["https://github.com/user/package#v1.2.3", + ("package", None, "git+https://github.com/user/package#v1.2.3")], + ["https://github.com/user/package.git#branch", + ("package", None, "git+https://github.com/user/package.git#branch")], + ["PkgName=https://github.com/user/package.git#a13d344fg56", + ("PkgName", None, + "git+https://github.com/user/package.git#a13d344fg56")], + ["PkgName=user/package", + ("PkgName", None, "git+https://github.com/user/package")], + ["PkgName=user/package#master", + ("PkgName", None, "git+https://github.com/user/package#master")], + ["git+https://github.com/user/package", + ("package", None, "git+https://github.com/user/package")], + ["hg+https://example.com/user/package", + ("package", None, "hg+https://example.com/user/package")], + ["git@github.com:user/package.git", + ("package", None, "git@github.com:user/package.git")], + ["git@github.com:user/package.git#v1.2.0", + ("package", None, "git@github.com:user/package.git#v1.2.0")] + ] + for params, result in items: + if isinstance(params, tuple): + assert BasePkgManager.parse_pkg_name(*params) == result + else: + assert BasePkgManager.parse_pkg_name(params) == result From bfab3dac813aab5ca963a084e00cb0bb1e0d68a2 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 2 Aug 2016 14:04:32 +0300 Subject: [PATCH 089/284] Measure code coverage by tests // Resolve #101 --- .coveragerc | 26 ++++++++++++++++++++++++++ .gitignore | 2 ++ .travis.yml | 3 +++ README.rst | 2 ++ tox.ini | 14 +++++++++++--- 5 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..cfb6fb9d --- /dev/null +++ b/.coveragerc @@ -0,0 +1,26 @@ +# Copyright 2014-present Ivan Kravets +# +# 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. + +[run] +omit = + platformio/builder/* +source = platformio + +[report] +# Regexes for lines to exclude from consideration +exclude_lines = + pragma: no cover + def __repr__ + raise AssertionError + raise NotImplementedError diff --git a/.gitignore b/.gitignore index 89257136..549cf8bb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ docs/_build dist build .cache +coverage.xml +.coverage diff --git a/.travis.yml b/.travis.yml index 0a418de9..8c34f8da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,9 @@ install: script: - tox -e $TOX_ENV +after_success: + - tox -e coverage + notifications: slack: secure: ksQmXOP5NVsf8IgoDuxD68Q/YNwDpZuwq0V29h2dxYCr38oYdAkq/Os4LSCs0X6P0cQFf6nC1hM/d+cAvU+SmzcHGxEceHNEGCg3/TAj+68KIwooPU93Lfq1zwdfteZWxANjKlCQy4+wZliHLhL8fvCYgfJww/6qKmqSYleBNM= diff --git a/README.rst b/README.rst index a3854318..3f51c344 100644 --- a/README.rst +++ b/README.rst @@ -7,6 +7,8 @@ PlatformIO .. image:: https://ci.appveyor.com/api/projects/status/dku0h2rutfj0ctls/branch/develop?svg=true :target: https://ci.appveyor.com/project/ivankravets/platformio :alt: AppVeyor.CI Build Status +.. image:: https://codecov.io/gh/platformio/platformio/branch/develop/graph/badge.svg + :target: https://codecov.io/gh/platformio/platformio .. image:: https://requires.io/github/platformio/platformio/requirements.svg?branch=develop :target: https://requires.io/github/platformio/platformio/requirements/?branch=develop :alt: Requirements Status diff --git a/tox.ini b/tox.ini index 7b32c481..39e23c8d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -55,7 +55,15 @@ basepython = py27: python2.7 usedevelop = True passenv = * -deps = pytest +deps = + pytest + pytest-cov commands = {envpython} --version - py.test -v --basetemp="{envtmpdir}" tests + py.test --cov=platformio -v --basetemp="{envtmpdir}" tests + +[testenv:coverage] +passenv = * +basepython = python2.7 +deps = codecov +commands = codecov From 26dae8ee94c9ccee48527eb280f575e18bcba28e Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 2 Aug 2016 15:45:05 +0300 Subject: [PATCH 090/284] Skip some tests from coverage --- tox.ini | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 39e23c8d..efc4138c 100644 --- a/tox.ini +++ b/tox.ini @@ -60,10 +60,12 @@ deps = pytest-cov commands = {envpython} --version - py.test --cov=platformio -v --basetemp="{envtmpdir}" tests + py.test -v --basetemp="{envtmpdir}" tests [testenv:coverage] passenv = * basepython = python2.7 deps = codecov -commands = codecov +commands = + py.test --cov=platformio -v tests --ignore=tests/test_examples.py --ignore=tests/test_pkgmanifest.py + codecov From 5b5a63cb5f4d58b7314ffe75a2bc91486775d962 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 2 Aug 2016 15:50:04 +0300 Subject: [PATCH 091/284] Use codecov after success script --- .gitignore | 1 + .travis.yml | 3 ++- tox.ini | 2 -- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 549cf8bb..0a54e681 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ build .cache coverage.xml .coverage +htmlcov diff --git a/.travis.yml b/.travis.yml index 8c34f8da..5b210f4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ env: install: - git submodule update --init --recursive - - pip install -U pip setuptools tox + - pip install -U pip setuptools tox codecov - sudo apt-get install -qq lib32z1 lib32ncurses5 lib32bz2-1.0 # temporarily script: @@ -18,6 +18,7 @@ script: after_success: - tox -e coverage + - bash <(curl -s https://codecov.io/bash) notifications: slack: diff --git a/tox.ini b/tox.ini index efc4138c..71717e00 100644 --- a/tox.ini +++ b/tox.ini @@ -65,7 +65,5 @@ commands = [testenv:coverage] passenv = * basepython = python2.7 -deps = codecov commands = py.test --cov=platformio -v tests --ignore=tests/test_examples.py --ignore=tests/test_pkgmanifest.py - codecov From 758396c9ead77cd8050754b50ba202ee44570cff Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 2 Aug 2016 19:10:29 +0300 Subject: [PATCH 092/284] PlatformIO Library Manager 3.0 // Resolve #588 , Resolve #414, Resolve #498, Resolve #475, Resolve #410, Resolve #461, Resolve #361, Resolve #507, Resolve #554 --- HISTORY.rst | 76 +++-- docs/librarymanager/ldf.rst | 2 +- docs/projectconf.rst | 2 +- docs/userguide/lib/cmd_install.rst | 228 +++++++++++--- docs/userguide/lib/cmd_list.rst | 42 ++- docs/userguide/lib/cmd_register.rst | 6 +- docs/userguide/lib/cmd_search.rst | 195 ++++++------ docs/userguide/lib/cmd_show.rst | 67 ++++- docs/userguide/lib/cmd_uninstall.rst | 48 ++- docs/userguide/lib/cmd_update.rst | 119 +++++--- docs/userguide/lib/index.rst | 39 ++- docs/userguide/platforms/cmd_install.rst | 104 ++++--- docs/userguide/platforms/cmd_list.rst | 5 +- docs/userguide/platforms/cmd_search.rst | 15 +- docs/userguide/platforms/cmd_show.rst | 5 +- docs/userguide/platforms/cmd_uninstall.rst | 4 +- docs/userguide/platforms/cmd_update.rst | 5 +- docs/userguide/platforms/index.rst | 4 +- platformio/__init__.py | 2 +- platformio/commands/lib.py | 333 ++++++++++----------- platformio/commands/run.py | 33 +- platformio/exception.py | 13 +- platformio/libmanager.py | 121 -------- platformio/maintenance.py | 35 ++- platformio/managers/lib.py | 209 +++++++++++++ platformio/managers/package.py | 16 +- platformio/managers/platform.py | 5 +- platformio/vcsclient.py | 26 +- tests/commands/test_boards.py | 4 +- tests/commands/test_init.py | 6 +- tests/commands/test_lib.py | 85 ++++-- tests/commands/test_platform.py | 2 +- tests/commands/test_settings.py | 2 +- tests/conftest.py | 27 +- 34 files changed, 1185 insertions(+), 700 deletions(-) delete mode 100644 platformio/libmanager.py create mode 100644 platformio/managers/lib.py diff --git a/HISTORY.rst b/HISTORY.rst index 763eb9d3..a85dcbac 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -7,41 +7,65 @@ PlatformIO 3.0 3.0.0 (2016-??-??) ~~~~~~~~~~~~~~~~~~ -* Decentralized architecture for development platforms: "platform.json", - semantic versioning, package dependencies, embedded board configs, isolated - build scripts - (`issue #479 `_) -* Unit Testing for Embedded (`docs `__) +* Decentralized Development Platforms + + + Development platform manifest "platform.json" and + `open source development platforms `__ + + `Semantic Versioning `__ for platform commands, + development platforms and dependent packages + + Custom package repositories + + External embedded board configuration files, isolated build scripts + (`issue #479 `_) + + Embedded Board compatibility with more than one development platform + (`issue #456 `_) + +* `Unit Testing `__ for Embedded (`issue #408 `_) + +* Library Manager 3.0 + + + `Semantic Versioning `__ for library commands and + dependencies + (`issue #410 `_) + + Multiple library storages: project's local, PlatformIO global or custom + (`issue #475 `_) + + Install library by name + (`issue #414 `_) + + Depend on a library using VCS URL (GitHub, Git, ARM mbed code registry, Hg, SVN) + (`issue #498 `_) + + Strict search for library dependencies + (`issue #588 `_) + + Allowed ``library.json`` to specify sources other than PlatformIO's Repository + (`issue #461 `_) + * New Intelligent Library Build System - + `Library Dependency Finder `__ - that interprets C Preprocessor conditional macros with deep search behavior - + Check library compatibility with project environment before building - (`issue #415 `_) - + Control Library Dependency Finder for compatibility using - `lib_compat_mode `__ - option - + Custom library storages/directories with - `lib_extra_dirs `__ option - (`issue #537 `_) - + Handle extra build flags, source filters and build script from - `library.json `__ - (`issue #289 `_) - + Allowed to disable library archiving (``*.ar``) - (`issue #719 `_) - + Show detailed build information about dependent libraries - (`issue #617 `_) - + Support for the 3rd party manifests (Arduino IDE "library.properties" - and ARM mbed "module.json") + + `Library Dependency Finder `__ + that interprets C Preprocessor conditional macros with deep search behavior + + Check library compatibility with project environment before building + (`issue #415 `_) + + Control Library Dependency Finder for compatibility using + `lib_compat_mode `__ + option + + Custom library storages/directories with + `lib_extra_dirs `__ option + (`issue #537 `_) + + Handle extra build flags, source filters and build script from + `library.json `__ + (`issue #289 `_) + + Allowed to disable library archiving (``*.ar``) + (`issue #719 `_) + + Show detailed build information about dependent libraries + (`issue #617 `_) + + Support for the 3rd party manifests (Arduino IDE "library.properties" + and ARM mbed "module.json") * Print human-readable information when processing environments without ``-v, --verbose`` option (`issue #721 `_) * Added ``license`` field to `library.json `__ (`issue #522 `_) -* Embedded Board compatibility with more than one development platform - (`issue #456 `_) + PlatformIO 2.0 -------------- diff --git a/docs/librarymanager/ldf.rst b/docs/librarymanager/ldf.rst index c1a8d79b..e833687b 100644 --- a/docs/librarymanager/ldf.rst +++ b/docs/librarymanager/ldf.rst @@ -50,7 +50,7 @@ libraries. These folders/path have priority and LDF operates in the next order: 2. :ref:`projectconf_pio_lib_dir` - own/private library storage per project 3. :ref:`projectconf_pio_piolibdeps_dir` - project dependencies storage used by :ref:`librarymanager` -4. :ref:`projectconf_pio_home_dir`/lib - global storage per all projects. +4. ":ref:`projectconf_pio_home_dir`/lib" - global storage per all projects. .. _ldf_mode: diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 748d0478..d4866ec3 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -253,7 +253,7 @@ General options :ref:`platforms` name. -PlatformIO allows to use specific platform versions using +PlatformIO allows to use specific version of platform using `Semantic Versioning `_ (X.Y.Z=MAJOR.MINOR.PATCH). Version specifications can take any of the following forms: diff --git a/docs/userguide/lib/cmd_install.rst b/docs/userguide/lib/cmd_install.rst index 7b6e2986..ddfef32b 100644 --- a/docs/userguide/lib/cmd_install.rst +++ b/docs/userguide/lib/cmd_install.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -21,22 +21,67 @@ Usage .. code-block:: bash - platformio lib install [OPTIONS] [LIBRARY_ID] + platformio lib [STORAGE_OPTIONS] install [OPTIONS] [LIBRARY...] + # install project dependent library + # (run it from a project root where is located "platformio.ini") + platformio lib install [OPTIONS] [LIBRARY...] + + # install to global storage + platformio lib --global install [OPTIONS] [LIBRARY...] + platformio lib -g install [OPTIONS] [LIBRARY...] + + # install to custom storage + platformio lib --storage-dir /path/to/dir install [OPTIONS] [LIBRARY...] + platformio lib -d /path/to/dir install [OPTIONS] [LIBRARY...] + + # [LIBRARY...] forms + platformio lib [STORAGE_OPTIONS] install (with no args, project dependencies) + platformio lib [STORAGE_OPTIONS] install + platformio lib [STORAGE_OPTIONS] install @ + platformio lib [STORAGE_OPTIONS] install @ + platformio lib [STORAGE_OPTIONS] install + platformio lib [STORAGE_OPTIONS] install @ + platformio lib [STORAGE_OPTIONS] install @ + platformio lib [STORAGE_OPTIONS] install + platformio lib [STORAGE_OPTIONS] install file:// + platformio lib [STORAGE_OPTIONS] install file:// + platformio lib [STORAGE_OPTIONS] install + platformio lib [STORAGE_OPTIONS] install (name it should have locally) + platformio lib [STORAGE_OPTIONS] install ("tag" can be commit, branch or tag) Description ----------- -Install new library by specified -`PlatformIO Library Registry ID `_. +Install a library, and any libraries that it depends on using: -Installs the project library dependencies or a specific set of libraries. -[LIBRARY] can have multiple forms: , @, - or =@ +1. Library ``id`` or ``name`` from `PlatformIO Library Registry `_ +2. Custom folder, repository or archive. -Where, is a registry ID, registry name, repository URL, physical -location, is a valid semantic version/range, commit, branch, etc., and - is the name it should have locally. +The ``version`` supports `Semantic Versioning `_ ( +``..``) and can take any of the following forms: + +* ``0.1.2`` - an exact version number. Use only this exact version +* ``^0.1.2`` - any compatible version (exact version for ``0.x.x`` versions +* ``~0.1.2`` - any version with the same major and minor versions, and an + equal or greater patch version +* ``>0.1.2`` - any version greater than ``0.1.2``. ``>=``, ``<``, and ``<=`` + are also possible +* ``>0.1.0,!=0.2.0,<0.3.0`` - any version greater than ``0.1.0``, not equal to + ``0.2.0`` and less than ``0.3.0`` + +Also, PlatformIO supports installing from local directory or archive. Need +to use ``file://`` prefix before local path. Also, directory or +archive should contain ``.library.json`` manifest (see :ref:`library_config`). + +* ``file:///local/path/to/the/platform/dir`` +* ``file:///local/path/to/the/platform.zip`` +* ``file:///local/path/to/the/platform.tar.gz`` + +Storage Options +--------------- + +See base options for :ref:`userguide_lib`. Options ------- @@ -44,50 +89,151 @@ Options .. program:: platformio lib install .. option:: - -v, --version + -q, --quiet -Install specified version of library +Suppress progress reporting + +Version control +--------------- + +PlatformIO supports installing from Git, Mercurial and Subversion, and detects +the type of VCS using url prefixes: "git+", "hg+", or "svn+". + +.. note:: + PlatformIO requires a working VCS command on your path: ``git``, ``hg`` + or ``svn``. + +Git +^^^ + +The supported schemes are: ``git``, ``git+https`` and ``git+ssh``. Here are +the supported forms: + +* user/library (short version for GitHub repository) +* https://github.com/user/library.git +* git+git://git.server.org/my-library +* git+https://git.server.org/my-library +* git+ssh://git.server.org/my-library + +Passing branch names, a commit hash or a tag name is possible like so: + +* https://github.com/user/library.git#master +* git+git://git.server.org/my-library#master +* git+https://git.server.org/my-library#v1.0 +* git+ssh://git.server.org/my-library#7846d8ad52f983f2f2887bdc0f073fe9755a806d + +Mercurial +^^^^^^^^^ + +The supported schemes are: ``hg+http``, ``hg+https`` and ``hg+ssh``. Here are +the supported forms: + +* https://developer.mbed.org/users/user/code/library/ (install ARM mbed library) +* hg+hg://hg.server.org/my-library +* hg+https://hg.server.org/my-library +* hg+ssh://hg.server.org/my-library + +Passing branch names, a commit hash or a tag name is possible like so: + +* hg+hg://hg.server.org/my-library#master +* hg+https://hg.server.org/my-library#v1.0 +* hg+ssh://hg.server.org/my-library#4cfe2fa00668 + +Subversion +^^^^^^^^^^ + +The supported schemes are: ``svn``, ``svn+svn``, ``svn+http``, ``svn+https`` +and ``svn+ssh``. Here are the supported forms: + +* svn+svn://svn.server.org/my-library +* svn+https://svn.server.org/my-library +* svn+ssh://svn.server.org/my-library + +You can also give specific revisions to an SVN URL, like so: + +* svn+svn://svn.server.org/my-library#13 Examples -------- -1. Install the latest version of library +1. Install the latest version of library to a global storage using ID or NAME -.. code-block:: bash +.. code:: - # IRremote: http://platformio.org/lib/show/4/IRremote - $ platformio lib install 4 - # Installing library [ 4 ]: - # Downloading [####################################] 100% - # Unpacking [####################################] 100% - # The library #4 'IRremote' has been successfully installed! + > platformio lib -g install 4 + + Library Storage: /storage/dir/... + LibraryManager: Installing id=4 + Downloading [####################################] 100% + Unpacking [####################################] 100% + IRremote @ 2.2.1 has been successfully installed! + + # repeat command with name + > platformio lib -g install IRRemote + + Library Storage: /storage/dir/... + Looking for IRRemote library in registry + Found: http://platformio.org/lib/show/4/IRremote + LibraryManager: Installing id=4 + IRremote @ 2.2.1 is already installed -2. Install specified version of library +2. Install specified version of a library to a global storage -.. code-block:: bash +.. code:: - # XBee: http://platformio.org/lib/show/6/XBee - $ platformio lib install 6 --version=0.5 - # Installing library [ 6 ]: - # Downloading [####################################] 100% - # Unpacking [####################################] 100% - # The library #6 'XBee' has been successfully installed! + > platformio lib -g install Json@5.4.0 + + Library Storage: /storage/dir/... + Looking for Json library in registry + Found: http://platformio.org/lib/show/64/Json + LibraryManager: Installing id=64 @ 5.4.0 + Downloading [####################################] 100% + Unpacking [####################################] 100% + Json @ 5.4.0 has been successfully installed! -3. Install library with dependencies +3. Install library with dependencies to custom storage -.. code-block:: bash +.. code:: - # Adafruit-ST7735: http://platformio.org/lib/show/12/Adafruit-ST7735 - $ platformio lib install 12 - # Installing library [ 12 ]: - # Downloading [####################################] 100% - # Unpacking [####################################] 100% - # The library #12 'Adafruit-ST7735' has been successfully installed! - # Installing dependencies: - # Installing library [ 13 ]: - # Downloading [####################################] 100% - # Unpacking [####################################] 100% - # The library #13 'Adafruit-GFX' has been successfully installed! + > platformio lib --storage-dir /my/storage/dir install DallasTemperature + + Library Storage: /my/storage/dir + Looking for DallasTemperature library in registry + Found: http://platformio.org/lib/show/54/DallasTemperature + LibraryManager: Installing id=54 + Downloading [####################################] 100% + Unpacking [####################################] 100% + DallasTemperature @ 3.7.7 has been successfully installed! + Installing dependencies + Looking for OneWire library in registry + Found: http://platformio.org/lib/show/1/OneWire + LibraryManager: Installing id=1 + Downloading [####################################] 100% + Unpacking [####################################] 100% + OneWire @ 8fd2ebfec7 has been successfully installed! + +4. Install ARM mbed library to the global storage + +.. code:: + + > platformio lib -g install https://developer.mbed.org/users/simon/code/TextLCD/ + + Library Storage: /storage/dir/... + LibraryManager: Installing TextLCD + Mercurial Distributed SCM (version 3.8.4) + (see https://mercurial-scm.org for more information) + + Copyright (C) 2005-2016 Matt Mackall and others + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + requesting all changes + adding changesets + adding manifests + adding file changes + added 9 changesets with 18 changes to 6 files + updating to branch default + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + TextLCD @ 308d188a2d3a has been successfully installed! diff --git a/docs/userguide/lib/cmd_list.rst b/docs/userguide/lib/cmd_list.rst index deb19b9c..fb2be037 100644 --- a/docs/userguide/lib/cmd_list.rst +++ b/docs/userguide/lib/cmd_list.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -21,14 +21,30 @@ Usage .. code-block:: bash + platformio lib [STORAGE_OPTIONS] list [OPTIONS] + + # list project dependent libraries + # (run it from a project root where is located "platformio.ini") platformio lib list [OPTIONS] + # list libraries from global storage + platformio lib --global list [OPTIONS] + platformio lib -g list [OPTIONS] + + # list libraries from custom storage + platformio lib --storage-dir /path/to/dir list [OPTIONS] + platformio lib -d /path/to/dir list [OPTIONS] Description ----------- List installed libraries +Storage Options +--------------- + +See base options for :ref:`userguide_lib`. + Options ~~~~~~~ @@ -42,18 +58,14 @@ Return the output in `JSON `_ format Examples -------- -.. code-block:: bash +.. code:: - $ platformio lib list - # - # [ ID ] Name Compatibility "Authors": Description - # ------------------------------------------------------------------------------------- - # [ 23 ] Adafruit-L3GD20-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the L3GD20 Gyroscope - # [ 12 ] Adafruit-ST7735 arduino, atmelavr "Adafruit Industries": A library for the Adafruit 1.8" SPI display - # [ 31 ] Adafruit-Unified-Sensor arduino, atmelavr "Adafruit Industries": Adafruit Unified Sensor Driver - # [ 26 ] Adafruit-LSM303DLHC-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for Adafruit's LSM303 Breakout (Accelerometer + Magnetometer) - # [ 6 ] XBee arduino, atmelavr "Andrew Rapp": Arduino library for communicating with XBees in API mode - # [ 13 ] Adafruit-GFX arduino, atmelavr "Adafruit Industries": A core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.) - # [ 4 ] IRremote arduino, atmelavr "Ken Shirriff": Send and receive infrared signals with multiple protocols - # [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) - # ... + > platformio lib list + + pio lib -g list + Library Storage: /storage/dir/... + [ ID ] Name Compatibility "Authors": Description + ----------------------------------------------------------------------------------------------------------- + [ 4 ] IRremote arduino, atmelavr "Rafi Khan, Ken Shirriff": Send and receive infrared signals with multiple protocols | @2.2.1 + [ 64 ] Json arduino, atmelavr, atmelsam, timsp430, titiva, teensy, freescalekinetis, ststm32, nordicnrf51, nxplpc, espressif, siliconlabsefm32, linux_arm, native, intel_arc32 "Benoit Blanchon": An elegant and efficient JSON library for embedded systems | @5.4.0 + [ VCS ] TextLCD - "Unknown": hg+https://developer.mbed.org/users/simon/code/TextLCD/ | @308d188a2d3a diff --git a/docs/userguide/lib/cmd_register.rst b/docs/userguide/lib/cmd_register.rst index 60f00c21..54ec524d 100644 --- a/docs/userguide/lib/cmd_register.rst +++ b/docs/userguide/lib/cmd_register.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -32,6 +32,6 @@ Register new library and allow others to install it. Examples -------- -.. code-block:: bash +.. code:: - $ platformio lib register http://my.example.com/library.json + platformio lib register http://my.example.com/raw-library.json diff --git a/docs/userguide/lib/cmd_search.rst b/docs/userguide/lib/cmd_search.rst index 4325fe7f..0502b340 100644 --- a/docs/userguide/lib/cmd_search.rst +++ b/docs/userguide/lib/cmd_search.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -74,6 +74,11 @@ Options .. program:: platformio lib search +.. option:: + -n, --name + +Filter libraries by specified name (strict search) + .. option:: -a, --author @@ -112,126 +117,134 @@ Examples 1. List all libraries -.. code-block:: bash +.. code:: - $ platformio lib search - # Found N libraries: - # - # [ ID ] Name Compatibility "Authors": Description - # ------------------------------------------------------------------------------------- - # [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) - # [ 13 ] Adafruit-GFX arduino, atmelavr "Adafruit Industries": A core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.) - # [ 23 ] Adafruit-L3GD20-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the L3GD20 Gyroscope - # [ 26 ] Adafruit-LSM303DLHC-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for Adafruit's LSM303 Breakout (Accelerometer + Magnetometer) - # [ 12 ] Adafruit-ST7735 arduino, atmelavr "Adafruit Industries": A library for the Adafruit 1.8" SPI display - # [ 31 ] Adafruit-Unified-Sensor arduino, atmelavr "Adafruit Industries": Adafruit Unified Sensor Driver - # [ 4 ] IRremote arduino, atmelavr "Ken Shirriff": Send and receive infrared signals with multiple protocols - # [ 1 ] OneWire arduino, atmelavr "Paul Stoffregen": Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) - # [ 6 ] XBee arduino, atmelavr "Andrew Rapp": Arduino library for communicating with XBees in API mode - # [ 15 ] Adafruit-ADXL345-Unified arduino, atmelavr "Adafruit Industries": Unified driver for the ADXL345 Accelerometer - # Show next libraries? [y/N]: - # ... + > platformio lib search + + Found N libraries: + + [ ID ] Name Compatibility "Authors": Description + ------------------------------------------------------------------------------------- + [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) + [ 13 ] Adafruit-GFX arduino, atmelavr "Adafruit Industries": A core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.) + [ 23 ] Adafruit-L3GD20-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the L3GD20 Gyroscope + [ 26 ] Adafruit-LSM303DLHC-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for Adafruit's LSM303 Breakout (Accelerometer + Magnetometer) + [ 12 ] Adafruit-ST7735 arduino, atmelavr "Adafruit Industries": A library for the Adafruit 1.8" SPI display + [ 31 ] Adafruit-Unified-Sensor arduino, atmelavr "Adafruit Industries": Adafruit Unified Sensor Driver + [ 4 ] IRremote arduino, atmelavr "Ken Shirriff": Send and receive infrared signals with multiple protocols + [ 1 ] OneWire arduino, atmelavr "Paul Stoffregen": Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) + [ 6 ] XBee arduino, atmelavr "Andrew Rapp": Arduino library for communicating with XBees in API mode + [ 15 ] Adafruit-ADXL345-Unified arduino, atmelavr "Adafruit Industries": Unified driver for the ADXL345 Accelerometer + Show next libraries? [y/N]: + ... 2. Search for `1-Wire libraries `_ -.. code-block:: bash +.. code:: - $ platformio lib search "1-wire" - # Found N libraries: - # - # [ ID ] Name Compatibility "Authors": Description - # ------------------------------------------------------------------------------------- - # [ 1 ] OneWire arduino, atmelavr "Paul Stoffregen": Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) - # ... + > platformio lib search "1-wire" + + Found N libraries: + + [ ID ] Name Compatibility "Authors": Description + ------------------------------------------------------------------------------------- + [ 1 ] OneWire arduino, atmelavr "Paul Stoffregen": Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) + ... 3. Search for `Arduino-based "I2C" libraries `_ -.. code-block:: bash +.. code:: - $ platformio lib search "i2c" --framework="arduino" - # Found N libraries: - # - # [ ID ] Name Compatibility "Authors": Description - # ------------------------------------------------------------------------------------- - # [ 11 ] I2Cdevlib-Core arduino, atmelavr "Jeff Rowberg": The I2C Device Library (I2Cdevlib) is a collection of uniform and well-documented classes to provide simple and intuitive interfaces to I2C devices. - # [ 24 ] Adafruit-L3GD20 arduino, atmelavr "Adafruit Industries": Driver for Adafruit's L3GD20 I2C Gyroscope Breakout - # [ 10 ] I2Cdevlib-AK8975 arduino, atmelavr "Jeff Rowberg": AK8975 is 3-axis electronic compass IC with high sensitive Hall sensor technology - # [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) - # ... + > platformio lib search "i2c" --framework="arduino" + + Found N libraries: + + [ ID ] Name Compatibility "Authors": Description + ------------------------------------------------------------------------------------- + [ 11 ] I2Cdevlib-Core arduino, atmelavr "Jeff Rowberg": The I2C Device Library (I2Cdevlib) is a collection of uniform and well-documented classes to provide simple and intuitive interfaces to I2C devices. + [ 24 ] Adafruit-L3GD20 arduino, atmelavr "Adafruit Industries": Driver for Adafruit's L3GD20 I2C Gyroscope Breakout + [ 10 ] I2Cdevlib-AK8975 arduino, atmelavr "Jeff Rowberg": AK8975 is 3-axis electronic compass IC with high sensitive Hall sensor technology + [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) + ... 4. Search for `libraries by "web" and "http" keywords `_. -.. code-block:: bash +.. code:: - $ platformio lib search --keyword="web" --keyword="http" - # Found N libraries: - # - # [ ID ] Name Compatibility "Authors": Description - # ------------------------------------------------------------------------------------- - # [ 5 ] Webduino arduino, atmelavr "Ben Combee": An extensible web server library (for use with the Arduino WizNet Ethernet Shield) - # [ 17 ] Adafruit-CC3000 arduino, atmelavr "Adafruit Industries": Library code for Adafruit's CC3000 Wi-Fi/WiFi breakouts - # ... + > platformio lib search --keyword="web" --keyword="http" + + Found N libraries: + + [ ID ] Name Compatibility "Authors": Description + ------------------------------------------------------------------------------------- + [ 5 ] Webduino arduino, atmelavr "Ben Combee": An extensible web server library (for use with the Arduino WizNet Ethernet Shield) + [ 17 ] Adafruit-CC3000 arduino, atmelavr "Adafruit Industries": Library code for Adafruit's CC3000 Wi-Fi/WiFi breakouts + ... 5. Search for `libraries by "Adafruit Industries" author `_ -.. code-block:: bash +.. code:: - $ platformio lib search --author="Adafruit Industries" - # Found N libraries: - # - # [ ID ] Name Compatibility "Authors": Description - # ------------------------------------------------------------------------------------- - # [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) - # [ 13 ] Adafruit-GFX arduino, atmelavr "Adafruit Industries": A core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.) - # [ 23 ] Adafruit-L3GD20-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the L3GD20 Gyroscope - # [ 26 ] Adafruit-LSM303DLHC-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for Adafruit's LSM303 Breakout (Accelerometer + Magnetometer) - # ... + > platformio lib search --author="Adafruit Industries" + + Found N libraries: + + [ ID ] Name Compatibility "Authors": Description + ------------------------------------------------------------------------------------- + [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) + [ 13 ] Adafruit-GFX arduino, atmelavr "Adafruit Industries": A core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.) + [ 23 ] Adafruit-L3GD20-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the L3GD20 Gyroscope + [ 26 ] Adafruit-LSM303DLHC-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for Adafruit's LSM303 Breakout (Accelerometer + Magnetometer) + ... 6. Search for `libraries which are compatible with Dallas temperature sensors `_ like DS18B20, DS18S20 and etc. -.. code-block:: bash +.. code:: - $ platformio lib search "DS*" - # Found N libraries: - # - # [ ID ] Name Compatibility "Authors": Description - # ------------------------------------------------------------------------------------- - # [ 1 ] OneWire arduino, atmelavr "Paul Stoffregen": Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) - # ... + > platformio lib search "DS*" + + Found N libraries: + + [ ID ] Name Compatibility "Authors": Description + ------------------------------------------------------------------------------------- + [ 1 ] OneWire arduino, atmelavr "Paul Stoffregen": Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) + ... 7. Search for `Energia-based *nRF24* or *HttpClient* libraries `_. The search query that is described below can be interpreted like ``energia nRF24 OR energia HttpClient`` -.. code-block:: bash +.. code:: - $ platformio lib search "+(nRF24 HttpClient)" --framework="energia" - # Found 2 libraries: - # - # [ ID ] Name Compatibility "Authors": Description - # ------------------------------------------------------------------------------------- - # [ 46 ] HttpClient energia, timsp430, titiva "Zack Lalanne": HttpClient is a library to make it easier to interact with web servers - # [ 43 ] nRF24 energia, timsp430 "Eric": The nRF24L01 is a low-cost 2.4GHz ISM transceiver module. It supports a number of channel frequencies in the 2.4GHz band and a range of data rates. + > platformio lib search "+(nRF24 HttpClient)" --framework="energia" + + Found 2 libraries: + + [ ID ] Name Compatibility "Authors": Description + ------------------------------------------------------------------------------------- + [ 46 ] HttpClient energia, timsp430, titiva "Zack Lalanne": HttpClient is a library to make it easier to interact with web servers + [ 43 ] nRF24 energia, timsp430 "Eric": The nRF24L01 is a low-cost 2.4GHz ISM transceiver module. It supports a number of channel frequencies in the 2.4GHz band and a range of data rates. 8. Search for the `all sensor libraries excluding temperature `_. -.. code-block:: bash +.. code:: - $ platformio lib search "sensor -temperature" - # Found N libraries: - # - # [ ID ] Name Compatibility "Authors": Description - # ------------------------------------------------------------------------------------- - # [ 31 ] Adafruit-Unified-Sensor arduino, atmelavr "Adafruit Industries": Adafruit Unified Sensor Driver - # [ 10 ] I2Cdevlib-AK8975 arduino, atmelavr "Jeff Rowberg": AK8975 is 3-axis electronic compass IC with high sensitive Hall sensor technology - # [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) - # [ 23 ] Adafruit-L3GD20-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the L3GD20 Gyroscope - # [ 26 ] Adafruit-LSM303DLHC-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for Adafruit's LSM303 Breakout (Accelerometer + Magnetometer) - # [ 33 ] Adafruit-TMP006 arduino, atmelavr "Adafruit Industries": A library for the Adafruit TMP006 Infrared Thermopile Sensor - # [ 34 ] Adafruit-TSL2561-Unified arduino, atmelavr "Adafruit Industries": Unified light sensor driver for Adafruit's TSL2561 breakouts - # [ 97 ] I2Cdevlib-BMA150 arduino, atmelavr "Jeff Rowberg": The BMA150 is a triaxial, low-g acceleration sensor IC with digital output for consumer market applications - # [ 106 ] I2Cdevlib-MPR121 arduino, atmelavr "Jeff Rowberg": The MPR121 is a 12-bit proximity capacitive touch sensor - # [ 111 ] I2Cdevlib-AK8975 energia, timsp430 "Jeff Rowberg": AK8975 is 3-axis electronic compass IC with high sensitive Hall sensor technology - # Show next libraries? [y/N]: + > platformio lib search "sensor -temperature" + + Found N libraries: + + [ ID ] Name Compatibility "Authors": Description + ------------------------------------------------------------------------------------- + [ 31 ] Adafruit-Unified-Sensor arduino, atmelavr "Adafruit Industries": Adafruit Unified Sensor Driver + [ 10 ] I2Cdevlib-AK8975 arduino, atmelavr "Jeff Rowberg": AK8975 is 3-axis electronic compass IC with high sensitive Hall sensor technology + [ 14 ] Adafruit-9DOF-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the Adafruit 9DOF Breakout (L3GD20 / LSM303) + [ 23 ] Adafruit-L3GD20-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for the L3GD20 Gyroscope + [ 26 ] Adafruit-LSM303DLHC-Unified arduino, atmelavr "Adafruit Industries": Unified sensor driver for Adafruit's LSM303 Breakout (Accelerometer + Magnetometer) + [ 33 ] Adafruit-TMP006 arduino, atmelavr "Adafruit Industries": A library for the Adafruit TMP006 Infrared Thermopile Sensor + [ 34 ] Adafruit-TSL2561-Unified arduino, atmelavr "Adafruit Industries": Unified light sensor driver for Adafruit's TSL2561 breakouts + [ 97 ] I2Cdevlib-BMA150 arduino, atmelavr "Jeff Rowberg": The BMA150 is a triaxial, low-g acceleration sensor IC with digital output for consumer market applications + [ 106 ] I2Cdevlib-MPR121 arduino, atmelavr "Jeff Rowberg": The MPR121 is a 12-bit proximity capacitive touch sensor + [ 111 ] I2Cdevlib-AK8975 energia, timsp430 "Jeff Rowberg": AK8975 is 3-axis electronic compass IC with high sensitive Hall sensor technology + Show next libraries? [y/N]: diff --git a/docs/userguide/lib/cmd_show.rst b/docs/userguide/lib/cmd_show.rst index 745685d1..9ee69da4 100644 --- a/docs/userguide/lib/cmd_show.rst +++ b/docs/userguide/lib/cmd_show.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -21,28 +21,65 @@ Usage .. code-block:: bash - platformio lib show ID + platformio lib [STORAGE_OPTIONS] show [LIBRARY] + # show info about project dependent library + # (run it from a project root where is located "platformio.ini") + platformio lib show [LIBRARY] + + # show info about library from global storage + platformio lib --global show [LIBRARY] + platformio lib -g show [LIBRARY] + + # show info about library from custom storage + platformio lib --storage-dir /path/to/dir show [LIBRARY] + platformio lib -d /path/to/dir show [LIBRARY] + + # [LIBRARY] forms + platformio lib [STORAGE_OPTIONS] show + platformio lib [STORAGE_OPTIONS] show + platformio lib [STORAGE_OPTIONS] show @ + platformio lib [STORAGE_OPTIONS] show @ + platformio lib [STORAGE_OPTIONS] show + platformio lib [STORAGE_OPTIONS] show @ + platformio lib [STORAGE_OPTIONS] show @ Description ----------- -Show details about the installed library +Show details about the installed library. +The ``version`` supports `Semantic Versioning `_ ( +``..``) and can take any of the following forms: + +* ``0.1.2`` - an exact version number. Use only this exact version +* ``^0.1.2`` - any compatible version (exact version for ``0.x.x`` versions +* ``~0.1.2`` - any version with the same major and minor versions, and an + equal or greater patch version +* ``>0.1.2`` - any version greater than ``0.1.2``. ``>=``, ``<``, and ``<=`` + are also possible +* ``>0.1.0,!=0.2.0,<0.3.0`` - any version greater than ``0.1.0``, not equal to + ``0.2.0`` and less than ``0.3.0`` + +Storage Options +--------------- + +See base options for :ref:`userguide_lib`. Examples -------- -.. code-block:: bash +.. code:: - # OneWire: http://platformio.org/lib/show/1/OneWire - $ platformio lib show 1 - # OneWire - # ------- - # Authors: Paul Stoffregen http://www.pjrc.com/teensy/td_libs_OneWire.html (maintainer), Jim Studt, Jason Dangel , Derek Yerger, Tom Pollard , Robin James - # Keywords: onewire, 1-wire, bus, sensor, temperature, ibutton - # Frameworks: arduino - # Platforms: atmelavr - # Version: 2.2 - # - # Control devices (from Dallas Semiconductor) that use the One Wire protocol (DS18S20, DS18B20, DS2408 and etc) + platformio lib -g show Json + + Library Storage: /storage/dir/... + Json + ==== + An elegant and efficient JSON library for embedded systems + + Authors: Benoit Blanchon http://blog.benoitblanchon.fr + Keywords: json, rest, http, web + Frameworks: arduino + Platforms: atmelavr, atmelsam, timsp430, titiva, teensy, freescalekinetis, ststm32, nordicnrf51, nxplpc, espressif, siliconlabsefm32, linux_arm, native, intel_arc32 + Version: 5.4.0 diff --git a/docs/userguide/lib/cmd_uninstall.rst b/docs/userguide/lib/cmd_uninstall.rst index df99372b..5df77eca 100644 --- a/docs/userguide/lib/cmd_uninstall.rst +++ b/docs/userguide/lib/cmd_uninstall.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -21,20 +21,56 @@ Usage .. code-block:: bash - platformio lib uninstall ID + platformio lib [STORAGE_OPTIONS] uninstall [LIBRARY...] + # uninstall project dependent library + # (run it from a project root where is located "platformio.ini") + platformio lib uninstall [LIBRARY...] + + # uninstall library from global storage + platformio lib --global uninstall [LIBRARY...] + platformio lib -g uninstall [LIBRARY...] + + # uninstall library from custom storage + platformio lib --storage-dir /path/to/dir uninstall [LIBRARY...] + platformio lib -d /path/to/dir uninstall [LIBRARY...] + + # [LIBRARY...] forms + platformio lib [STORAGE_OPTIONS] uninstall + platformio lib [STORAGE_OPTIONS] uninstall @ + platformio lib [STORAGE_OPTIONS] uninstall @ + platformio lib [STORAGE_OPTIONS] uninstall + platformio lib [STORAGE_OPTIONS] uninstall @ + platformio lib [STORAGE_OPTIONS] uninstall @ Description ----------- Uninstall specified library +The ``version`` supports `Semantic Versioning `_ ( +``..``) and can take any of the following forms: + +* ``0.1.2`` - an exact version number. Use only this exact version +* ``^0.1.2`` - any compatible version (exact version for ``0.x.x`` versions +* ``~0.1.2`` - any version with the same major and minor versions, and an + equal or greater patch version +* ``>0.1.2`` - any version greater than ``0.1.2``. ``>=``, ``<``, and ``<=`` + are also possible +* ``>0.1.0,!=0.2.0,<0.3.0`` - any version greater than ``0.1.0``, not equal to + ``0.2.0`` and less than ``0.3.0`` + +Storage Options +--------------- + +See base options for :ref:`userguide_lib`. Examples -------- -.. code-block:: bash +.. code:: - # XBee: http://platformio.org/lib/show/6/XBee - $ platformio lib uninstall 6 - # The library #6 'XBee' has been successfully uninstalled! + > platformio lib -g uninstall AsyncMqttClient + + Library Storage: /storage/dir/... + Uninstalling AsyncMqttClient @ 0.2.0: [OK] diff --git a/docs/userguide/lib/cmd_update.rst b/docs/userguide/lib/cmd_update.rst index 6b24f699..4e47ac9f 100644 --- a/docs/userguide/lib/cmd_update.rst +++ b/docs/userguide/lib/cmd_update.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present Ivan Kravets 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 @@ -21,51 +21,102 @@ Usage .. code-block:: bash - platformio lib update [LIBRARY_ID] + platformio lib [STORAGE_OPTIONS] update [OPTIONS] + + # update all project libraries + # (run it from a project root where is located "platformio.ini") + platformio lib update [OPTIONS] + + # update project dependent library + platformio lib [STORAGE_OPTIONS] update [OPTIONS] [LIBRARY...] + + # update library in global storage + platformio lib --global update [OPTIONS] [LIBRARY...] + platformio lib -g update [OPTIONS] [LIBRARY...] + + # update library in custom storage + platformio lib --storage-dir /path/to/dir update [OPTIONS] [LIBRARY...] + platformio lib -d /path/to/dir update [OPTIONS] [LIBRARY...] + + # [LIBRARY...] forms + platformio lib [STORAGE_OPTIONS] update + platformio lib [STORAGE_OPTIONS] update @ + platformio lib [STORAGE_OPTIONS] update @ + platformio lib [STORAGE_OPTIONS] update + platformio lib [STORAGE_OPTIONS] update @ + platformio lib [STORAGE_OPTIONS] update @ Description ----------- -Check or update installed libraries +Check or update installed libraries. +The ``version`` supports `Semantic Versioning `_ ( +``..``) and can take any of the following forms: + +* ``0.1.2`` - an exact version number. Use only this exact version +* ``^0.1.2`` - any compatible version (exact version for ``0.x.x`` versions +* ``~0.1.2`` - any version with the same major and minor versions, and an + equal or greater patch version +* ``>0.1.2`` - any version greater than ``0.1.2``. ``>=``, ``<``, and ``<=`` + are also possible +* ``>0.1.0,!=0.2.0,<0.3.0`` - any version greater than ``0.1.0``, not equal to + ``0.2.0`` and less than ``0.3.0`` + +Storage Options +--------------- + +See base options for :ref:`userguide_lib`. + +Options +------- + +.. program:: platformio lib update + +.. option:: + -c, --only-check + +Do not update, only check for new version Examples -------- -1. Update all installed libraries +1. Update all installed libraries in global storage -.. code-block:: bash +.. code:: - $ platformio lib update - # Updating [ 23 ] Adafruit-L3GD20-Unified library: - # Versions: Current=63de2eb9ea, Latest=63de2eb9ea [Up-to-date] - # Updating [ 12 ] Adafruit-ST7735 library: - # Versions: Current=e880eb1687, Latest=e880eb1687 [Up-to-date] - # Updating [ 31 ] Adafruit-Unified-Sensor library: - # Versions: Current=88ae805bce, Latest=88ae805bce [Up-to-date] - # Updating [ 26 ] Adafruit-LSM303DLHC-Unified library: - # Versions: Current=59767208a8, Latest=59767208a8 [Up-to-date] - # Updating [ 13 ] Adafruit-GFX library: - # Versions: Current=a9e5bc4707, Latest=a9e5bc4707 [Up-to-date] - # Updating [ 1 ] OneWire library: - # Versions: Current=2.2, Latest=2.2 [Up-to-date] - # Updating [ 4 ] IRremote library: - # Versions: Current=f2dafe5030, Latest=f2dafe5030 [Up-to-date] - # Updating [ 14 ] Adafruit-9DOF-Unified library: - # Versions: Current=b2f07242ac, Latest=b2f07242ac [Up-to-date] + > platformio lib -g update -2. Update specified libraries + Library Storage: /storage/dir/... + Updating ESP8266_SSD1306 @ 3.2.3: [Up-to-date] + Updating EngduinoMagnetometer @ 3.1.0: [Up-to-date] + Updating IRremote @ 2.2.1: [Up-to-date] + Updating Json @ 5.4.0: [Out-of-date] + LibraryManager: Installing id=64 @ 5.6.4 + Downloading [####################################] 100% + Unpacking [####################################] 100% + Json @ 5.6.4 has been successfully installed! + Updating PJON @ 1fb26fd: [Checking] + git version 2.7.4 (Apple Git-66) + Already up-to-date. + Updating TextLCD @ 308d188a2d3a: [Checking] + Mercurial Distributed SCM (version 3.8.4) + (see https://mercurial-scm.org for more information) -.. code-block:: bash + Copyright (C) 2005-2016 Matt Mackall and others + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + pulling from https://developer.mbed.org/users/simon/code/TextLCD/ + searching for changes + no changes found - $ platformio lib update 1 59 - # Updating [ 1 ] OneWire library: - # Versions: Current=2.2, Latest=2.2 [Up-to-date] - # Updating [ 59 ] USB-Host-Shield-20 library: - # Versions: Current=fcab83dcb3, Latest=c61f9ce1c2 [Out-of-date] - # The library #59 'USB-Host-Shield-20' has been successfully uninstalled! - # Installing library [ 59 ]: - # Downloading [####################################] 100% - # Unpacking [####################################] 100% - # The library #59 'USB-Host-Shield-20' has been successfully installed! +2. Update specified libraries in global storage + +.. code:: + + > platformio lib -g update Json 4 + + Library Storage: /storage/dir/... + Updating Json @ 5.6.4: [Up-to-date] + Updating IRremote @ 2.2.1: [Up-to-date] diff --git a/docs/userguide/lib/index.rst b/docs/userguide/lib/index.rst index 55626bfb..f6aed45b 100644 --- a/docs/userguide/lib/index.rst +++ b/docs/userguide/lib/index.rst @@ -14,15 +14,48 @@ Library Manager =============== -To print all available commands and options use: +Usage +----- .. code-block:: bash - $ platformio lib --help - $ platformio lib COMMAND --help + platformio lib [OPTIONS] COMMAND + + # To print all available commands and options use + platformio lib --help + platformio lib COMMAND --help + +Options +------- + +.. program:: platformio lib + +.. option:: + -g, --global + +.. versionadded:: 3.0 + + +Manage global PlatformIO's library storage ( +":ref:`projectconf_pio_home_dir`/lib") where :ref:`ldf` will look for +dependencies by default. + +.. option:: + -d, --storage-dir + +.. versionadded:: 3.0 + +Manage custom library storage. It can be used later for the +:ref:`projectconf_extra_script` option from :ref:`projectconf`. + +Demo +---- .. image:: ../../_static/platformio-demo-lib.gif +Commands +-------- + .. toctree:: :maxdepth: 2 diff --git a/docs/userguide/platforms/cmd_install.rst b/docs/userguide/platforms/cmd_install.rst index 3ada1992..11563c3c 100644 --- a/docs/userguide/platforms/cmd_install.rst +++ b/docs/userguide/platforms/cmd_install.rst @@ -21,14 +21,18 @@ Usage .. code-block:: bash - # install platform by name platformio platform install [OPTIONS] [PLATFORM...] - # install specific platform version using Semantic Versioning - platformio platform install [OPTIONS] PLATFORM@X.Y.Z - - # install platform using URL - platformio platform install [OPTIONS] URL + # [PLATFORM...] forms + platformio platform install + platformio platform install @ + platformio platform install @ + platformio platform install + platformio platform install file:// + platformio platform install file:// + platformio platform install + platformio platform install (name it should have locally) + platformio platform install ("tag" can be commit, branch or tag) Description @@ -36,33 +40,56 @@ Description Install :ref:`platforms` and dependent packages. -There are several predefined aliases for packages, such as: +The ``version`` supports `Semantic Versioning `_ ( +``..``) and can take any of the following forms: -* ``framework`` -* ``toolchain`` -* ``uploader`` +* ``0.1.2`` - an exact version number. Use only this exact version +* ``^0.1.2`` - any compatible version (exact version for ``0.x.x`` versions +* ``~0.1.2`` - any version with the same major and minor versions, and an + equal or greater patch version +* ``>0.1.2`` - any version greater than ``0.1.2``. ``>=``, ``<``, and ``<=`` + are also possible +* ``>0.1.0,!=0.2.0,<0.3.0`` - any version greater than ``0.1.0``, not equal to + ``0.2.0`` and less than ``0.3.0`` -Local -~~~~~ - -PlatformIO supports installing development platform from local directory or -archive. Need to use ``file://`` prefix before local path. Also, platform -directory or archive should contain ``platform.json`` manifest. +Also, PlatformIO supports installing from local directory or archive. Need to +use ``file://`` prefix before local path. Also, directory or archive should +contain ``platform.json`` manifest. * ``file:///local/path/to/the/platform/dir`` * ``file:///local/path/to/the/platform.zip`` * ``file:///local/path/to/the/platform.tar.gz`` -Remote -~~~~~~ +Options +------- -VCS -~~~ +.. program:: platformio platform install + +.. option:: + --with-package + +Install specified package (or alias) + + +.. option:: + --without-package + +Do not install specified package (or alias) + +.. option:: + --skip-default + +Skip default packages + +Version control +--------------- PlatformIO supports installing from Git, Mercurial and Subversion, and detects the type of VCS using url prefixes: "git+", "hg+", or "svn+". -PlatformIO requires a working VCS command on your path: git, hg or svn. +.. note:: + PlatformIO requires a working VCS command on your path: ``git``, ``hg`` + or ``svn``. Git ^^^ @@ -70,6 +97,7 @@ Git The supported schemes are: ``git``, ``git+https`` and ``git+ssh``. Here are the supported forms: +* platformio/platform-NAME (short version for GitHub repository) * https://github.com/platformio/platform-NAME.git * git+git://git.server.org/my-platform * git+https://git.server.org/my-platform @@ -112,35 +140,15 @@ You can also give specific revisions to an SVN URL, like so: * svn+svn://svn.server.org/my-platform#13 -Options -------- - -.. program:: platformio platform install - -.. option:: - --with-package - -Install specified package (or alias) - - -.. option:: - --without-package - -Do not install specified package (or alias) - -.. option:: - --skip-default - -Skip default packages - Examples -------- 1. Install :ref:`platform_atmelavr` with default packages -.. code-block:: bash +.. code:: + + > platformio platform install atmelavr - $ platformio platform install atmelavr PlatformManager: Installing atmelavr Downloading... Unpacking [####################################] 100% @@ -159,7 +167,9 @@ Examples 2. Install :ref:`platform_atmelavr` with ``uploader`` utility only and skip default packages -.. code-block:: bash +.. code:: + + > platformio platform install atmelavr --skip-default-package --with-package=uploader PlatformManager: Installing atmelavr Downloading [####################################] 100% @@ -178,9 +188,9 @@ Examples 3. Install the latest development :ref:`platform_atmelavr` from Git repository -.. code-block:: bash +.. code:: - $ platformio platform install https://github.com/platformio/platform-atmelavr.git + > platformio platform install https://github.com/platformio/platform-atmelavr.git PlatformManager: Installing platform-atmelavr git version 2.7.4 (Apple Git-66) diff --git a/docs/userguide/platforms/cmd_list.rst b/docs/userguide/platforms/cmd_list.rst index aca7aec1..c4e19756 100644 --- a/docs/userguide/platforms/cmd_list.rst +++ b/docs/userguide/platforms/cmd_list.rst @@ -42,9 +42,10 @@ Return the output in `JSON `_ format Examples -------- -.. code-block:: bash +.. code:: + + > platformio platform list - $ platformio platform list atmelavr ~ Atmel AVR ==================== Atmel AVR 8- and 32-bit MCUs deliver a unique combination of performance, power efficiency and design flexibility. Optimized to speed time to market-and easily adapt to new ones-they are based on the industrys most code-efficient architecture for C and assembly programming. diff --git a/docs/userguide/platforms/cmd_search.rst b/docs/userguide/platforms/cmd_search.rst index 96f1bf5e..e377b631 100644 --- a/docs/userguide/platforms/cmd_search.rst +++ b/docs/userguide/platforms/cmd_search.rst @@ -45,9 +45,10 @@ Examples 1. Print all available development platforms -.. code-block:: bash +.. code:: + + > platformio platform search - $ platformio platform search atmelavr ~ Atmel AVR ==================== Atmel AVR 8- and 32-bit MCUs deliver a unique combination of performance, power efficiency and design flexibility. Optimized to speed time to market-and easily adapt to new ones-they are based on the industrys most code-efficient architecture for C and assembly programming. @@ -75,9 +76,10 @@ Examples 2. Search for TI development platforms -.. code-block:: bash +.. code:: + + > platformio platform search texas - $ platformio platform search texas timsp430 ~ TI MSP430 ==================== MSP430 microcontrollers (MCUs) from Texas Instruments (TI) are 16-bit, RISC-based, mixed-signal processors designed for ultra-low power. These MCUs offer the lowest power consumption and the perfect mix of integrated peripherals for thousands of applications. @@ -92,9 +94,10 @@ Examples Home: http://platformio.org/platforms/titiva Packages: ldscripts, framework-libopencm3, toolchain-gccarmnoneeabi, tool-lm4flash, framework-energiativa -.. code-block:: bash +.. code:: + + > platformio platform search framework-mbed - $ platformio platform search framework-mbed atmelsam ~ Atmel SAM ==================== Atmel | SMART offers Flash- based ARM products based on the ARM Cortex-M0+, Cortex-M3 and Cortex-M4 architectures, ranging from 8KB to 2MB of Flash including a rich peripheral and feature mix. diff --git a/docs/userguide/platforms/cmd_show.rst b/docs/userguide/platforms/cmd_show.rst index 114b4bce..9d02d1f9 100644 --- a/docs/userguide/platforms/cmd_show.rst +++ b/docs/userguide/platforms/cmd_show.rst @@ -33,9 +33,10 @@ Show details about the installed :ref:`platforms` Examples -------- -.. code-block:: bash +.. code:: + + > platformio platform show atmelavr - $ platformio platform show atmelavr atmelavr ~ Atmel AVR ==================== Atmel AVR 8- and 32-bit MCUs deliver a unique combination of performance, power efficiency and design flexibility. Optimized to speed time to market-and easily adapt to new ones-they are based on the industrys most code-efficient architecture for C and assembly programming. diff --git a/docs/userguide/platforms/cmd_uninstall.rst b/docs/userguide/platforms/cmd_uninstall.rst index 3292f147..5066a9c6 100644 --- a/docs/userguide/platforms/cmd_uninstall.rst +++ b/docs/userguide/platforms/cmd_uninstall.rst @@ -36,9 +36,9 @@ Uninstall specified :ref:`platforms` Examples -------- -.. code-block:: bash +.. code:: - $ platformio platform uninstall atmelavr + > platformio platform uninstall atmelavr Uninstalling platform atmelavr @ 0.0.0: [OK] Uninstalling package tool-scons @ 2.4.1: [OK] Uninstalling package toolchain-atmelavr @ 1.40801.0: [OK] diff --git a/docs/userguide/platforms/cmd_update.rst b/docs/userguide/platforms/cmd_update.rst index c48f802b..b225fcb3 100644 --- a/docs/userguide/platforms/cmd_update.rst +++ b/docs/userguide/platforms/cmd_update.rst @@ -51,9 +51,10 @@ Do not update, only check for new version Examples -------- -.. code-block:: bash +.. code:: + + > platformio platform update - $ platformio platform update Platform atmelavr -------- Updating atmelavr @ 0.0.0: [Up-to-date] diff --git a/docs/userguide/platforms/index.rst b/docs/userguide/platforms/index.rst index 437826f1..cc113e86 100644 --- a/docs/userguide/platforms/index.rst +++ b/docs/userguide/platforms/index.rst @@ -18,8 +18,8 @@ To print all available commands and options use: .. code-block:: bash - $ platformio platform --help - $ platformio platform COMMAND --help + platformio platform --help + platformio platform COMMAND --help .. image:: ../../_static/platformio-demo-platforms.gif diff --git a/platformio/__init__.py b/platformio/__init__.py index 6ac5d903..9fd6f088 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev15") +VERSION = (3, 0, "0.dev16") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index bbf8bb09..2a708d81 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,51 +13,136 @@ # limitations under the License. import json +from os.path import join import click -from platformio import app, exception -from platformio.libmanager import LibraryManager +from platformio import app, exception, util +from platformio.managers.lib import LibraryManager from platformio.util import get_api_result + +@click.group(short_help="Library Manager") +@click.option( + "-g", + "--global", + is_flag=True, + help="Manager 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") +@click.pass_context +def cli(ctx, **options): + # skip commands that don't need storage folder + if ctx.invoked_subcommand in ("search", "register") or \ + (len(ctx.args) == 2 and ctx.args[1] in ("-h", "--help")): + return + storage_dir = options['storage_dir'] + if not storage_dir and options['global']: + storage_dir = join(util.get_home_dir(), "lib") + + if not storage_dir and not util.is_platformio_project(): + raise exception.PlatformioException( + "The `%s` is not a PlatformIO project.\nTo manage libraries " + "in the global storage `%s`, please use " + "`platformio lib --global %s` instead." % + (util.get_project_dir(), join(util.get_home_dir(), "lib"), + ctx.invoked_subcommand)) + + ctx.obj = LibraryManager(storage_dir) + click.echo("Library Storage: " + storage_dir) + + +@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( + "-q", "--quiet", is_flag=True, help="Suppress progress reporting") +@click.pass_obj +def lib_install(lm, libraries, save, quiet): # pylint: disable=unused-argument + # @TODO "save" option + for library in libraries: + lm.install(library, quiet=quiet) + + +@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) + + +@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.pass_obj +def lib_update(lm, libraries, only_check): + if not libraries: + libraries = [str(m.get("id", m['name'])) for m in lm.get_installed()] + for library in libraries: + lm.update(library, only_check=only_check) + +####### + LIBLIST_TPL = ("[{id:^14}] {name:<25} {compatibility:<30} " "\"{authornames}\": {description}") def echo_liblist_header(): - click.echo(LIBLIST_TPL.format( - id=click.style("ID", fg="green"), - name=click.style("Name", fg="cyan"), - compatibility=click.style("Compatibility", fg="yellow"), - authornames="Authors", - description="Description" - )) + click.echo( + LIBLIST_TPL.format( + id=click.style( + "ID", fg="green"), + name=click.style( + "Name", fg="cyan"), + compatibility=click.style( + "Compatibility", fg="yellow"), + authornames="Authors", + description="Description")) terminal_width, _ = click.get_terminal_size() click.echo("-" * terminal_width) def echo_liblist_item(item): - click.echo(LIBLIST_TPL.format( - id=click.style(str(item['id']), fg="green"), - name=click.style(item['name'], fg="cyan"), - compatibility=click.style( - ", ".join(item['frameworks'] + item['platforms']), - fg="yellow" - ), - authornames=", ".join(item['authornames']), - description=item['description'] - )) - - -@click.group(short_help="Library Manager") -def cli(): - pass + click.echo( + LIBLIST_TPL.format( + id=click.style( + str(item.get("id", "VCS")), fg="green"), + name=click.style( + item['name'], fg="cyan"), + compatibility=click.style( + ", ".join( + item.get("frameworks", ["-"]) + item.get("platforms", [])), + fg="yellow"), + authornames=", ".join(item.get("authornames", ["Unknown"])), + description=item.get("description", item.get("url", ""))) + + (" | @" + click.style( + item['version'], fg="yellow") if "version" in item else "")) @cli.command("search", short_help="Search for library") @click.option("--json-output", is_flag=True) @click.option("--page", type=click.INT, default=1) +@click.option("-n", "--name", multiple=True) @click.option("-a", "--author", multiple=True) @click.option("-k", "--keyword", multiple=True) @click.option("-f", "--framework", multiple=True) @@ -73,8 +158,9 @@ def lib_search(query, json_output, page, **filters): for value in values: query.append('%s:"%s"' % (key, value)) - result = get_api_result("/lib/search", - dict(query=" ".join(query), page=page)) + result = get_api_result( + "/lib/search", dict( + query=" ".join(query), page=page)) if json_output: click.echo(json.dumps(result)) @@ -84,17 +170,22 @@ def lib_search(query, json_output, page, **filters): click.secho( "Nothing has been found by your request\n" "Try a less-specific search or use truncation (or wildcard) " - "operator", fg="yellow", nl=False) + "operator", + fg="yellow", + nl=False) click.secho(" *", fg="green") click.secho("For example: DS*, PCA*, DHT* and etc.\n", fg="yellow") click.echo("For more examples and advanced search syntax, " "please use documentation:") - click.secho("http://docs.platformio.org" - "/en/latest/userguide/lib/cmd_search.html\n", fg="cyan") + click.secho( + "http://docs.platformio.org" + "/en/latest/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") if result['total']: echo_liblist_header() @@ -111,94 +202,17 @@ def lib_search(query, json_output, page, **filters): click.confirm("Show next libraries?")): result = get_api_result( "/lib/search", - dict(query=" ".join(query), page=int(result['page']) + 1) - ) + dict( + query=" ".join(query), page=int(result['page']) + 1)) else: break -@cli.command("install", short_help="Install library") -@click.argument("libid", type=click.INT, nargs=-1, metavar="[LIBRARY_ID]") -@click.option("-v", "--version") -@click.pass_context -def lib_install(ctx, libid, version): - lm = LibraryManager() - for id_ in libid: - click.echo( - "Installing library [ %s ]:" % click.style(str(id_), fg="green")) - try: - if not lm.install(id_, version): - continue - - info = lm.get_info(id_) - click.secho( - "The library #%s '%s' has been successfully installed!" - % (str(id_), info['name']), fg="green") - - if "dependencies" in info: - click.secho("Installing dependencies:", fg="yellow") - _dependencies = info['dependencies'] - if not isinstance(_dependencies, list): - _dependencies = [_dependencies] - for item in _dependencies: - try: - lib_install_dependency(ctx, item) - except AssertionError: - raise exception.LibInstallDependencyError(str(item)) - - except exception.LibAlreadyInstalled: - click.secho("Already installed", fg="yellow") - - -def lib_install_dependency(ctx, data): - assert isinstance(data, dict) - query = [] - for key in data: - if key in ("authors", "frameworks", "platforms", "keywords"): - values = data[key] - if not isinstance(values, list): - values = [v.strip() for v in values.split(",") if v] - for value in values: - query.append('%s:"%s"' % (key[:-1], value)) - elif isinstance(data[key], basestring): - query.append('+"%s"' % data[key]) - - result = get_api_result("/lib/search", dict(query=" ".join(query))) - assert result['total'] > 0 - - if result['total'] == 1 or not app.get_setting("enable_prompts"): - ctx.invoke(lib_install, libid=[result['items'][0]['id']]) - else: - click.secho( - "Conflict: More than one dependent libraries have been found " - "by request %s:" % json.dumps(data), fg="red") - - echo_liblist_header() - for item in result['items']: - echo_liblist_item(item) - - deplib_id = click.prompt( - "Please choose one dependent library ID", - type=click.Choice([str(i['id']) for i in result['items']])) - ctx.invoke(lib_install, libid=[int(deplib_id)]) - - -@cli.command("uninstall", short_help="Uninstall libraries") -@click.argument("libid", type=click.INT, nargs=-1) -def lib_uninstall(libid): - lm = LibraryManager() - for id_ in libid: - info = lm.get_info(id_) - if lm.uninstall(id_): - click.secho("The library #%s '%s' has been successfully " - "uninstalled!" % (str(id_), info['name']), fg="green") - - @cli.command("list", short_help="List installed libraries") @click.option("--json-output", is_flag=True) -def lib_list(json_output): - lm = LibraryManager() - items = lm.get_installed().values() +@click.pass_obj +def lib_list(lm, json_output): + items = lm.get_installed() if json_output: click.echo(json.dumps(items)) @@ -208,21 +222,34 @@ def lib_list(json_output): return echo_liblist_header() - for item in sorted(items, key=lambda i: i['id']): - item['authornames'] = [i['name'] for i in item['authors']] + for item in sorted(items, key=lambda i: i['name']): + if "authors" in item: + item['authornames'] = [i['name'] for i in item['authors']] echo_liblist_item(item) @cli.command("show", short_help="Show details about installed library") -@click.argument("libid", type=click.INT) -def lib_show(libid): - lm = LibraryManager() - info = lm.get_info(libid) - click.secho(info['name'], fg="cyan") - click.echo("-" * len(info['name'])) +@click.pass_obj +@click.argument("library", metavar="[LIBRARY]") +def lib_show(lm, library): # pylint: disable=too-many-branches + name, requirements, url = lm.parse_pkg_name(library) + installed_dir = lm.get_installed_dir(name, requirements, url) + if not installed_dir: + click.secho( + "%s @ %s is not installed" % (name, requirements or "*"), + fg="yellow") + return + + manifest = lm.load_manifest(installed_dir) + + click.secho(manifest['name'], fg="cyan") + click.echo("=" * len(manifest['name'])) + if "description" in manifest: + click.echo(manifest['description']) + click.echo() _authors = [] - for author in info['authors']: + for author in manifest.get("authors", []): _data = [] for key in ("name", "email", "url", "maintainer"): if not author[key]: @@ -234,61 +261,29 @@ def lib_show(libid): else: _data.append(author[key]) _authors.append(" ".join(_data)) - click.echo("Authors: %s" % ", ".join(_authors)) + if _authors: + click.echo("Authors: %s" % ", ".join(_authors)) - click.echo("Keywords: %s" % ", ".join(info['keywords'])) - if "frameworks" in info: - click.echo("Frameworks: %s" % ", ".join(info['frameworks'])) - if "platforms" in info: - click.echo("Platforms: %s" % ", ".join(info['platforms'])) - click.echo("Version: %s" % info['version']) - click.echo() - click.echo(info['description']) - click.echo() - - -@cli.command("update", short_help="Update installed libraries") -@click.argument("libid", type=click.INT, nargs=-1, required=False, - metavar="[LIBRARY_ID]") -@click.pass_context -def lib_update(ctx, libid): - lm = LibraryManager() - for id_, latest_version in (lm.get_latest_versions() or {}).items(): - if libid and int(id_) not in libid: - continue - - info = lm.get_info(int(id_)) - - click.echo("Updating [ %s ] %s library:" % ( - click.style(id_, fg="yellow"), - click.style(info['name'], fg="cyan"))) - - current_version = info['version'] - if latest_version is None: - click.secho("Unknown library", fg="red") - continue - - click.echo("Versions: Current=%s, Latest=%s \t " % ( - current_version, latest_version), nl=False) - - if current_version == latest_version: - click.echo("[%s]" % (click.style("Up-to-date", fg="green"))) + for key in ("keywords", "frameworks", "platforms", "license", "url", + "version"): + if key not in manifest: continue + if isinstance(manifest[key], list): + click.echo("%s: %s" % (key.title(), ", ".join(manifest[key]))) else: - click.echo("[%s]" % (click.style("Out-of-date", fg="red"))) - - ctx.invoke(lib_uninstall, libid=[int(id_)]) - ctx.invoke(lib_install, libid=[int(id_)]) + click.echo("%s: %s" % (key.title(), manifest[key])) @cli.command("register", short_help="Register 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)) 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") diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 53fc96de..56dab189 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -21,11 +21,11 @@ from time import time import click -from platformio import __version__, app, exception, telemetry, util +from platformio import __version__, exception, telemetry, util from platformio.commands.lib import lib_install as cmd_lib_install from platformio.commands.platform import \ platform_install as cmd_platform_install -from platformio.libmanager import LibraryManager +from platformio.managers.lib import LibraryManager from platformio.managers.platform import PlatformFactory @@ -188,8 +188,8 @@ class EnvironmentProcessor(object): # install dependent libraries if "lib_install" in self.options: - _autoinstall_libs(self.cmd_ctx, self.options['lib_install']) - + _autoinstall_libs(self.cmd_ctx, self.options['lib_install'], + self.verbose) try: p = PlatformFactory.newPlatform(self.options['platform']) @@ -201,22 +201,15 @@ class EnvironmentProcessor(object): return p.run(build_vars, build_targets, self.verbose) -def _autoinstall_libs(ctx, libids_list): - require_libs = [int(l.strip()) for l in libids_list.split(",")] - installed_libs = [ - l['id'] for l in LibraryManager().get_installed().values() - ] - - not_intalled_libs = set(require_libs) - set(installed_libs) - if not require_libs or not not_intalled_libs: - return - - if (not app.get_setting("enable_prompts") or - click.confirm( - "The libraries with IDs '%s' have not been installed yet. " - "Would you like to install them now?" % - ", ".join([str(i) for i in not_intalled_libs]))): - ctx.invoke(cmd_lib_install, libid=not_intalled_libs) +def _autoinstall_libs(ctx, libids_list, verbose=False): + storage_dir = util.get_projectlibdeps_dir() + ctx.obj = LibraryManager(storage_dir) + if verbose: + click.echo("Library Storage: " + storage_dir) + ctx.invoke( + cmd_lib_install, + libraries=[int(l.strip()) for l in libids_list.split(",")], + quiet=not verbose) def _clean_pioenvs_dir(pioenvs_dir): diff --git a/platformio/exception.py b/platformio/exception.py index 197ec0f9..c05d23d0 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -146,18 +146,9 @@ class APIRequestError(PlatformioException): MESSAGE = "[API] {0}" -class LibAlreadyInstalled(PlatformioException): - pass +class LibNotFound(PlatformioException): - -class LibNotInstalled(PlatformioException): - - MESSAGE = "Library #{0:d} has not been installed yet" - - -class LibInstallDependencyError(PlatformioException): - - MESSAGE = "Error has been occurred for library dependency '{0}'" + MESSAGE = "Library `{0}` has not been found in the registry" class InvalidLibConfURL(PlatformioException): diff --git a/platformio/libmanager.py b/platformio/libmanager.py deleted file mode 100644 index 8235d102..00000000 --- a/platformio/libmanager.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright 2014-2016 Ivan Kravets -# -# 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 re -from os import listdir, makedirs, remove, rename -from os.path import isdir, isfile, join -from shutil import rmtree -from tempfile import gettempdir - -from platformio import telemetry, util -from platformio.downloader import FileDownloader -from platformio.exception import LibAlreadyInstalled, LibNotInstalled -from platformio.unpacker import FileUnpacker - - -class LibraryManager(object): - - CONFIG_NAME = ".library.json" - - def __init__(self, lib_dir=None): - self.lib_dir = lib_dir or join(util.get_home_dir(), "lib") - - @staticmethod - def download(url, dest_dir): - fd = FileDownloader(url, dest_dir) - fd.start() - return fd.get_filepath() - - @staticmethod - def unpack(pkgpath, dest_dir): - fu = FileUnpacker(pkgpath, dest_dir) - return fu.start() - - def get_installed(self): - items = {} - if not isdir(self.lib_dir): - return items - for dirname in sorted(listdir(self.lib_dir)): - conf_path = join(self.lib_dir, dirname, self.CONFIG_NAME) - if not isfile(conf_path): - continue - items[dirname] = util.load_json(conf_path) - return items - - def get_latest_versions(self): - lib_ids = [str(item['id']) for item in self.get_installed().values()] - if not lib_ids: - return None - return util.get_api_result("/lib/version/" + str(",".join(lib_ids))) - - def get_outdated(self): - outdated = [] - for id_, latest_version in (self.get_latest_versions() or {}).items(): - info = self.get_info(int(id_)) - if latest_version != info['version']: - outdated.append(info['name']) - return outdated - - def get_info(self, id_): - for item in self.get_installed().values(): - if "id" in item and item['id'] == id_: - return item - raise LibNotInstalled(id_) - - def is_installed(self, id_): - try: - return int(self.get_info(id_)['id']) == id_ - except LibNotInstalled: - return False - - def install(self, id_, version=None): - if self.is_installed(id_): - raise LibAlreadyInstalled() - - dlinfo = util.get_api_result( - "/lib/download/" + str(id_), - dict(version=version) if version else None - ) - dlpath = None - tmplib_dir = join(self.lib_dir, str(id_)) - try: - dlpath = self.download(dlinfo['url'], gettempdir()) - if not isdir(tmplib_dir): - makedirs(tmplib_dir) - self.unpack(dlpath, tmplib_dir) - finally: - if dlpath: - remove(dlpath) - - info = self.get_info(id_) - rename(tmplib_dir, join(self.lib_dir, "%s_ID%d" % ( - re.sub(r"[^\da-zA-Z]+", "_", info['name']), id_))) - - telemetry.on_event( - category="LibraryManager", action="Install", - label="#%d %s" % (id_, info['name']) - ) - - return True - - def uninstall(self, id_): - for libdir, item in self.get_installed().iteritems(): - if "id" in item and item['id'] == id_: - rmtree(join(self.lib_dir, libdir)) - telemetry.on_event( - category="LibraryManager", action="Uninstall", - label="#%d %s" % (id_, item['name']) - ) - return True - raise LibNotInstalled(id_) diff --git a/platformio/maintenance.py b/platformio/maintenance.py index ccea3cd1..2f7d66d1 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -22,12 +22,12 @@ import click import semantic_version from platformio import __version__, app, exception, telemetry, util -from platformio.commands.lib import lib_update as cmd_libraries_update +from platformio.commands.lib import lib_update as cmd_lib_update from platformio.commands.platform import \ platform_install as cmd_platform_install from platformio.commands.platform import platform_update as cmd_platform_update from platformio.commands.upgrade import get_latest_version -from platformio.libmanager import LibraryManager +from platformio.managers.lib import LibraryManager from platformio.managers.platform import PlatformManager @@ -221,16 +221,12 @@ def check_internal_updates(ctx, what): last_check[what + '_update'] = int(time()) app.set_state_item("last_check", last_check) + pm = PlatformManager() if what == "platforms" else LibraryManager() outdated_items = [] - if what == "platforms": - pm = PlatformManager() - for manifest in pm.get_installed(): - if manifest['name'] not in outdated_items and \ - pm.is_outdated(manifest['name']): - outdated_items.append(manifest['name']) - elif what == "libraries": - lm = LibraryManager() - outdated_items = lm.get_outdated() + for manifest in pm.get_installed(): + if manifest['name'] not in outdated_items and \ + pm.is_outdated(manifest['name']): + outdated_items.append(manifest['name']) if not outdated_items: return @@ -245,19 +241,26 @@ def check_internal_updates(ctx, what): if not app.get_setting("auto_update_" + what): click.secho("Please update them via ", fg="yellow", nl=False) click.secho("`platformio %s update`" % - ("lib" if what == "libraries" else "platform"), + ("lib --global" if what == "libraries" else "platform"), + fg="cyan", nl=False) + click.secho(" command.\n", fg="yellow") + click.secho("If you want to manually check for the new versions " + "without updating, please use ", fg="yellow", nl=False) + click.secho("`platformio %s update --only-check`" % + ("lib --global" if what == "libraries" else "platform"), fg="cyan", nl=False) click.secho(" command.", fg="yellow") else: click.secho("Please wait while updating %s ..." % what, fg="yellow") if what == "platforms": - ctx.invoke(cmd_platform_update) + ctx.invoke(cmd_platform_update, platforms=outdated_items) elif what == "libraries": - ctx.invoke(cmd_libraries_update) + ctx.obj = pm + ctx.invoke(cmd_lib_update, libraries=outdated_items) click.echo() - telemetry.on_event(category="Auto", action="Update", - label=what.title()) + telemetry.on_event( + category="Auto", action="Update", label=what.title()) click.echo("*" * terminal_width) click.echo("") diff --git a/platformio/managers/lib.py b/platformio/managers/lib.py new file mode 100644 index 00000000..7a1fd221 --- /dev/null +++ b/platformio/managers/lib.py @@ -0,0 +1,209 @@ +# Copyright 2014-present Ivan Kravets +# +# 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 +from os.path import join + +import click +import semantic_version + +from platformio import app, commands, exception, util +from platformio.managers.package import BasePkgManager + + +class LibraryManager(BasePkgManager): + + def __init__(self, package_dir=None): + if not package_dir: + package_dir = join(util.get_home_dir(), "lib") + BasePkgManager.__init__(self, package_dir) + + @property + def manifest_name(self): + return ".library.json" + + @staticmethod + def max_satisfying_repo_version(versions, requirements=None): + + def _cmp_dates(datestr1, datestr2): + from datetime import datetime + assert "T" in datestr1 and "T" in datestr2 + dateformat = "%Y-%m-%d %H:%M:%S" + date1 = datetime.strptime(datestr1[:-1].replace("T", " "), + dateformat) + date2 = datetime.strptime(datestr2[:-1].replace("T", " "), + dateformat) + if date1 == date2: + return 0 + return -1 if date1 < date2 else 1 + + item = None + reqspec = None + if requirements: + try: + reqspec = semantic_version.Spec(requirements) + except ValueError: + pass + for v in versions: + specver = None + try: + specver = semantic_version.Version(v['version'], partial=True) + except ValueError: + pass + + if reqspec: + if not specver or specver not in reqspec: + continue + if not item or semantic_version.Version( + item['version'], partial=True) < specver: + item = v + elif requirements: + if requirements == v['version']: + return v + else: + if not item or _cmp_dates(item['date'], v['date']) == -1: + item = v + return item + + def get_latest_repo_version(self, name, requirements): + item = self.max_satisfying_repo_version( + util.get_api_result("/lib/versions/%d" % self._get_pkg_id_by_name( + name, requirements)), requirements) + return item['version'] if item else None + + def _get_pkg_id_by_name(self, name, requirements, quiet=False): + if name.startswith("id="): + return int(name[3:]) + # try to find ID from installed packages + installed_dir = self.get_installed_dir(name, requirements) + if installed_dir: + manifest = self.load_manifest(installed_dir) + if "id" in manifest: + return int(manifest['id']) + return int(self.search_for_library({"name": name}, quiet)['id']) + + def _install_from_piorepo(self, name, requirements): + assert name.startswith("id=") + version = self.get_latest_repo_version(name, requirements) + if not version: + raise exception.UndefinedPackageVersion(requirements or "latest", + util.get_systype()) + dl_data = util.get_api_result( + "/lib/download/" + str(name[3:]), dict(version=version)) + assert dl_data + pkg_dir = None + try: + pkg_dir = self._install_from_url( + name, dl_data['url'].replace("http://", "https://"), + requirements) + except exception.APIRequestError: + pkg_dir = self._install_from_url(name, dl_data['url'], + requirements) + return pkg_dir + + def install(self, name, requirements=None, quiet=False, + trigger_event=True): + _name, _requirements, _url = self.parse_pkg_name(name, requirements) + if not _url: + _name = "id=%d" % self._get_pkg_id_by_name( + _name, _requirements, quiet=quiet) + already_installed = self.get_installed_dir(_name, _requirements, _url) + pkg_dir = BasePkgManager.install(self, _name if not _url else name, + _requirements, quiet, trigger_event) + + if already_installed: + return + + manifest = self.load_manifest(pkg_dir) + if "dependencies" not in manifest: + return pkg_dir + + if not quiet: + click.secho("Installing dependencies", fg="yellow") + + _dependencies = manifest['dependencies'] + if not isinstance(_dependencies, list): + _dependencies = [_dependencies] + for filters in _dependencies: + assert "name" in filters + if any([s in filters.get("version", "") for s in ("\\", "/")]): + self.install("{name}={version}".format(**filters)) + else: + lib_info = self.search_for_library(filters, quiet) + if filters.get("version"): + self.install( + lib_info['id'], + requirements=filters.get("version"), + quiet=quiet, + trigger_event=trigger_event) + else: + self.install( + lib_info['id'], + quiet=quiet, + trigger_event=trigger_event) + return pkg_dir + + @staticmethod + def search_for_library( # pylint: disable=too-many-branches + filters, quiet=False): + assert isinstance(filters, dict) + assert "name" in filters + if not quiet: + click.echo("Looking for %s library in registry" % click.style( + filters['name'], fg="cyan")) + query = [] + for key in filters: + if key not in ("name", "authors", "frameworks", "platforms"): + continue + values = filters[key] + if not isinstance(values, list): + values = [v.strip() for v in values.split(",") if v] + for value in values: + query.append('%s:"%s"' % (key[:-1] if key.endswith("s") else + key, value)) + + lib_info = None + result = util.get_api_result( + "/lib/search", dict(query=" ".join(query))) + if result['total'] == 1: + lib_info = result['items'][0] + elif result['total'] > 1: + click.secho( + "Conflict: More than one library has been found " + "by request %s:" % json.dumps(filters), + fg="red") + commands.lib.echo_liblist_header() + for item in result['items']: + commands.lib.echo_liblist_item(item) + + if not app.get_setting("enable_prompts"): + click.echo("Automatically chose the first available library") + lib_info = result['items'][0] + else: + deplib_id = click.prompt( + "Please choose library ID", + type=click.Choice([str(i['id']) for i in result['items']])) + for item in result['items']: + if item['id'] == int(deplib_id): + lib_info = item + break + + if not lib_info: + raise exception.LibNotFound(str(filters)) + if not quiet: + click.echo("Found: %s" % click.style( + "http://platformio.org/lib/show/{id}/{name}".format( + **lib_info), + fg="blue")) + return lib_info diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 45e3e174..ac481866 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -312,7 +312,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): if "=" in text and not text.startswith("id="): name, url = text.split("=", 1) - # Handle GitHub URL (https://github.com/user/package.git) + # Handle GitHub URL (https://github.com/user/package) if url.startswith("https://github.com/") and \ not url.endswith((".zip", ".tar.gz")): url = "git+" + url @@ -394,6 +394,20 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): return best.get("__pkg_dir") return None + def is_outdated(self, name, requirements=None): + installed_dir = self.get_installed_dir(name, requirements) + if not installed_dir: + click.secho( + "%s @ %s is not installed" % (name, requirements or "*"), + fg="yellow") + return + manifest_path = self.get_manifest_path(installed_dir) + if manifest_path.endswith(self.VCS_MANIFEST_NAME): + return False + manifest = self.load_manifest(installed_dir) + return manifest['version'] != self.get_latest_repo_version( + name, requirements) + def install(self, name, requirements=None, quiet=False, trigger_event=True): name, requirements, url = self.parse_pkg_name(name, requirements) diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 2a485f07..9855746c 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -71,9 +71,10 @@ class PlatformManager(BasePkgManager): return True def is_outdated(self, name, requirements=None): + if BasePkgManager.is_outdated(self, name, requirements): + return True p = PlatformFactory.newPlatform(name, requirements) - return (p.are_outdated_packages() or - p.version != self.get_latest_repo_version(name, requirements)) + return p.are_outdated_packages() def cleanup_packages(self, names): self.reset_cache() diff --git a/platformio/vcsclient.py b/platformio/vcsclient.py index fffd6792..da0f9316 100644 --- a/platformio/vcsclient.py +++ b/platformio/vcsclient.py @@ -43,10 +43,10 @@ class VCSClientBase(object): command = None - def __init__(self, src_dir, remote_url=None, branch=None): + def __init__(self, src_dir, remote_url=None, tag=None): self.src_dir = src_dir self.remote_url = remote_url - self.branch = branch + self.tag = tag self.check_client() def check_client(self): @@ -71,7 +71,7 @@ class VCSClientBase(object): @property def can_be_updated(self): - return not self.branch + return not self.tag def get_current_revision(self): raise NotImplementedError @@ -113,19 +113,19 @@ class GitClient(VCSClientBase): @property def can_be_updated(self): - return not self.branch or not self.is_commit_id(self.branch) + return not self.tag or not self.is_commit_id(self.tag) def export(self): - is_commit = self.is_commit_id(self.branch) + is_commit = self.is_commit_id(self.tag) args = ["clone", "--recursive"] - if not self.branch or not is_commit: + if not self.tag or not is_commit: args += ["--depth", "1"] - if self.branch: - args += ["--branch", self.branch] + if self.tag: + args += ["--branch", self.tag] args += [self.remote_url, self.src_dir] assert self.run_cmd(args) if is_commit: - return self.run_cmd(["reset", "--hard", self.branch]) + return self.run_cmd(["reset", "--hard", self.tag]) return True def update(self): @@ -142,8 +142,8 @@ class HgClient(VCSClientBase): def export(self): args = ["clone"] - if self.branch: - args.extend(["--updaterev", self.branch]) + if self.tag: + args.extend(["--updaterev", self.tag]) args.extend([self.remote_url, self.src_dir]) return self.run_cmd(args) @@ -161,8 +161,8 @@ class SvnClient(VCSClientBase): def export(self): args = ["checkout"] - if self.branch: - args.extend(["--revision", self.branch]) + if self.tag: + args.extend(["--revision", self.tag]) args.extend([self.remote_url, self.src_dir]) return self.run_cmd(args) diff --git a/tests/commands/test_boards.py b/tests/commands/test_boards.py index 1a2539fd..be537c15 100644 --- a/tests/commands/test_boards.py +++ b/tests/commands/test_boards.py @@ -14,10 +14,8 @@ import json -from platformio import util from platformio.commands.boards import cli as cmd_boards -from platformio.commands.platform import \ - platform_search as cmd_platform_search +from platformio.commands.platform import platform_search as cmd_platform_search def test_board_json_output(platformio_setup, clirunner, validate_cliresult): diff --git a/tests/commands/test_init.py b/tests/commands/test_init.py index 45c23ed5..1605bba0 100644 --- a/tests/commands/test_init.py +++ b/tests/commands/test_init.py @@ -13,12 +13,12 @@ # limitations under the License. import json -from os import makedirs, getcwd +from os import getcwd, makedirs from os.path import getsize, isdir, isfile, join -from platformio.commands.init import cli -from platformio.commands.boards import cli as cmd_boards from platformio import util +from platformio.commands.boards import cli as cmd_boards +from platformio.commands.init import cli def validate_pioproject(pioproject_dir): diff --git a/tests/commands/test_lib.py b/tests/commands/test_lib.py index e749a68c..220ff632 100644 --- a/tests/commands/test_lib.py +++ b/tests/commands/test_lib.py @@ -12,25 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from os import listdir -from os.path import isdir, isfile, join - import re from platformio.commands.lib import cli -from platformio import util -def validate_libfolder(): - libs_path = util.get_lib_dir() - installed_libs = listdir(libs_path) - for lib in installed_libs: - assert isdir(join(libs_path, lib)) - assert isfile(join(libs_path, lib, ".library.json")) and isfile( - join(libs_path, lib, "library.json")) - - -def test_lib_search(clirunner, validate_cliresult): +def test_search(clirunner, validate_cliresult): result = clirunner.invoke(cli, ["search", "DHT22"]) validate_cliresult(result) match = re.search(r"Found\s+(\d+)\slibraries:", result.output) @@ -42,34 +29,70 @@ def test_lib_search(clirunner, validate_cliresult): assert int(match.group(1)) == 1 -def test_lib_install(clirunner, validate_cliresult): - result = clirunner.invoke(cli, ["install", "58", "115"]) +def test_global_install_registry(clirunner, validate_cliresult, + isolated_pio_home): + result = clirunner.invoke( + cli, ["-g", "install", "58", "OneWire", "Json@5.4.0", "Json@>5.4"]) validate_cliresult(result) - validate_libfolder() + items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] + items2 = ["DHT22_ID58", "Json_ID64", "Json_ID64@5.4.0", "OneWire_ID1"] + assert set(items1) == set(items2) -def test_lib_list(clirunner, validate_cliresult): - result = clirunner.invoke(cli, ["list"]) +def test_global_install_repository(clirunner, validate_cliresult, + isolated_pio_home): + result = clirunner.invoke( + cli, ["-g", "install", "https://github.com/gioblu/PJON.git#3.0", + "https://developer.mbed.org/users/simon/code/TextLCD/", + "http://dl.platformio.org/libraries/archives/3/3756.tar.gz", + "knolleary/pubsubclient"]) validate_cliresult(result) - assert "58" in result.output and "115" in result.output + items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] + items2 = ["PJON", "TextLCD", "ESPAsyncTCP", "PubSubClient"] + assert set(items2) & set(items1) -def test_lib_show(clirunner, validate_cliresult): - result = clirunner.invoke(cli, ["show", "115"]) +def test_global_lib_list(clirunner, validate_cliresult, isolated_pio_home): + result = clirunner.invoke(cli, ["-g", "list"]) validate_cliresult(result) - assert "arduino" in result.output and "atmelavr" in result.output + assert all([n in result.output for n in ("OneWire", "DHT22", "64")]) - result = clirunner.invoke(cli, ["show", "58"]) + result = clirunner.invoke(cli, ["-g", "list", "--json-output"]) validate_cliresult(result) - assert "energia" in result.output and "timsp430" in result.output + assert all( + [n in result.output + for n in ("PJON", + "https://developer.mbed.org/users/simon/code/TextLCD/")]) -def test_lib_update(clirunner, validate_cliresult): - result = clirunner.invoke(cli, ["update"]) +def test_global_lib_show(clirunner, validate_cliresult, isolated_pio_home): + result = clirunner.invoke(cli, ["-g", "show", "64@5.4.0"]) validate_cliresult(result) - assert "58" in result.output and "115" in result.output + assert all( + [s in result.output for s in ("Json", "arduino", "atmelavr", "5.4.0")]) - -def test_lib_uninstall(clirunner, validate_cliresult): - result = clirunner.invoke(cli, ["uninstall", "58", "115"]) + result = clirunner.invoke(cli, ["-g", "show", "Json@>5.4.0"]) validate_cliresult(result) + assert all([s in result.output for s in ("Json", "arduino", "atmelavr")]) + assert "5.4.0" not in result.output + + result = clirunner.invoke(cli, ["-g", "show", "1"]) + validate_cliresult(result) + assert "OneWire" in result.output + + +def test_global_lib_update(clirunner, validate_cliresult, isolated_pio_home): + result = clirunner.invoke(cli, ["-g", "update"]) + validate_cliresult(result) + assert all([s in result.output for s in ("Up-to-date", "Checking")]) + + +def test_global_lib_uninstall(clirunner, validate_cliresult, + isolated_pio_home): + result = clirunner.invoke( + cli, ["-g", "uninstall", "1", "Json@!=5.4.0", "TextLCD"]) + validate_cliresult(result) + items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] + items2 = ["DHT22_ID58", "Json_ID64@5.4.0", "ESPAsyncTCP_ID305", + "pubsubclient", "PJON"] + assert set(items1) == set(items2) diff --git a/tests/commands/test_platform.py b/tests/commands/test_platform.py index bd96230e..2379ec16 100644 --- a/tests/commands/test_platform.py +++ b/tests/commands/test_platform.py @@ -16,8 +16,8 @@ import json import os from os.path import join -from platformio.commands import platform as cli_platform from platformio import exception, util +from platformio.commands import platform as cli_platform def test_list_json_output(clirunner, validate_cliresult): diff --git a/tests/commands/test_settings.py b/tests/commands/test_settings.py index d74c3ad8..b1403e39 100644 --- a/tests/commands/test_settings.py +++ b/tests/commands/test_settings.py @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from platformio.commands.settings import cli from platformio import app +from platformio.commands.settings import cli def test_settings_check(clirunner, validate_cliresult): diff --git a/tests/conftest.py b/tests/conftest.py index f4cdc110..ca5b70f9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present Ivan Kravets # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,29 +12,28 @@ # See the License for the specific language governing permissions and # limitations under the License. -from os import environ - -from click.testing import CliRunner +import os import pytest +from click.testing import CliRunner @pytest.fixture(scope="session") def platformio_setup(request): pioenvvars = ("ENABLE_PROMPTS", "ENABLE_TELEMETRY") for v in pioenvvars: - environ["PLATFORMIO_SETTING_%s" % v] = "No" + os.environ["PLATFORMIO_SETTING_%s" % v] = "No" def platformio_teardown(): for v in pioenvvars: _name = "PLATFORMIO_SETTING_%s" % v - if _name in environ: - del environ[_name] + if _name in os.environ: + del os.environ[_name] request.addfinalizer(platformio_teardown) -@pytest.fixture(scope="session") +@pytest.fixture(scope="module") def clirunner(): return CliRunner() @@ -46,3 +45,15 @@ def validate_cliresult(): assert not result.exception assert "error" not in result.output.lower() return decorator + + +@pytest.fixture(scope="module") +def isolated_pio_home(request, tmpdir_factory): + home_dir = tmpdir_factory.mktemp(".platformio") + os.environ['PLATFORMIO_HOME_DIR'] = str(home_dir) + + def fin(): + del os.environ['PLATFORMIO_HOME_DIR'] + + request.addfinalizer(fin) + return home_dir From bd430e5afd69d197d8409f87e94aa2a4791b23e7 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 2 Aug 2016 20:19:52 +0300 Subject: [PATCH 093/284] Makefile with useful targets --- Makefile | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..383bf6ee --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ + +lint: + pylint --rcfile=./.pylintrc ./platformio + +isort: + isort -rc ./platformio + +clean: + find . -name \*.pyc -delete \ No newline at end of file From 677cff1230a5f9f1d3a38225924b91e9b684709b Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 2 Aug 2016 20:35:28 +0300 Subject: [PATCH 094/284] Stop Supporting Python 2.6 --- .travis.yml | 1 - HISTORY.rst | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5b210f4d..b73e5dd6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ python: env: - TOX_ENV=docs - TOX_ENV=lint - - TOX_ENV=py26 - TOX_ENV=py27 install: diff --git a/HISTORY.rst b/HISTORY.rst index a85dcbac..392c156e 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -65,6 +65,7 @@ PlatformIO 3.0 (`issue #721 `_) * Added ``license`` field to `library.json `__ (`issue #522 `_) +* Stopped Supporting Python 2.6 PlatformIO 2.0 From 1cb8d61787684ac4b85d7a75158a1fd2610f42f1 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 2 Aug 2016 20:40:54 +0300 Subject: [PATCH 095/284] Stop Supporting Python 2.6 --- platformio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 9fd6f088..6bd42967 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -36,7 +36,7 @@ __apiurl__ = "http://api.platformio.org" __apiip__ = "198.7.57.247" -if sys.version_info >= (3, 0, 0): +if sys.version_info < (2, 7, 0) or sys.version_info >= (3, 0, 0): msg = ("PlatformIO version %s does not run under Python version %s.\n" "Python 3 is not yet supported.\n") sys.stderr.write(msg % (__version__, sys.version.split()[0])) From edc04987d38507f9688bb0bcde0a58ecda308889 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 2 Aug 2016 21:31:12 +0300 Subject: [PATCH 096/284] Use stable docs --- README.rst | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.rst b/README.rst index a3854318..2b3817ac 100644 --- a/README.rst +++ b/README.rst @@ -72,13 +72,13 @@ TI MSP430 & Tiva, Teensy, Arduino, mbed, libOpenCM3, etc.* * `Development Platforms `_ * `Frameworks `_ * `Embedded Boards Explorer `_ -* `Library Manager `_ -* `User Guide `_ -* `Continuous Integration `_ -* `IDE Integration `_ -* `Articles about us `_ -* `FAQ `_ -* `Release Notes `_ +* `Library Manager `_ +* `User Guide `_ +* `Continuous Integration `_ +* `IDE Integration `_ +* `Articles about us `_ +* `FAQ `_ +* `Release Notes `_ Use whenever. *Run everywhere.* ------------------------------- @@ -95,12 +95,12 @@ Embedded Development. *Easier Than Ever.* settings for most popular `Embedded Boards `_. * Colourful `command-line output `_ -* `IDE Integration `_ with +* `IDE Integration `_ with *Arduino, Atom, Eclipse, Emacs, Energia, Qt Creator, Sublime Text, Vim, Visual Studio* -* Cloud compiling and `Continuous Integration `_ +* Cloud compiling and `Continuous Integration `_ with *AppVeyor, Circle CI, Drone, Shippable, Travis CI* -* Built-in `Serial Port Monitor `_ and configurable - `build -flags/-options `_ +* Built-in `Serial Port Monitor `_ and configurable + `build -flags/-options `_ * Automatic **firmware uploading** * Pre-built tool chains, frameworks for the popular `Hardware Platforms `_ @@ -113,10 +113,10 @@ The Missing Library Manager. *It's here!* *PlatformIO Library Manager* is the missing library manager for development platforms which allows you to organize and have up-to-date external libraries. -* Friendly `Command-Line Interface `_ +* Friendly `Command-Line Interface `_ * Modern `Web 2.0 Library Search `_ * Open Source `Library Registry API `_ -* Library Crawler based on `library.json `_ +* Library Crawler based on `library.json `_ specification * Library **dependency management** * Automatic library updating @@ -135,7 +135,7 @@ cross-platform substitute for the classic *Make* utility. * Reliable detection of *build changes* * Improved support for *parallel builds* * Ability to share *built files in a cache* -* Lookup for external libraries which are installed via `Library Manager `_ +* Lookup for external libraries which are installed via `Library Manager `_ .. image:: https://raw.githubusercontent.com/platformio/platformio-web/develop/app/images/platformio-scons-builder.png :target: http://platformio.org @@ -145,9 +145,9 @@ Single source code. *Multiple platforms.* ----------------------------------------- *PlatformIO* allows the developer to compile the same code with different development platforms using only *One Command* -`platformio run `_. +`platformio run `_. This happens due to -`Project Configuration File (platformio.ini) `_ +`Project Configuration File (platformio.ini) `_ where you can setup different environments with specific options (platform type, firmware uploading settings, pre-built framework, build flags and many more). @@ -180,7 +180,7 @@ Frameworks: * `SPL `_ * `WiringPi `_ -For further details, please refer to `What is PlatformIO? `_ +For further details, please refer to `What is PlatformIO? `_ Contributing ------------ From fbadf839976ea28341a4c75e867eff298ade6de7 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 3 Aug 2016 00:26:48 +0300 Subject: [PATCH 097/284] Use stable docs --- platformio/__init__.py | 2 +- platformio/commands/lib.py | 2 +- platformio/exception.py | 2 +- platformio/maintenance.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 6bd42967..46a60abe 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev16") +VERSION = (3, 0, "0.dev17") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index 2a708d81..aacf0fc6 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -179,7 +179,7 @@ def lib_search(query, json_output, page, **filters): "please use documentation:") click.secho( "http://docs.platformio.org" - "/en/latest/userguide/lib/cmd_search.html\n", + "/en/stable/userguide/lib/cmd_search.html\n", fg="cyan") return diff --git a/platformio/exception.py b/platformio/exception.py index 049d178e..50da0265 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -181,7 +181,7 @@ class CIBuildEnvsEmpty(PlatformioException): class TestDirEmpty(PlatformioException): MESSAGE = "Test directory '{0}' is empty. More details about Unit "\ - "Testing:\n http://docs.platformio.org/en/latest/platforms/"\ + "Testing:\n http://docs.platformio.org/en/stable/platforms/"\ "unit_testing.html" diff --git a/platformio/maintenance.py b/platformio/maintenance.py index 2f7d66d1..78407ab5 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -207,7 +207,7 @@ def check_platformio_upgrade(): click.secho("pip install -U platformio", fg="cyan", nl=False) click.secho("` command.", fg="yellow") click.secho("Changes: ", fg="yellow", nl=False) - click.secho("http://docs.platformio.org/en/latest/history.html", fg="cyan") + click.secho("http://docs.platformio.org/en/stable/history.html", fg="cyan") click.echo("*" * terminal_width) click.echo("") From 98a6449b063ee61e1f54f3239d26f1cabf564711 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 3 Aug 2016 01:04:40 +0300 Subject: [PATCH 098/284] Show hint about verbosity mode --- platformio/builder/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 714d7ca7..c27e30ed 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -96,6 +96,7 @@ DefaultEnvironment( env = DefaultEnvironment() if env.GetOption("silent"): + print "Use `-v, --verbose` option to enable verbose mode" Progress(env.ProgressHandler) # decode common variables From 82a7e67bece90942ca3c4d9bcb56286e3fcce858 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 3 Aug 2016 17:06:30 +0300 Subject: [PATCH 099/284] Don't show verbose info for LDF when is a clean target --- platformio/builder/tools/piolib.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 6249107f..e108256f 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -21,6 +21,7 @@ import sys from os.path import basename, commonprefix, isdir, isfile, join, realpath import SCons.Scanner +from SCons.Script import COMMAND_LINE_TARGETS from platformio import util from platformio.builder.tools import platformio as piotool @@ -471,6 +472,7 @@ def GetLibBuilders(env): f.lower().strip() for f in env.get("PIOFRAMEWORK", "").split(",") ] compat_mode = int(env.get("LIB_COMPAT_MODE", 1)) + verbose = not (env.GetOption("silent") or env.GetOption('clean')) for libs_dir in env['LIBSOURCE_DIRS']: libs_dir = env.subst(libs_dir) @@ -481,18 +483,18 @@ def GetLibBuilders(env): continue lb = LibBuilderFactory.new(env, join(libs_dir, item)) if lb.name in env.get("LIB_IGNORE", []): - if not env.GetOption("silent"): + if verbose: sys.stderr.write("Ignored library %s\n" % lb.path) continue if compat_mode > 1 and not lb.is_platform_compatible(env[ 'PIOPLATFORM']): - if not env.GetOption("silent"): + if verbose: sys.stderr.write("Platform incompatible library %s\n" % lb.path) continue if compat_mode > 0 and not any([lb.is_framework_compatible(f) for f in env_frameworks]): - if not env.GetOption("silent"): + if verbose: sys.stderr.write("Framework incompatible library %s\n" % lb.path) continue From 11c8ab52f6eda89ea357c962e6ef25d1123df8f5 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 3 Aug 2016 17:43:54 +0300 Subject: [PATCH 100/284] Improve "update" command; add test --- docs/userguide/cmd_update.rst | 248 +++++++++++++++++++++-------- docs/userguide/cmd_upgrade.rst | 7 +- platformio/builder/tools/piolib.py | 1 - platformio/commands/update.py | 18 ++- tests/commands/test_update.py | 29 ++++ 5 files changed, 234 insertions(+), 69 deletions(-) create mode 100644 tests/commands/test_update.py diff --git a/docs/userguide/cmd_update.rst b/docs/userguide/cmd_update.rst index d429bb0d..d27c80dd 100644 --- a/docs/userguide/cmd_update.rst +++ b/docs/userguide/cmd_update.rst @@ -21,91 +21,215 @@ Usage .. code-block:: bash - platformio update + platformio update [OPTIONS] Description ----------- -Check or update installed :ref:`platforms` and -:ref:`Libraries ` +Check or update installed :ref:`platforms` and global +:ref:`Libraries `. This command is combination of 2 sub-commands: + +* :ref:`cmd_platform_update` +* :ref:`cmd_lib_update` + +Options +------- + +.. program:: platformio update + +.. option:: + -c, --only-check + +Do not update, only check for new version Examples -------- -.. code-block:: bash +.. code:: - $ platformio update + > platformio update + + Platform Manager + ================ + Platform timsp430 + -------- + Updating timsp430 @ 0.0.0: [Up-to-date] + Updating toolchain-timsp430 @ 1.40603.0: [Up-to-date] + Updating framework-energiamsp430 @ 1.17.0: [Up-to-date] + Updating framework-arduinomsp430 @ 1.10601.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + + Platform freescalekinetis + -------- + Updating freescalekinetis @ 0.0.0: [Up-to-date] + Updating framework-mbed @ 1.121.1: [Up-to-date] + Updating toolchain-gccarmnoneeabi @ 1.40804.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + + Platform ststm32 + -------- + Updating ststm32 @ 0.0.0: [Up-to-date] + Updating framework-libopencm3 @ 1.1.0: [Up-to-date] + Updating toolchain-gccarmnoneeabi @ 1.40804.0: [Up-to-date] + Updating tool-stlink @ 1.10200.0: [Up-to-date] + Updating framework-spl @ 1.10201.0: [Up-to-date] + Updating framework-cmsis @ 1.40300.0: [Up-to-date] + Updating framework-mbed @ 1.121.1: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + + Platform lattice_ice40 + -------- + Updating lattice_ice40 @ 0.0.0: [Up-to-date] + Updating toolchain-icestorm @ 1.7.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] Platform atmelavr -------- - Updating toolchain-atmelavr package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating tool-avrdude package: - Versions: Current=2, Latest=2 [Up-to-date] - Updating framework-arduinoavr package: - Versions: Current=12, Latest=12 [Up-to-date] - Updating tool-micronucleus package: - Versions: Current=1, Latest=1 [Up-to-date] + Updating atmelavr @ 0.0.0: [Up-to-date] + Updating framework-arduinoavr @ 1.10608.1: [Up-to-date] + Updating tool-avrdude @ 1.60001.1: [Up-to-date] + Updating toolchain-atmelavr @ 1.40801.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] - Platform atmelsam + Platform espressif -------- - Updating framework-arduinosam package: - Versions: Current=3, Latest=3 [Up-to-date] - Updating ldscripts package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating toolchain-gccarmnoneeabi package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating tool-bossac package: - Versions: Current=1, Latest=1 [Up-to-date] + Updating espressif @ 0.0.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + Updating toolchain-xtensa @ 1.40802.0: [Up-to-date] + Updating tool-esptool @ 1.409.0: [Up-to-date] + Updating tool-mkspiffs @ 1.102.0: [Up-to-date] + Updating framework-arduinoespressif @ 1.20300.0: [Up-to-date] + Updating sdk-esp8266 @ 1.10502.0: [Up-to-date] - Platform stm32 + Platform linux_x86_64 -------- - Updating toolchain-gccarmnoneeabi package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating tool-stlink package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating framework-spl package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating framework-cmsis package: - Versions: Current=2, Latest=2 [Up-to-date] - Updating framework-opencm3 package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating ldscripts package: - Versions: Current=1, Latest=1 [Up-to-date] + Updating linux_x86_64 @ 0.0.0: [Up-to-date] + Updating toolchain-gcclinux64 @ 1.40801.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + + Platform windows_x86 + -------- + Updating windows_x86 @ 0.0.0: [Up-to-date] + Updating toolchain-gccmingw32 @ 1.40800.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] Platform teensy -------- - Updating toolchain-atmelavr package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating ldscripts package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating framework-arduinoteensy package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating toolchain-gccarmnoneeabi package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating tool-teensy package: - Versions: Current=1, Latest=1 [Up-to-date] + Updating teensy @ 0.0.0: [Up-to-date] + Updating framework-arduinoteensy @ 1.128.0: [Up-to-date] + Updating tool-teensy @ 1.1.0: [Up-to-date] + Updating framework-mbed @ 1.121.1: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + Updating toolchain-atmelavr @ 1.40801.0: [Up-to-date] + Updating toolchain-gccarmnoneeabi @ 1.40804.0: [Up-to-date] - Platform timsp430 + Platform nordicnrf51 -------- - Updating toolchain-timsp430 package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating tool-mspdebug package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating framework-energiamsp430 package: - Versions: Current=2, Latest=2 [Up-to-date] + Updating nordicnrf51 @ 0.0.0: [Up-to-date] + Updating toolchain-gccarmnoneeabi @ 1.40804.0: [Up-to-date] + Updating framework-arduinonordicnrf51 @ 1.20302.0: [Up-to-date] + Updating framework-mbed @ 1.121.1: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] Platform titiva -------- - Updating ldscripts package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating toolchain-gccarmnoneeabi package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating tool-lm4flash package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating framework-opencm3 package: - Versions: Current=1, Latest=1 [Up-to-date] - Updating framework-energiativa package: - Versions: Current=4, Latest=4 [Up-to-date] + Updating titiva @ 0.0.0: [Up-to-date] + Updating framework-libopencm3 @ 1.1.0: [Up-to-date] + Updating toolchain-gccarmnoneeabi @ 1.40804.0: [Up-to-date] + Updating framework-energiativa @ 1.17.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + + Platform atmelsam + -------- + Updating atmelsam @ 0.0.0: [Up-to-date] + Updating toolchain-gccarmnoneeabi @ 1.40804.0: [Up-to-date] + Updating tool-openocd @ 1.900.0: [Up-to-date] + Updating framework-mbed @ 1.121.1: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + Updating tool-avrdude @ 1.60001.1: [Up-to-date] + Updating tool-bossac @ 1.10601.0: [Up-to-date] + + Platform siliconlabsefm32 + -------- + Updating siliconlabsefm32 @ 0.0.0: [Up-to-date] + Updating framework-mbed @ 1.121.1: [Up-to-date] + Updating toolchain-gccarmnoneeabi @ 1.40804.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + + Platform microchippic32 + -------- + Updating microchippic32 @ 0.0.0: [Up-to-date] + Updating framework-arduinomicrochippic32 @ 1.10201.0: [Up-to-date] + Updating toolchain-microchippic32 @ 1.40803.0: [Up-to-date] + Updating tool-pic32prog @ 1.200200.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + + Platform linux_i686 + -------- + Updating linux_i686 @ 0.0.0: [Up-to-date] + Updating toolchain-gcclinux32 @ 1.40801.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + + Platform intel_arc32 + -------- + Updating intel_arc32 @ 0.0.0: [Up-to-date] + Updating framework-arduinointel @ 1.10006.0: [Up-to-date] + Updating tool-arduino101load @ 1.124.0: [Up-to-date] + Updating toolchain-intelarc32 @ 1.40805.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + + Platform nxplpc + -------- + Updating nxplpc @ 0.0.0: [Up-to-date] + Updating framework-mbed @ 1.121.1: [Up-to-date] + Updating toolchain-gccarmnoneeabi @ 1.40804.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + + Platform linux_arm + -------- + Updating linux_arm @ 0.0.0: [Up-to-date] + Updating toolchain-gccarmlinuxgnueabi @ 1.40802.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + + Platform native + -------- + Updating native @ 0.0.0: [Up-to-date] + Updating tool-scons @ 2.4.1: [Up-to-date] + + + Library Manager + =============== + Updating Adafruit-GFX @ 334e815bc1: [Up-to-date] + Updating Adafruit-ST7735 @ d53d4bf03a: [Up-to-date] + Updating Adafruit-DHT @ 09344416d2: [Up-to-date] + Updating Adafruit-Unified-Sensor @ f2af6f4efc: [Up-to-date] + Updating ESP8266_SSD1306 @ 3.2.3: [Up-to-date] + Updating EngduinoMagnetometer @ 3.1.0: [Up-to-date] + Updating IRremote @ 2.2.1: [Up-to-date] + Updating Json @ 5.6.4: [Up-to-date] + Updating MODSERIAL @ d8422efe47: [Up-to-date] + Updating PJON @ 1fb26fd: [Checking] + git version 2.7.4 (Apple Git-66) + Already up-to-date. + Updating Servo @ 36b69a7ced07: [Checking] + Mercurial Distributed SCM (version 3.8.4) + (see https://mercurial-scm.org for more information) + + Copyright (C) 2005-2016 Matt Mackall and others + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + pulling from https://developer.mbed.org/users/simon/code/Servo/ + searching for changes + no changes found + Updating TextLCD @ 308d188a2d3a: [Checking] + Mercurial Distributed SCM (version 3.8.4) + (see https://mercurial-scm.org for more information) + + Copyright (C) 2005-2016 Matt Mackall and others + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + pulling from https://developer.mbed.org/users/simon/code/TextLCD/ + searching for changes + no changes found diff --git a/docs/userguide/cmd_upgrade.rst b/docs/userguide/cmd_upgrade.rst index d0b1ebce..bc61fd0d 100644 --- a/docs/userguide/cmd_upgrade.rst +++ b/docs/userguide/cmd_upgrade.rst @@ -33,11 +33,12 @@ Check or upgrade PlatformIO to the latest version Examples -------- -.. code-block:: bash +.. code:: + + > platformio upgrade - $ platformio upgrade You are up-to-date! PlatformIO x.x.x is currently the newest version available. # If you have problem with permissions try: - $ sudo platformio upgrade + > sudo platformio upgrade diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index e108256f..e50436d3 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -21,7 +21,6 @@ import sys from os.path import basename, commonprefix, isdir, isfile, join, realpath import SCons.Scanner -from SCons.Script import COMMAND_LINE_TARGETS from platformio import util from platformio.builder.tools import platformio as piotool diff --git a/platformio/commands/update.py b/platformio/commands/update.py index 42830dc2..7fabeb21 100644 --- a/platformio/commands/update.py +++ b/platformio/commands/update.py @@ -16,12 +16,24 @@ import click 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.lib import LibraryManager @click.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") @click.pass_context -def cli(ctx): - ctx.invoke(cmd_platform_update) +def cli(ctx, only_check): + click.echo("Platform Manager") + click.echo("================") + ctx.invoke(cmd_platform_update, only_check=only_check) + click.echo() - ctx.invoke(cmd_lib_update) + click.echo("Library Manager") + click.echo("===============") + ctx.obj = LibraryManager() + ctx.invoke(cmd_lib_update, only_check=only_check) diff --git a/tests/commands/test_update.py b/tests/commands/test_update.py new file mode 100644 index 00000000..c78e55b6 --- /dev/null +++ b/tests/commands/test_update.py @@ -0,0 +1,29 @@ +# Copyright 2014-present Ivan Kravets +# +# 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.update import cli as cmd_update + + +def test_update(platformio_setup, clirunner, validate_cliresult): + matches = ( + "Platform Manager", + "Up-to-date", + "Library Manager" + ) + result = clirunner.invoke(cmd_update, ["--only-check"]) + validate_cliresult(result) + assert all([m in result.output for m in matches]) + result = clirunner.invoke(cmd_update) + validate_cliresult(result) + assert all([m in result.output for m in matches]) From 6b064cb915361c40deac6eef2e684e44c753848c Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 3 Aug 2016 19:58:35 +0300 Subject: [PATCH 101/284] Refactor DevPlatform to PioPlatform --- platformio/__init__.py | 2 +- platformio/builder/main.py | 4 ++-- platformio/builder/tools/piomisc.py | 2 +- .../tools/{devplatform.py => pioplatform.py} | 18 +++++++++--------- platformio/builder/tools/piotest.py | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) rename platformio/builder/tools/{devplatform.py => pioplatform.py} (90%) diff --git a/platformio/__init__.py b/platformio/__init__.py index 46a60abe..031e0d08 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev17") +VERSION = (3, 0, "0.dev18") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/main.py b/platformio/builder/main.py index c27e30ed..0e75f873 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -68,7 +68,7 @@ commonvars.AddVariables( DefaultEnvironment( tools=[ "ar", "as", "gcc", "g++", "gnulink", - "platformio", "devplatform", + "platformio", "pioplatform", "piolib", "piotest", "pioupload", "pioar", "piomisc" ], # yapf: disable toolpath=[join(util.get_source_dir(), "builder", "tools")], @@ -118,7 +118,7 @@ for opt in ("LIB_IGNORE", "LIB_FORCE", "LIB_EXTRA_DIRS"): env[opt] = [l.strip() for l in env[opt].split(",") if l.strip()] env.Prepend(LIBSOURCE_DIRS=env.get("LIB_EXTRA_DIRS", [])) -env.LoadDevPlatform(commonvars) +env.LoadPioPlatform(commonvars) env.SConscriptChdir(0) env.SConsignFile(join("$PROJECTPIOENVS_DIR", ".sconsign.dblite")) diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index e2153798..07a8c55f 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -161,7 +161,7 @@ def DumpIDEData(env): includes.extend(lb.get_inc_dirs()) # includes from toolchains - p = env.DevPlatform() + p = env.PioPlatform() for name in p.get_installed_packages(): if p.get_package_type(name) != "toolchain": continue diff --git a/platformio/builder/tools/devplatform.py b/platformio/builder/tools/pioplatform.py similarity index 90% rename from platformio/builder/tools/devplatform.py rename to platformio/builder/tools/pioplatform.py index deaa017e..521ecdec 100644 --- a/platformio/builder/tools/devplatform.py +++ b/platformio/builder/tools/pioplatform.py @@ -23,23 +23,23 @@ from platformio.managers.platform import PlatformFactory @util.memoized -def initDevPlatform(name): +def initPioPlatform(name): return PlatformFactory.newPlatform(name) -def DevPlatform(env): +def PioPlatform(env): variables = {} for key in ("board", "pioframework"): if key not in env: continue variables[key] = env[key.upper()] - p = initDevPlatform(env['PLATFORM_MANIFEST']) + p = initPioPlatform(env['PLATFORM_MANIFEST']) p.configure_default_packages(variables, COMMAND_LINE_TARGETS) return p def BoardConfig(env, board=None): - p = initDevPlatform(env['PLATFORM_MANIFEST']) + p = initPioPlatform(env['PLATFORM_MANIFEST']) try: config = p.board_config(board if board else env['BOARD']) except exception.UnknownBoard as e: @@ -48,7 +48,7 @@ def BoardConfig(env, board=None): def GetFrameworkScript(env, framework): - p = env.DevPlatform() + p = env.PioPlatform() assert p.frameworks and framework in p.frameworks script_path = env.subst(p.frameworks[framework]['script']) if not isfile(script_path): @@ -56,8 +56,8 @@ def GetFrameworkScript(env, framework): return script_path -def LoadDevPlatform(env, variables): - p = env.DevPlatform() +def LoadPioPlatform(env, variables): + p = env.PioPlatform() installed_packages = p.get_installed_packages() # Add toolchains and uploaders to $PATH @@ -99,8 +99,8 @@ def exists(_): def generate(env): - env.AddMethod(DevPlatform) + env.AddMethod(PioPlatform) env.AddMethod(BoardConfig) env.AddMethod(GetFrameworkScript) - env.AddMethod(LoadDevPlatform) + env.AddMethod(LoadPioPlatform) return env diff --git a/platformio/builder/tools/piotest.py b/platformio/builder/tools/piotest.py index af820dc4..d4fce7c7 100644 --- a/platformio/builder/tools/piotest.py +++ b/platformio/builder/tools/piotest.py @@ -62,7 +62,7 @@ def ProcessTest(env): ) unitylib = env.BuildLibrary( join("$BUILD_DIR", "UnityTestLib"), - env.DevPlatform().get_package_dir("tool-unity") + env.PioPlatform().get_package_dir("tool-unity") ) env.Prepend(LIBS=[unitylib]) From 823e8374b1bc0406ccab7dd641970ed27cf48120 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 3 Aug 2016 20:21:23 +0300 Subject: [PATCH 102/284] Don't show tools in processing output --- platformio/builder/tools/piomisc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 07a8c55f..87f0a9e7 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -265,7 +265,8 @@ def GetActualLDScript(env): def ProgressHandler(env, node): item = str(node) - if "toolchain-" in item or item.endswith((".o", ".h", ".hpp", ".ipp")): + if ("toolchain-" in item or "tool-" in item) or \ + item.endswith((".o", ".h", ".hpp", ".ipp")): return item = item.replace(env['PIOHOME_DIR'], ".platformio") print "Processing %s" % item From 306b77a3f405e7a13d95f9756bc35d9b0186e0cd Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 3 Aug 2016 22:01:11 +0300 Subject: [PATCH 103/284] Extend a clean target --- Makefile | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 383bf6ee..d9f0aeb3 100644 --- a/Makefile +++ b/Makefile @@ -5,5 +5,13 @@ lint: isort: isort -rc ./platformio -clean: - find . -name \*.pyc -delete \ No newline at end of file +clean-docs: + rm -rf docs/_build + +clean: clean-docs + find . -name \*.pyc -delete + find . -name __pycache__ -delete + rm -rf .cache + rm -rf build + rm -rf htmlcov + rm -f .coverage \ No newline at end of file From 0c9d539a920b2b20c0378fb1cb0f3568117c6ddf Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 3 Aug 2016 22:18:51 +0300 Subject: [PATCH 104/284] Update copyrights --- .coveragerc | 2 +- README.rst | 2 +- docs/_static/extra.css | 2 +- docs/articles.rst | 2 +- docs/ci/appveyor.rst | 2 +- docs/ci/circleci.rst | 2 +- docs/ci/drone.rst | 2 +- docs/ci/index.rst | 2 +- docs/ci/shippable.rst | 2 +- docs/ci/travis.rst | 2 +- docs/demo.rst | 2 +- docs/envvars.rst | 2 +- docs/faq.rst | 2 +- docs/frameworks/arduino.rst | 2 +- docs/frameworks/cmsis.rst | 2 +- docs/frameworks/cmsis_extra.rst | 2 +- docs/frameworks/energia.rst | 2 +- docs/frameworks/index.rst | 2 +- docs/frameworks/libopencm3.rst | 2 +- docs/frameworks/libopencm3_extra.rst | 2 +- docs/frameworks/mbed.rst | 2 +- docs/frameworks/mbed_extra.rst | 2 +- docs/frameworks/simba.rst | 2 +- docs/frameworks/simba_extra.rst | 2 +- docs/frameworks/spl.rst | 2 +- docs/frameworks/spl_extra.rst | 2 +- docs/frameworks/wiringpi.rst | 2 +- docs/frameworks/wiringpi_extra.rst | 2 +- docs/history.rst | 2 +- docs/ide.rst | 2 +- docs/ide/_platformio_ide_extra.rst | 2 +- docs/ide/atom.rst | 2 +- docs/ide/clion.rst | 2 +- docs/ide/codeblocks.rst | 2 +- docs/ide/eclipse.rst | 2 +- docs/ide/emacs.rst | 2 +- docs/ide/netbeans.rst | 2 +- docs/ide/qtcreator.rst | 2 +- docs/ide/sublimetext.rst | 2 +- docs/ide/vim.rst | 2 +- docs/ide/visualstudio.rst | 2 +- docs/index.rst | 2 +- docs/installation.rst | 2 +- docs/librarymanager/config.rst | 2 +- docs/librarymanager/creating.rst | 2 +- docs/librarymanager/index.rst | 2 +- docs/librarymanager/ldf.rst | 2 +- docs/platforms/atmelavr.rst | 2 +- docs/platforms/atmelavr_extra.rst | 2 +- docs/platforms/atmelsam.rst | 2 +- docs/platforms/creating_board.rst | 2 +- docs/platforms/creating_platform.rst | 2 +- docs/platforms/custom_platform_and_board.rst | 2 +- docs/platforms/embedded_boards.rst | 2 +- docs/platforms/espressif.rst | 2 +- docs/platforms/espressif_extra.rst | 2 +- docs/platforms/freescalekinetis.rst | 2 +- docs/platforms/index.rst | 2 +- docs/platforms/intel_arc32.rst | 2 +- docs/platforms/lattice_ice40.rst | 2 +- docs/platforms/linux_arm.rst | 2 +- docs/platforms/linux_i686.rst | 2 +- docs/platforms/linux_x86_64.rst | 2 +- docs/platforms/microchippic32.rst | 2 +- docs/platforms/native.rst | 2 +- docs/platforms/nordicnrf51.rst | 2 +- docs/platforms/nordicnrf51_extra.rst | 2 +- docs/platforms/nxplpc.rst | 2 +- docs/platforms/siliconlabsefm32.rst | 2 +- docs/platforms/ststm32.rst | 2 +- docs/platforms/ststm32_extra.rst | 2 +- docs/platforms/teensy.rst | 2 +- docs/platforms/teensy_extra.rst | 2 +- docs/platforms/timsp430.rst | 2 +- docs/platforms/timsp430_extra.rst | 2 +- docs/platforms/titiva.rst | 2 +- docs/platforms/titiva_extra.rst | 2 +- docs/platforms/unit_testing.rst | 2 +- docs/platforms/windows_x86.rst | 2 +- docs/projectconf.rst | 2 +- docs/quickstart.rst | 2 +- docs/userguide/cmd_boards.rst | 2 +- docs/userguide/cmd_ci.rst | 2 +- docs/userguide/cmd_init.rst | 2 +- docs/userguide/cmd_run.rst | 2 +- docs/userguide/cmd_serialports.rst | 2 +- docs/userguide/cmd_settings.rst | 2 +- docs/userguide/cmd_test.rst | 2 +- docs/userguide/cmd_update.rst | 2 +- docs/userguide/cmd_upgrade.rst | 2 +- docs/userguide/index.rst | 2 +- docs/userguide/lib/cmd_install.rst | 2 +- docs/userguide/lib/cmd_list.rst | 2 +- docs/userguide/lib/cmd_register.rst | 2 +- docs/userguide/lib/cmd_search.rst | 2 +- docs/userguide/lib/cmd_show.rst | 2 +- docs/userguide/lib/cmd_uninstall.rst | 2 +- docs/userguide/lib/cmd_update.rst | 2 +- docs/userguide/lib/index.rst | 2 +- docs/userguide/platforms/cmd_install.rst | 2 +- docs/userguide/platforms/cmd_list.rst | 2 +- docs/userguide/platforms/cmd_search.rst | 2 +- docs/userguide/platforms/cmd_show.rst | 2 +- docs/userguide/platforms/cmd_uninstall.rst | 2 +- docs/userguide/platforms/cmd_update.rst | 2 +- docs/userguide/platforms/index.rst | 2 +- docs/what-is-platformio.rst | 2 +- examples | 2 +- platformio/__init__.py | 2 +- platformio/__main__.py | 2 +- platformio/app.py | 2 +- platformio/builder/__init__.py | 2 +- platformio/builder/main.py | 2 +- platformio/builder/tools/__init__.py | 2 +- platformio/builder/tools/pioar.py | 2 +- platformio/builder/tools/piolib.py | 2 +- platformio/builder/tools/piomisc.py | 2 +- platformio/builder/tools/pioplatform.py | 2 +- platformio/builder/tools/piotest.py | 2 +- platformio/builder/tools/pioupload.py | 2 +- platformio/builder/tools/platformio.py | 2 +- platformio/commands/__init__.py | 2 +- platformio/commands/boards.py | 2 +- platformio/commands/ci.py | 2 +- platformio/commands/init.py | 2 +- platformio/commands/lib.py | 2 +- platformio/commands/platform.py | 2 +- platformio/commands/run.py | 2 +- platformio/commands/serialports.py | 2 +- platformio/commands/settings.py | 2 +- platformio/commands/test.py | 2 +- platformio/commands/update.py | 2 +- platformio/commands/upgrade.py | 2 +- platformio/downloader.py | 2 +- platformio/exception.py | 2 +- platformio/ide/__init__.py | 2 +- platformio/ide/projectgenerator.py | 2 +- platformio/maintenance.py | 2 +- platformio/managers/__init__.py | 2 +- platformio/managers/lib.py | 2 +- platformio/managers/package.py | 2 +- platformio/managers/platform.py | 2 +- platformio/telemetry.py | 2 +- platformio/unpacker.py | 2 +- platformio/util.py | 2 +- platformio/vcsclient.py | 2 +- scripts/99-platformio-udev.rules | 2 +- scripts/docspregen.py | 8 ++++---- scripts/fixsymlink.py | 2 +- scripts/get-platformio.py | 2 +- scripts/mbed_to_package.py | 2 +- setup.py | 2 +- tests/commands/test_boards.py | 2 +- tests/commands/test_init.py | 2 +- tests/commands/test_lib.py | 2 +- tests/commands/test_platform.py | 2 +- tests/commands/test_settings.py | 2 +- tests/commands/test_update.py | 2 +- tests/conftest.py | 2 +- tests/test_examples.py | 2 +- tests/test_managers.py | 2 +- tests/test_pkgmanifest.py | 2 +- tox.ini | 2 +- 163 files changed, 166 insertions(+), 166 deletions(-) diff --git a/.coveragerc b/.coveragerc index cfb6fb9d..32d9f345 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/README.rst b/README.rst index d8270b88..b0d469df 100644 --- a/README.rst +++ b/README.rst @@ -192,7 +192,7 @@ See `contributing guidelines +Copyright 2014-present PlatformIO The PlatformIO is licensed under the permissive Apache 2.0 license, so you can use it in both commercial and personal projects with confidence. diff --git a/docs/_static/extra.css b/docs/_static/extra.css index 1d7f3b0b..6c61b363 100644 --- a/docs/_static/extra.css +++ b/docs/_static/extra.css @@ -1,5 +1,5 @@ /** - * Copyright 2014-2016 Ivan Kravets + * Copyright 2014-present PlatformIO * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/docs/articles.rst b/docs/articles.rst index 3ceb7fce..7acd3e5a 100644 --- a/docs/articles.rst +++ b/docs/articles.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ci/appveyor.rst b/docs/ci/appveyor.rst index 2fc919dd..af246a86 100644 --- a/docs/ci/appveyor.rst +++ b/docs/ci/appveyor.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ci/circleci.rst b/docs/ci/circleci.rst index f8d4e333..c159a4ef 100644 --- a/docs/ci/circleci.rst +++ b/docs/ci/circleci.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ci/drone.rst b/docs/ci/drone.rst index 37d0ac0b..8156a449 100644 --- a/docs/ci/drone.rst +++ b/docs/ci/drone.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ci/index.rst b/docs/ci/index.rst index 93b1b2a6..931f5147 100644 --- a/docs/ci/index.rst +++ b/docs/ci/index.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ci/shippable.rst b/docs/ci/shippable.rst index c64e96e9..aafc2d07 100644 --- a/docs/ci/shippable.rst +++ b/docs/ci/shippable.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ci/travis.rst b/docs/ci/travis.rst index cb27dd33..53ff0f06 100644 --- a/docs/ci/travis.rst +++ b/docs/ci/travis.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/demo.rst b/docs/demo.rst index ed55b719..b44a2c69 100644 --- a/docs/demo.rst +++ b/docs/demo.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/envvars.rst b/docs/envvars.rst index fdbbada7..771f043e 100644 --- a/docs/envvars.rst +++ b/docs/envvars.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/faq.rst b/docs/faq.rst index 75ed3cfb..dd30f4bd 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/arduino.rst b/docs/frameworks/arduino.rst index b16c12d6..ff28614b 100644 --- a/docs/frameworks/arduino.rst +++ b/docs/frameworks/arduino.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/cmsis.rst b/docs/frameworks/cmsis.rst index 7520cd94..394c652e 100644 --- a/docs/frameworks/cmsis.rst +++ b/docs/frameworks/cmsis.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/cmsis_extra.rst b/docs/frameworks/cmsis_extra.rst index d57aff1a..fb8711ce 100644 --- a/docs/frameworks/cmsis_extra.rst +++ b/docs/frameworks/cmsis_extra.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/energia.rst b/docs/frameworks/energia.rst index 4f9a2594..5235ee76 100644 --- a/docs/frameworks/energia.rst +++ b/docs/frameworks/energia.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/index.rst b/docs/frameworks/index.rst index 56a5f532..dc925667 100644 --- a/docs/frameworks/index.rst +++ b/docs/frameworks/index.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/libopencm3.rst b/docs/frameworks/libopencm3.rst index 9822bc97..ea45d299 100644 --- a/docs/frameworks/libopencm3.rst +++ b/docs/frameworks/libopencm3.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/libopencm3_extra.rst b/docs/frameworks/libopencm3_extra.rst index f0bc221a..54f9050b 100644 --- a/docs/frameworks/libopencm3_extra.rst +++ b/docs/frameworks/libopencm3_extra.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/mbed.rst b/docs/frameworks/mbed.rst index df5d4c00..05009466 100644 --- a/docs/frameworks/mbed.rst +++ b/docs/frameworks/mbed.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/mbed_extra.rst b/docs/frameworks/mbed_extra.rst index b073db35..4da14956 100644 --- a/docs/frameworks/mbed_extra.rst +++ b/docs/frameworks/mbed_extra.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/simba.rst b/docs/frameworks/simba.rst index 699e38be..93512001 100644 --- a/docs/frameworks/simba.rst +++ b/docs/frameworks/simba.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/simba_extra.rst b/docs/frameworks/simba_extra.rst index 40b700ee..aa4c7298 100755 --- a/docs/frameworks/simba_extra.rst +++ b/docs/frameworks/simba_extra.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/spl.rst b/docs/frameworks/spl.rst index 54fbe5e5..d9203e8b 100644 --- a/docs/frameworks/spl.rst +++ b/docs/frameworks/spl.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/spl_extra.rst b/docs/frameworks/spl_extra.rst index 15b14696..f84cff83 100644 --- a/docs/frameworks/spl_extra.rst +++ b/docs/frameworks/spl_extra.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/wiringpi.rst b/docs/frameworks/wiringpi.rst index c973dbd8..93febf97 100644 --- a/docs/frameworks/wiringpi.rst +++ b/docs/frameworks/wiringpi.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/frameworks/wiringpi_extra.rst b/docs/frameworks/wiringpi_extra.rst index e82a29bc..a0a33ec8 100644 --- a/docs/frameworks/wiringpi_extra.rst +++ b/docs/frameworks/wiringpi_extra.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/history.rst b/docs/history.rst index 08e44848..9c0c0f45 100644 --- a/docs/history.rst +++ b/docs/history.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ide.rst b/docs/ide.rst index 63c3469f..f41e3643 100644 --- a/docs/ide.rst +++ b/docs/ide.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ide/_platformio_ide_extra.rst b/docs/ide/_platformio_ide_extra.rst index c762c1b1..cf446adf 100644 --- a/docs/ide/_platformio_ide_extra.rst +++ b/docs/ide/_platformio_ide_extra.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ide/atom.rst b/docs/ide/atom.rst index 09c6692c..fdfe142b 100644 --- a/docs/ide/atom.rst +++ b/docs/ide/atom.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ide/clion.rst b/docs/ide/clion.rst index 387dad92..01600f2e 100644 --- a/docs/ide/clion.rst +++ b/docs/ide/clion.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ide/codeblocks.rst b/docs/ide/codeblocks.rst index 04819998..dd1857dd 100644 --- a/docs/ide/codeblocks.rst +++ b/docs/ide/codeblocks.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ide/eclipse.rst b/docs/ide/eclipse.rst index 6f889b6b..558117c8 100644 --- a/docs/ide/eclipse.rst +++ b/docs/ide/eclipse.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ide/emacs.rst b/docs/ide/emacs.rst index ef402dfb..769a64ce 100644 --- a/docs/ide/emacs.rst +++ b/docs/ide/emacs.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ide/netbeans.rst b/docs/ide/netbeans.rst index 432ddb26..d4a95e98 100644 --- a/docs/ide/netbeans.rst +++ b/docs/ide/netbeans.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ide/qtcreator.rst b/docs/ide/qtcreator.rst index a84c8875..714d10c7 100644 --- a/docs/ide/qtcreator.rst +++ b/docs/ide/qtcreator.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ide/sublimetext.rst b/docs/ide/sublimetext.rst index feaa5f3a..7e58b2fc 100644 --- a/docs/ide/sublimetext.rst +++ b/docs/ide/sublimetext.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ide/vim.rst b/docs/ide/vim.rst index 02a09733..c6fc368f 100644 --- a/docs/ide/vim.rst +++ b/docs/ide/vim.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/ide/visualstudio.rst b/docs/ide/visualstudio.rst index e7008e92..46323421 100644 --- a/docs/ide/visualstudio.rst +++ b/docs/ide/visualstudio.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/index.rst b/docs/index.rst index 3b95e020..13be0abd 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/installation.rst b/docs/installation.rst index a74cca4e..53dd81ca 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index 1c0e5354..7f619bcb 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/librarymanager/creating.rst b/docs/librarymanager/creating.rst index 2fe3dbbd..5d150f16 100644 --- a/docs/librarymanager/creating.rst +++ b/docs/librarymanager/creating.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/librarymanager/index.rst b/docs/librarymanager/index.rst index 8a935663..5e2327d4 100644 --- a/docs/librarymanager/index.rst +++ b/docs/librarymanager/index.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/librarymanager/ldf.rst b/docs/librarymanager/ldf.rst index e833687b..8744cafb 100644 --- a/docs/librarymanager/ldf.rst +++ b/docs/librarymanager/ldf.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/atmelavr.rst b/docs/platforms/atmelavr.rst index 52bcb584..0c5faa9a 100644 --- a/docs/platforms/atmelavr.rst +++ b/docs/platforms/atmelavr.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/atmelavr_extra.rst b/docs/platforms/atmelavr_extra.rst index 754de6e0..7d97a4d8 100644 --- a/docs/platforms/atmelavr_extra.rst +++ b/docs/platforms/atmelavr_extra.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/atmelsam.rst b/docs/platforms/atmelsam.rst index 12cbc41a..8bc92bbc 100644 --- a/docs/platforms/atmelsam.rst +++ b/docs/platforms/atmelsam.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/creating_board.rst b/docs/platforms/creating_board.rst index df3ab04a..02c8b0ea 100644 --- a/docs/platforms/creating_board.rst +++ b/docs/platforms/creating_board.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/creating_platform.rst b/docs/platforms/creating_platform.rst index 8233fe06..90f14517 100644 --- a/docs/platforms/creating_platform.rst +++ b/docs/platforms/creating_platform.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/custom_platform_and_board.rst b/docs/platforms/custom_platform_and_board.rst index 7db1381c..36614a24 100644 --- a/docs/platforms/custom_platform_and_board.rst +++ b/docs/platforms/custom_platform_and_board.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/embedded_boards.rst b/docs/platforms/embedded_boards.rst index 91df1475..9bf44d69 100644 --- a/docs/platforms/embedded_boards.rst +++ b/docs/platforms/embedded_boards.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/espressif.rst b/docs/platforms/espressif.rst index 56ffbc43..fca7b8ab 100644 --- a/docs/platforms/espressif.rst +++ b/docs/platforms/espressif.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/espressif_extra.rst b/docs/platforms/espressif_extra.rst index 65d7356a..b6315b4e 100644 --- a/docs/platforms/espressif_extra.rst +++ b/docs/platforms/espressif_extra.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/freescalekinetis.rst b/docs/platforms/freescalekinetis.rst index 13e60daf..aba52b24 100644 --- a/docs/platforms/freescalekinetis.rst +++ b/docs/platforms/freescalekinetis.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/index.rst b/docs/platforms/index.rst index f7f68146..cdfa1003 100644 --- a/docs/platforms/index.rst +++ b/docs/platforms/index.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/intel_arc32.rst b/docs/platforms/intel_arc32.rst index c4863e5c..3127fd76 100644 --- a/docs/platforms/intel_arc32.rst +++ b/docs/platforms/intel_arc32.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/lattice_ice40.rst b/docs/platforms/lattice_ice40.rst index 4a836ed3..fd54c760 100644 --- a/docs/platforms/lattice_ice40.rst +++ b/docs/platforms/lattice_ice40.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/linux_arm.rst b/docs/platforms/linux_arm.rst index 56783765..0b69a2d3 100644 --- a/docs/platforms/linux_arm.rst +++ b/docs/platforms/linux_arm.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/linux_i686.rst b/docs/platforms/linux_i686.rst index 583ad151..fb1f3dd7 100644 --- a/docs/platforms/linux_i686.rst +++ b/docs/platforms/linux_i686.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/linux_x86_64.rst b/docs/platforms/linux_x86_64.rst index d770b2e8..445eb691 100644 --- a/docs/platforms/linux_x86_64.rst +++ b/docs/platforms/linux_x86_64.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/microchippic32.rst b/docs/platforms/microchippic32.rst index 51c92e8e..dc5db46a 100644 --- a/docs/platforms/microchippic32.rst +++ b/docs/platforms/microchippic32.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/native.rst b/docs/platforms/native.rst index 68fd805b..a4174222 100644 --- a/docs/platforms/native.rst +++ b/docs/platforms/native.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/nordicnrf51.rst b/docs/platforms/nordicnrf51.rst index fff500b3..75fd69d8 100644 --- a/docs/platforms/nordicnrf51.rst +++ b/docs/platforms/nordicnrf51.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/nordicnrf51_extra.rst b/docs/platforms/nordicnrf51_extra.rst index beab99ce..b77d8629 100644 --- a/docs/platforms/nordicnrf51_extra.rst +++ b/docs/platforms/nordicnrf51_extra.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/nxplpc.rst b/docs/platforms/nxplpc.rst index 2c94410f..c733fa3e 100644 --- a/docs/platforms/nxplpc.rst +++ b/docs/platforms/nxplpc.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/siliconlabsefm32.rst b/docs/platforms/siliconlabsefm32.rst index c4829f08..c1ccc8a5 100644 --- a/docs/platforms/siliconlabsefm32.rst +++ b/docs/platforms/siliconlabsefm32.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/ststm32.rst b/docs/platforms/ststm32.rst index fb1acfa4..6edea8b9 100644 --- a/docs/platforms/ststm32.rst +++ b/docs/platforms/ststm32.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/ststm32_extra.rst b/docs/platforms/ststm32_extra.rst index 6a98012b..077a5517 100644 --- a/docs/platforms/ststm32_extra.rst +++ b/docs/platforms/ststm32_extra.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/teensy.rst b/docs/platforms/teensy.rst index 0edcbcd2..80e92de9 100644 --- a/docs/platforms/teensy.rst +++ b/docs/platforms/teensy.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/teensy_extra.rst b/docs/platforms/teensy_extra.rst index 360ea86c..77438896 100644 --- a/docs/platforms/teensy_extra.rst +++ b/docs/platforms/teensy_extra.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/timsp430.rst b/docs/platforms/timsp430.rst index 28b25393..b807d4b1 100644 --- a/docs/platforms/timsp430.rst +++ b/docs/platforms/timsp430.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/timsp430_extra.rst b/docs/platforms/timsp430_extra.rst index 40e21277..e30f5e3b 100644 --- a/docs/platforms/timsp430_extra.rst +++ b/docs/platforms/timsp430_extra.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/titiva.rst b/docs/platforms/titiva.rst index bf4d6288..88b960b1 100644 --- a/docs/platforms/titiva.rst +++ b/docs/platforms/titiva.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/titiva_extra.rst b/docs/platforms/titiva_extra.rst index bdc91b0c..5830ab70 100644 --- a/docs/platforms/titiva_extra.rst +++ b/docs/platforms/titiva_extra.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/unit_testing.rst b/docs/platforms/unit_testing.rst index 809eb76c..316c17ba 100644 --- a/docs/platforms/unit_testing.rst +++ b/docs/platforms/unit_testing.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/platforms/windows_x86.rst b/docs/platforms/windows_x86.rst index 6f904a0b..690c955b 100644 --- a/docs/platforms/windows_x86.rst +++ b/docs/platforms/windows_x86.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/projectconf.rst b/docs/projectconf.rst index d4866ec3..439ced3d 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 10ebd14e..f6d8600b 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/cmd_boards.rst b/docs/userguide/cmd_boards.rst index 8083e8bb..a4b0eae9 100644 --- a/docs/userguide/cmd_boards.rst +++ b/docs/userguide/cmd_boards.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/cmd_ci.rst b/docs/userguide/cmd_ci.rst index 785f2e0d..283744c6 100644 --- a/docs/userguide/cmd_ci.rst +++ b/docs/userguide/cmd_ci.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/cmd_init.rst b/docs/userguide/cmd_init.rst index 716ed155..6605d9a0 100644 --- a/docs/userguide/cmd_init.rst +++ b/docs/userguide/cmd_init.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/cmd_run.rst b/docs/userguide/cmd_run.rst index 6d2696de..c5b75ea3 100644 --- a/docs/userguide/cmd_run.rst +++ b/docs/userguide/cmd_run.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/cmd_serialports.rst b/docs/userguide/cmd_serialports.rst index 963046b1..882a5f02 100644 --- a/docs/userguide/cmd_serialports.rst +++ b/docs/userguide/cmd_serialports.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/cmd_settings.rst b/docs/userguide/cmd_settings.rst index 24d592d3..04be4260 100644 --- a/docs/userguide/cmd_settings.rst +++ b/docs/userguide/cmd_settings.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/cmd_test.rst b/docs/userguide/cmd_test.rst index 0749f6ec..c42bda6c 100644 --- a/docs/userguide/cmd_test.rst +++ b/docs/userguide/cmd_test.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/cmd_update.rst b/docs/userguide/cmd_update.rst index d27c80dd..137b8172 100644 --- a/docs/userguide/cmd_update.rst +++ b/docs/userguide/cmd_update.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/cmd_upgrade.rst b/docs/userguide/cmd_upgrade.rst index bc61fd0d..887a8b32 100644 --- a/docs/userguide/cmd_upgrade.rst +++ b/docs/userguide/cmd_upgrade.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/index.rst b/docs/userguide/index.rst index 856ebda2..05ada62a 100644 --- a/docs/userguide/index.rst +++ b/docs/userguide/index.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/lib/cmd_install.rst b/docs/userguide/lib/cmd_install.rst index ddfef32b..c43122c0 100644 --- a/docs/userguide/lib/cmd_install.rst +++ b/docs/userguide/lib/cmd_install.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/lib/cmd_list.rst b/docs/userguide/lib/cmd_list.rst index fb2be037..db521e2b 100644 --- a/docs/userguide/lib/cmd_list.rst +++ b/docs/userguide/lib/cmd_list.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/lib/cmd_register.rst b/docs/userguide/lib/cmd_register.rst index 54ec524d..08911f64 100644 --- a/docs/userguide/lib/cmd_register.rst +++ b/docs/userguide/lib/cmd_register.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/lib/cmd_search.rst b/docs/userguide/lib/cmd_search.rst index 0502b340..4bc5d0ea 100644 --- a/docs/userguide/lib/cmd_search.rst +++ b/docs/userguide/lib/cmd_search.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/lib/cmd_show.rst b/docs/userguide/lib/cmd_show.rst index 9ee69da4..b1f09e95 100644 --- a/docs/userguide/lib/cmd_show.rst +++ b/docs/userguide/lib/cmd_show.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/lib/cmd_uninstall.rst b/docs/userguide/lib/cmd_uninstall.rst index 5df77eca..a465ad17 100644 --- a/docs/userguide/lib/cmd_uninstall.rst +++ b/docs/userguide/lib/cmd_uninstall.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/lib/cmd_update.rst b/docs/userguide/lib/cmd_update.rst index 4e47ac9f..aea28cf0 100644 --- a/docs/userguide/lib/cmd_update.rst +++ b/docs/userguide/lib/cmd_update.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/lib/index.rst b/docs/userguide/lib/index.rst index f6aed45b..d0722ab7 100644 --- a/docs/userguide/lib/index.rst +++ b/docs/userguide/lib/index.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-2016 Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/platforms/cmd_install.rst b/docs/userguide/platforms/cmd_install.rst index 11563c3c..4dd8145a 100644 --- a/docs/userguide/platforms/cmd_install.rst +++ b/docs/userguide/platforms/cmd_install.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/platforms/cmd_list.rst b/docs/userguide/platforms/cmd_list.rst index c4e19756..9aacba4c 100644 --- a/docs/userguide/platforms/cmd_list.rst +++ b/docs/userguide/platforms/cmd_list.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/platforms/cmd_search.rst b/docs/userguide/platforms/cmd_search.rst index e377b631..00a3f63a 100644 --- a/docs/userguide/platforms/cmd_search.rst +++ b/docs/userguide/platforms/cmd_search.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/platforms/cmd_show.rst b/docs/userguide/platforms/cmd_show.rst index 9d02d1f9..35ec16c3 100644 --- a/docs/userguide/platforms/cmd_show.rst +++ b/docs/userguide/platforms/cmd_show.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/platforms/cmd_uninstall.rst b/docs/userguide/platforms/cmd_uninstall.rst index 5066a9c6..d26c4c23 100644 --- a/docs/userguide/platforms/cmd_uninstall.rst +++ b/docs/userguide/platforms/cmd_uninstall.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/platforms/cmd_update.rst b/docs/userguide/platforms/cmd_update.rst index b225fcb3..581c2c35 100644 --- a/docs/userguide/platforms/cmd_update.rst +++ b/docs/userguide/platforms/cmd_update.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/userguide/platforms/index.rst b/docs/userguide/platforms/index.rst index cc113e86..b9402f61 100644 --- a/docs/userguide/platforms/index.rst +++ b/docs/userguide/platforms/index.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/docs/what-is-platformio.rst b/docs/what-is-platformio.rst index f7849078..13fd7a2b 100644 --- a/docs/what-is-platformio.rst +++ b/docs/what-is-platformio.rst @@ -1,4 +1,4 @@ -.. Copyright 2014-present Ivan Kravets +.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/examples b/examples index 3b8f997b..dc677cf2 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 3b8f997b6e69879f1b935087e988290046a3fc84 +Subproject commit dc677cf233990929fea1cf36338094837cc5d518 diff --git a/platformio/__init__.py b/platformio/__init__.py index 031e0d08..c972b724 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/__main__.py b/platformio/__main__.py index e60429be..f1d22bd9 100644 --- a/platformio/__main__.py +++ b/platformio/__main__.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/app.py b/platformio/app.py index 7b7d1635..268462d0 100644 --- a/platformio/app.py +++ b/platformio/app.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/builder/__init__.py b/platformio/builder/__init__.py index 0c05c3b0..95899c71 100644 --- a/platformio/builder/__init__.py +++ b/platformio/builder/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 0e75f873..05823c66 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/builder/tools/__init__.py b/platformio/builder/tools/__init__.py index 0c05c3b0..95899c71 100644 --- a/platformio/builder/tools/__init__.py +++ b/platformio/builder/tools/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/builder/tools/pioar.py b/platformio/builder/tools/pioar.py index 6d8a2be0..95d5816b 100644 --- a/platformio/builder/tools/pioar.py +++ b/platformio/builder/tools/pioar.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index e50436d3..35fba8cd 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 87f0a9e7..d2364b79 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/builder/tools/pioplatform.py b/platformio/builder/tools/pioplatform.py index 521ecdec..807f525d 100644 --- a/platformio/builder/tools/pioplatform.py +++ b/platformio/builder/tools/pioplatform.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/builder/tools/piotest.py b/platformio/builder/tools/piotest.py index d4fce7c7..a93f1d78 100644 --- a/platformio/builder/tools/piotest.py +++ b/platformio/builder/tools/piotest.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/builder/tools/pioupload.py b/platformio/builder/tools/pioupload.py index aac85f57..c098f40e 100644 --- a/platformio/builder/tools/pioupload.py +++ b/platformio/builder/tools/pioupload.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index e4875e15..ff048daf 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/__init__.py b/platformio/commands/__init__.py index 5466a0e8..95899c71 100644 --- a/platformio/commands/__init__.py +++ b/platformio/commands/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/boards.py b/platformio/commands/boards.py index 07b800a0..c116a8ba 100644 --- a/platformio/commands/boards.py +++ b/platformio/commands/boards.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index b7b1fe32..e9a92984 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/init.py b/platformio/commands/init.py index 00c0bf03..6497f765 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index aacf0fc6..67c8ff59 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index 9a6d7704..fd72f402 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 56dab189..c662e012 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/serialports.py b/platformio/commands/serialports.py index 19b69ddb..4371b15c 100644 --- a/platformio/commands/serialports.py +++ b/platformio/commands/serialports.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/settings.py b/platformio/commands/settings.py index 43be3c8d..34e460d3 100644 --- a/platformio/commands/settings.py +++ b/platformio/commands/settings.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/test.py b/platformio/commands/test.py index 31811afd..3b16d7a6 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/update.py b/platformio/commands/update.py index 7fabeb21..d97ae99d 100644 --- a/platformio/commands/update.py +++ b/platformio/commands/update.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/commands/upgrade.py b/platformio/commands/upgrade.py index 3440fe89..ddac25c1 100644 --- a/platformio/commands/upgrade.py +++ b/platformio/commands/upgrade.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/downloader.py b/platformio/downloader.py index 891e7bf5..bce15dea 100644 --- a/platformio/downloader.py +++ b/platformio/downloader.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/exception.py b/platformio/exception.py index 50da0265..7064b34e 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/ide/__init__.py b/platformio/ide/__init__.py index 0c05c3b0..95899c71 100644 --- a/platformio/ide/__init__.py +++ b/platformio/ide/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/ide/projectgenerator.py b/platformio/ide/projectgenerator.py index f59ed98b..093508f7 100644 --- a/platformio/ide/projectgenerator.py +++ b/platformio/ide/projectgenerator.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/maintenance.py b/platformio/maintenance.py index 78407ab5..3fc980ac 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/managers/__init__.py b/platformio/managers/__init__.py index 5466a0e8..95899c71 100644 --- a/platformio/managers/__init__.py +++ b/platformio/managers/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/managers/lib.py b/platformio/managers/lib.py index 7a1fd221..a34a196b 100644 --- a/platformio/managers/lib.py +++ b/platformio/managers/lib.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/managers/package.py b/platformio/managers/package.py index ac481866..0b57520d 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 9855746c..fbfc0af3 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/telemetry.py b/platformio/telemetry.py index 48ca79ab..f7c06102 100644 --- a/platformio/telemetry.py +++ b/platformio/telemetry.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/unpacker.py b/platformio/unpacker.py index ab8955cd..1011fe4c 100644 --- a/platformio/unpacker.py +++ b/platformio/unpacker.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/util.py b/platformio/util.py index 879adb12..8a389717 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/platformio/vcsclient.py b/platformio/vcsclient.py index da0f9316..0d3af892 100644 --- a/platformio/vcsclient.py +++ b/platformio/vcsclient.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/scripts/99-platformio-udev.rules b/scripts/99-platformio-udev.rules index ac52af74..3156ef0e 100644 --- a/scripts/99-platformio-udev.rules +++ b/scripts/99-platformio-udev.rules @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/scripts/docspregen.py b/scripts/docspregen.py index 90fb3455..8b42e242 100644 --- a/scripts/docspregen.py +++ b/scripts/docspregen.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -134,7 +134,7 @@ def generate_platform(name): print "Processing platform: %s" % name lines = [] - lines.append(""".. Copyright 2014-present Ivan Kravets + lines.append(""".. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -241,7 +241,7 @@ def generate_framework(type_, data): print "Processing framework: %s" % type_ lines = [] - lines.append(""".. Copyright 2014-present Ivan Kravets + lines.append(""".. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -367,7 +367,7 @@ Packages def update_embedded_boards(): lines = [] - lines.append(""".. Copyright 2014-present Ivan Kravets + lines.append(""".. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/scripts/fixsymlink.py b/scripts/fixsymlink.py index d7d97f37..44a628fd 100644 --- a/scripts/fixsymlink.py +++ b/scripts/fixsymlink.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/scripts/get-platformio.py b/scripts/get-platformio.py index 75453e56..c67debfe 100644 --- a/scripts/get-platformio.py +++ b/scripts/get-platformio.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/scripts/mbed_to_package.py b/scripts/mbed_to_package.py index fcf5581c..6effd7ea 100644 --- a/scripts/mbed_to_package.py +++ b/scripts/mbed_to_package.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/setup.py b/setup.py index c1511504..4c309883 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/commands/test_boards.py b/tests/commands/test_boards.py index be537c15..71f4ebd8 100644 --- a/tests/commands/test_boards.py +++ b/tests/commands/test_boards.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/commands/test_init.py b/tests/commands/test_init.py index 1605bba0..9c8c1189 100644 --- a/tests/commands/test_init.py +++ b/tests/commands/test_init.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/commands/test_lib.py b/tests/commands/test_lib.py index 220ff632..ed4fc603 100644 --- a/tests/commands/test_lib.py +++ b/tests/commands/test_lib.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/commands/test_platform.py b/tests/commands/test_platform.py index 2379ec16..ec618a90 100644 --- a/tests/commands/test_platform.py +++ b/tests/commands/test_platform.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/commands/test_settings.py b/tests/commands/test_settings.py index b1403e39..bec21889 100644 --- a/tests/commands/test_settings.py +++ b/tests/commands/test_settings.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/commands/test_update.py b/tests/commands/test_update.py index c78e55b6..27eb8c9d 100644 --- a/tests/commands/test_update.py +++ b/tests/commands/test_update.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/conftest.py b/tests/conftest.py index ca5b70f9..8483d8b9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/test_examples.py b/tests/test_examples.py index f953feab..959d974b 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/test_managers.py b/tests/test_managers.py index abed10a1..f41c31a1 100644 --- a/tests/test_managers.py +++ b/tests/test_managers.py @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/test_pkgmanifest.py b/tests/test_pkgmanifest.py index 62b1b9d6..476666a0 100644 --- a/tests/test_pkgmanifest.py +++ b/tests/test_pkgmanifest.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tox.ini b/tox.ini index 71717e00..da496e8f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,4 +1,4 @@ -# Copyright 2014-present Ivan Kravets +# Copyright 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. From 87d0ead203d694780c568713d8a5dfd1ca9b6c69 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 3 Aug 2016 23:38:20 +0300 Subject: [PATCH 105/284] Format code with pep8 style --- .style.yapf | 2 + Makefile | 7 + platformio/__init__.py | 11 +- platformio/__main__.py | 16 +- platformio/app.py | 29 ++-- platformio/builder/tools/pioar.py | 4 +- platformio/builder/tools/piomisc.py | 33 ++-- platformio/builder/tools/pioplatform.py | 4 +- platformio/builder/tools/piotest.py | 24 +-- platformio/builder/tools/pioupload.py | 3 +- platformio/builder/tools/platformio.py | 46 +++--- platformio/commands/boards.py | 30 ++-- platformio/commands/ci.py | 48 +++--- platformio/commands/init.py | 82 +++++----- platformio/commands/run.py | 80 +++++----- platformio/commands/serialports.py | 190 ++++++++++++++++-------- platformio/commands/settings.py | 25 ++-- platformio/commands/test.py | 59 ++++---- platformio/commands/update.py | 4 +- platformio/commands/upgrade.py | 60 ++++---- platformio/downloader.py | 3 +- platformio/ide/projectgenerator.py | 26 ++-- platformio/maintenance.py | 102 +++++++------ platformio/telemetry.py | 15 +- platformio/unpacker.py | 7 +- platformio/util.py | 45 +++--- setup.py | 5 - 27 files changed, 514 insertions(+), 446 deletions(-) create mode 100644 .style.yapf diff --git a/.style.yapf b/.style.yapf new file mode 100644 index 00000000..0a658196 --- /dev/null +++ b/.style.yapf @@ -0,0 +1,2 @@ +[style] +blank_line_before_nested_class_or_def = true \ No newline at end of file diff --git a/Makefile b/Makefile index d9f0aeb3..2117e072 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,13 @@ lint: isort: isort -rc ./platformio + isort -rc ./tests + isort -rc ./scripts + +yapf: + yapf --recursive --in-place platformio/ + +before-commit: isort yapf pylint clean-docs: rm -rf docs/_build diff --git a/platformio/__init__.py b/platformio/__init__.py index c972b724..469a4e79 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -18,12 +18,10 @@ VERSION = (3, 0, "0.dev18") __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 and MBED compatible. Ready for Cloud compiling." -) +__description__ = ("An open source ecosystem for IoT development. " + "Cross-platform build system and library manager. " + "Continuous and IDE integration. " + "Arduino and MBED compatible. Ready for Cloud compiling.") __url__ = "http://platformio.org" __author__ = "Ivan Kravets" @@ -35,7 +33,6 @@ __copyright__ = "Copyright 2014-2016 Ivan Kravets" __apiurl__ = "http://api.platformio.org" __apiip__ = "198.7.57.247" - if sys.version_info < (2, 7, 0) or sys.version_info >= (3, 0, 0): msg = ("PlatformIO version %s does not run under Python version %s.\n" "Python 3 is not yet supported.\n") diff --git a/platformio/__main__.py b/platformio/__main__.py index f1d22bd9..08679523 100644 --- a/platformio/__main__.py +++ b/platformio/__main__.py @@ -40,8 +40,8 @@ class PlatformioCLI(click.MultiCommand): # pylint: disable=R0904 def get_command(self, ctx, name): mod = None try: - mod = __import__("platformio.commands." + name, - None, None, ["cli"]) + mod = __import__("platformio.commands." + name, None, None, + ["cli"]) except ImportError: try: return self._handle_obsolate_command(name) @@ -57,11 +57,15 @@ class PlatformioCLI(click.MultiCommand): # pylint: disable=R0904 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): diff --git a/platformio/app.py b/platformio/app.py index 268462d0..3bacc180 100644 --- a/platformio/app.py +++ b/platformio/app.py @@ -49,28 +49,23 @@ DEFAULT_SETTINGS = { "value": False }, "enable_telemetry": { - "description": ( - "Telemetry service (Yes/No)"), + "description": + ("Telemetry service (Yes/No)"), "value": True }, "enable_prompts": { - "description": ( - "Can PlatformIO communicate with you via prompts: " - "propose to install platforms which aren't installed yet, " - "paginate over library search results and etc.)? ATTENTION!!! " - "If you call PlatformIO like subprocess, " - "please disable prompts to avoid blocking (Yes/No)"), + "description": + ("Can PlatformIO communicate with you via prompts: " + "propose to install platforms which aren't installed yet, " + "paginate over library search results and etc.)? ATTENTION!!! " + "If you call PlatformIO like subprocess, " + "please disable prompts to avoid blocking (Yes/No)"), "value": True } } - -SESSION_VARS = { - "command_ctx": None, - "force_option": False, - "caller_id": None -} +SESSION_VARS = {"command_ctx": None, "force_option": False, "caller_id": None} class State(object): @@ -108,8 +103,8 @@ class State(object): return self._lockfile = LockFile(self.path) - if (self._lockfile.is_locked() and - (time() - getmtime(self._lockfile.lock_file)) > 10): + if self._lockfile.is_locked() and \ + (time() - getmtime(self._lockfile.lock_file)) > 10: self._lockfile.break_lock() self._lockfile.acquire() diff --git a/platformio/builder/tools/pioar.py b/platformio/builder/tools/pioar.py index 95d5816b..d530892a 100644 --- a/platformio/builder/tools/pioar.py +++ b/platformio/builder/tools/pioar.py @@ -43,7 +43,7 @@ def generate(env): env.Replace( _huge_sources_hook=_huge_sources_hook, - ARCOM=env.get("ARCOM", "").replace( - "$SOURCES", "${_huge_sources_hook(SOURCES)}")) + ARCOM=env.get("ARCOM", "").replace("$SOURCES", + "${_huge_sources_hook(SOURCES)}")) return env diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index d2364b79..b4f4735e 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -25,15 +25,12 @@ from platformio import util class InoToCPPConverter(object): - PROTOTYPE_RE = re.compile( - r"""^( + PROTOTYPE_RE = re.compile(r"""^( (\s*[a-z_\d]+\*?){1,2} # return type (\s+[a-z_\d]+\s*) # name of prototype \([a-z_,\.\*\&\[\]\s\d]*\) # arguments )\s*\{ # must end with { - """, - re.X | re.M | re.I - ) + """, re.X | re.M | re.I) DETECTMAIN_RE = re.compile(r"void\s+(setup|loop)\s*\(", re.M | re.I) PROTOPTRS_TPLRE = r"\([^&\(]*&(%s)[^\)]*\)" @@ -66,20 +63,18 @@ class InoToCPPConverter(object): split_pos = item['match'].start() break - 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()) result.append(contents[:split_pos].strip()) result.append("%s;" % ";\n".join([p['match'].group(1) for p in prototypes])) - result.append('#line %d "%s"' % ( - contents.count("\n", 0, split_pos) + 2, - file_path.replace("\\", "/"))) + result.append('#line %d "%s"' % + (contents.count("\n", 0, split_pos) + 2, + file_path.replace("\\", "/"))) result.append(contents[split_pos:].strip()) return result @@ -106,8 +101,8 @@ class InoToCPPConverter(object): result.append('#line 1 "%s"' % file_path.replace("\\", "/")) if is_first and prototypes: - result += self.append_prototypes( - file_path, contents, prototypes) + result += self.append_prototypes(file_path, contents, + prototypes) else: result.append(contents) is_first = False @@ -187,9 +182,7 @@ def DumpIDEData(env): if env['PIOPLATFORM'] == "atmelavr": defines.append( "__AVR_%s__" % env.BoardConfig().get("build.mcu").upper() - .replace("ATMEGA", "ATmega") - .replace("ATTINY", "ATtiny") - ) + .replace("ATMEGA", "ATmega").replace("ATTINY", "ATtiny")) return defines LINTCCOM = "$CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS" @@ -257,8 +250,8 @@ def GetActualLDScript(env): return path if script: - env.Exit("Error: Could not find '%s' LD script in LDPATH '%s'" % ( - script, env.subst("$LIBPATH"))) + env.Exit("Error: Could not find '%s' LD script in LDPATH '%s'" % + (script, env.subst("$LIBPATH"))) return None diff --git a/platformio/builder/tools/pioplatform.py b/platformio/builder/tools/pioplatform.py index 807f525d..2cec0992 100644 --- a/platformio/builder/tools/pioplatform.py +++ b/platformio/builder/tools/pioplatform.py @@ -89,9 +89,7 @@ def LoadPioPlatform(env, variables): env.Replace(**{k: board_config.get("%s.%s" % (_opt, _val))}) if "build.ldscript" in board_config: - env.Replace( - LDSCRIPT_PATH=board_config.get("build.ldscript") - ) + env.Replace(LDSCRIPT_PATH=board_config.get("build.ldscript")) def exists(_): diff --git a/platformio/builder/tools/piotest.py b/platformio/builder/tools/piotest.py index a93f1d78..3789e73f 100644 --- a/platformio/builder/tools/piotest.py +++ b/platformio/builder/tools/piotest.py @@ -28,7 +28,6 @@ FRAMEWORK_PARAMETERS = { "serial_begin": "Serial.begin(9600)", "serial_end": "Serial.end()" }, - "mbed": { "framework": "mbed.h", "serial_obj": "Serial pc(USBTX, USBRX);", @@ -37,7 +36,6 @@ FRAMEWORK_PARAMETERS = { "serial_begin": "pc.baud(9600)", "serial_end": "" }, - "energia": { "framework": "Energia.h", "serial_obj": "", @@ -52,19 +50,14 @@ FRAMEWORK_PARAMETERS = { def ProcessTest(env): env.Append( CPPDEFINES=[ - "UNIT_TEST", - "UNITY_INCLUDE_CONFIG_H" + "UNIT_TEST", "UNITY_INCLUDE_CONFIG_H" ], - CPPPATH=[ join("$BUILD_DIR", "UnityTestLib") - ] - ) + ]) unitylib = env.BuildLibrary( join("$BUILD_DIR", "UnityTestLib"), - env.PioPlatform().get_package_dir("tool-unity") - - ) + env.PioPlatform().get_package_dir("tool-unity")) env.Prepend(LIBS=[unitylib]) test_dir = env.subst("$PROJECTTEST_DIR") @@ -75,8 +68,7 @@ def ProcessTest(env): src_filter += " +<%s%s>" % (env['PIOTEST'], sep) return env.CollectBuildFiles( - "$BUILDTEST_DIR", test_dir, src_filter=src_filter, duplicate=False - ) + "$BUILDTEST_DIR", test_dir, src_filter=src_filter, duplicate=False) def GenerateOutputReplacement(env, destination_dir): @@ -124,11 +116,11 @@ void output_complete(void) framework = env.subst("$PIOFRAMEWORK").lower() if framework not in FRAMEWORK_PARAMETERS: - env.Exit( - "Error: %s framework doesn't support testing feature!" % framework) + env.Exit("Error: %s framework doesn't support testing feature!" % + framework) else: - data = Template(TEMPLATECPP).substitute( - FRAMEWORK_PARAMETERS[framework]) + data = Template(TEMPLATECPP).substitute(FRAMEWORK_PARAMETERS[ + framework]) tmp_file = join(destination_dir, "output_export.cpp") with open(tmp_file, "w") as f: diff --git a/platformio/builder/tools/pioupload.py b/platformio/builder/tools/pioupload.py index c098f40e..65d80b79 100644 --- a/platformio/builder/tools/pioupload.py +++ b/platformio/builder/tools/pioupload.py @@ -120,8 +120,7 @@ def AutodetectUploadPort(*args, **kwargs): # pylint: disable=unused-argument "\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" - ) + "/develop/scripts/99-platformio-udev.rules\n") env.Replace(UPLOAD_PORT=_look_for_serial_port()) if env.subst("$UPLOAD_PORT"): diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index ff048daf..0db54cfd 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -32,18 +32,14 @@ SRC_FILTER_DEFAULT = ["+<*>", "-<.git%s>" % sep, "-" % sep] def BuildProgram(env): def _append_pio_macros(): - env.AppendUnique( - CPPDEFINES=["PLATFORMIO={0:02d}{1:02d}{2:02d}".format( - *pioversion_to_intstr())]) + env.AppendUnique(CPPDEFINES=["PLATFORMIO={0:02d}{1:02d}{2:02d}".format( + *pioversion_to_intstr())]) _append_pio_macros() # fix ASM handling under non-casitive OS if not case_sensitive_suffixes(".s", ".S"): - env.Replace( - AS="$CC", - ASCOM="$ASPPCOM" - ) + env.Replace(AS="$CC", ASCOM="$ASPPCOM") # process extra flags from board if "BOARD" in env and "build.extra_flags" in env.BoardConfig(): @@ -55,7 +51,8 @@ def BuildProgram(env): if env.get("PIOFRAMEWORK"): env.BuildFrameworks([ - f.lower().strip() for f in env['PIOFRAMEWORK'].split(",")]) + f.lower().strip() for f in env['PIOFRAMEWORK'].split(",") + ]) # restore PIO macros if it was deleted by framework _append_pio_macros() @@ -66,18 +63,12 @@ def BuildProgram(env): # 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"'] - ) + 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" - ) + env.Prepend(_LIBFLAGS="-Wl,--start-group ") + env.Append(_LIBFLAGS=" -Wl,--end-group") # Handle SRC_BUILD_FLAGS env.ProcessFlags(env.get("SRC_BUILD_FLAGS")) @@ -96,14 +87,11 @@ def BuildProgram(env): env.Append(PIOBUILDFILES=env.ProcessTest()) if not env['PIOBUILDFILES'] and not COMMAND_LINE_TARGETS: - env.Exit( - "Error: Nothing to build. Please put your source code files " - "to '%s' folder" % env.subst("$PROJECTSRC_DIR")) + env.Exit("Error: Nothing to build. Please put your source code files " + "to '%s' folder" % env.subst("$PROJECTSRC_DIR")) program = env.Program( - join("$BUILD_DIR", env.subst("$PROGNAME")), - env['PIOBUILDFILES'] - ) + join("$BUILD_DIR", env.subst("$PROGNAME")), env['PIOBUILDFILES']) if set(["upload", "uploadlazy", "program"]) & set(COMMAND_LINE_TARGETS): env.AddPostAction(program, env.CheckUploadSize) @@ -210,8 +198,11 @@ def VariantDirWrap(env, variant_dir, src_dir, duplicate=False): env.VariantDir(variant_dir, src_dir, duplicate) -def CollectBuildFiles(env, variant_dir, src_dir, - src_filter=None, duplicate=False): +def CollectBuildFiles(env, + variant_dir, + src_dir, + src_filter=None, + duplicate=False): sources = [] variants = [] @@ -239,9 +230,8 @@ def BuildFrameworks(env, frameworks): return if "BOARD" not in env: - env.Exit( - "Please specify `board` in `platformio.ini` to use " - "with '%s' framework" % ", ".join(frameworks)) + env.Exit("Please specify `board` in `platformio.ini` to use " + "with '%s' framework" % ", ".join(frameworks)) board_frameworks = env.BoardConfig().get("frameworks", []) if frameworks == ["platformio"]: diff --git a/platformio/commands/boards.py b/platformio/commands/boards.py index c116a8ba..572e39a3 100644 --- a/platformio/commands/boards.py +++ b/platformio/commands/boards.py @@ -48,15 +48,21 @@ def cli(query, installed, json_output): # pylint: disable=R0912 click.echo("Platform: ", nl=False) click.secho(platform, bold=True) click.echo("-" * terminal_width) - click.echo(BOARDLIST_TPL.format( - type=click.style("ID", fg="cyan"), mcu="MCU", - frequency="Frequency", flash="Flash", ram="RAM", name="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 sorted(pboards, key=lambda b: b['id']): if query: - search_data = "%s %s" % ( - board['id'], json.dumps(board).lower()) + search_data = "%s %s" % (board['id'], + json.dumps(board).lower()) if query.lower() not in search_data.lower(): continue @@ -71,11 +77,15 @@ def cli(query, installed, json_output): # pylint: disable=R0912 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=flash_size, ram=ram_size, name=board['name'])) + click.echo( + BOARDLIST_TPL.format( + type=click.style( + board['id'], fg="cyan"), + mcu=board['mcu'], + frequency="%dMhz" % (board['fcpu'] / 1000000), + flash=flash_size, + ram=ram_size, + name=board['name'])) def _get_boards(installed=False): diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index e9a92984..401b00ff 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -55,19 +55,37 @@ def validate_path(ctx, param, value): # pylint: disable=W0613 @click.argument("src", nargs=-1, callback=validate_path) @click.option("-l", "--lib", multiple=True, callback=validate_path) @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( + exists=True, + file_okay=False, + dir_okay=True, + writable=True, + resolve_path=True)) @click.option("--keep-build-dir", is_flag=True) -@click.option("--project-conf", - type=click.Path(exists=True, file_okay=True, dir_okay=False, - readable=True, resolve_path=True)) +@click.option( + "--project-conf", + type=click.Path( + exists=True, + file_okay=True, + dir_okay=False, + readable=True, + resolve_path=True)) @click.option("-v", "--verbose", is_flag=True) @click.pass_context -def cli(ctx, src, lib, exclude, board, # pylint: disable=R0913 - build_dir, keep_build_dir, project_conf, verbose): +def cli(ctx, # pylint: disable=R0913 + src, + lib, + exclude, + board, + build_dir, + keep_build_dir, + project_conf, + verbose): if not src: src = getenv("PLATFORMIO_CI_SRC", "").split(":") @@ -102,9 +120,8 @@ def cli(ctx, src, lib, exclude, board, # pylint: disable=R0913 finally: if not keep_build_dir: rmtree( - build_dir, onerror=lambda action, name, exc: - (chmod(name, stat.S_IWRITE), remove(name)) - ) + build_dir, + onerror=lambda action, name, exc: (chmod(name, stat.S_IWRITE), remove(name))) def _clean_dir(dirpath): @@ -113,10 +130,7 @@ def _clean_dir(dirpath): def _copy_contents(dst_dir, contents): - items = { - "dirs": set(), - "files": set() - } + items = {"dirs": set(), "files": set()} for path in contents: if isdir(path): diff --git a/platformio/commands/init.py b/platformio/commands/init.py index 6497f765..7d9fb2ed 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -37,24 +37,35 @@ def validate_boards(ctx, param, value): # pylint: disable=W0613 assert not unknown_boards return value except AssertionError: - raise click.BadParameter( - "%s. Please search for the board ID using " - "`platformio boards` command" % ", ".join(unknown_boards)) + raise click.BadParameter("%s. Please search for the board ID using " + "`platformio boards` command" % + ", ".join(unknown_boards)) @click.command("init", short_help="Initialize new PlatformIO based project") -@click.option("--project-dir", "-d", default=getcwd, - type=click.Path(exists=True, file_okay=False, dir_okay=True, - writable=True, resolve_path=True)) -@click.option("-b", "--board", multiple=True, metavar="ID", - callback=validate_boards) -@click.option("--ide", - type=click.Choice(ProjectGenerator.get_supported_ides())) +@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("--enable-auto-uploading", is_flag=True) @click.option("--env-prefix", default="") @click.pass_context -def cli(ctx, project_dir, board, ide, # pylint: disable=R0913 - enable_auto_uploading, env_prefix): +def cli(ctx, # pylint: disable=R0913 + project_dir, + board, + ide, + enable_auto_uploading, + env_prefix): if project_dir == getcwd(): click.secho("\nThe current working directory", fg="yellow", nl=False) @@ -63,18 +74,20 @@ def cli(ctx, project_dir, board, ide, # pylint: disable=R0913 "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" - ) + fg="yellow") click.echo("") click.echo("The next files/directories will be created in %s" % - click.style(project_dir, fg="cyan")) + click.style( + project_dir, fg="cyan")) click.echo("%s - Project Configuration File. |-> PLEASE EDIT ME <-|" % - click.style("platformio.ini", fg="cyan")) - click.echo("%s - Put your source files here" % - click.style("src", fg="cyan")) + click.style( + "platformio.ini", fg="cyan")) + click.echo("%s - Put your source files here" % click.style( + "src", fg="cyan")) click.echo("%s - Put here project specific (private) libraries" % - click.style("lib", fg="cyan")) + click.style( + "lib", fg="cyan")) if (app.get_setting("enable_prompts") and not click.confirm("Do you want to continue?")): @@ -83,10 +96,8 @@ def cli(ctx, project_dir, board, ide, # pylint: disable=R0913 init_base_project(project_dir) if board: - fill_project_envs( - ctx, project_dir, board, - enable_auto_uploading, env_prefix, ide is not None - ) + fill_project_envs(ctx, project_dir, board, enable_auto_uploading, + env_prefix, ide is not None) if ide: if not board: @@ -102,8 +113,7 @@ def cli(ctx, project_dir, board, ide, # pylint: disable=R0913 "However, the IDE features (code autocompletion, syntax " "linter) have been configured for the first board '%s' from " "your list '%s'." % (board[0], ", ".join(board)), - fg="yellow" - ) + fg="yellow") pg = ProjectGenerator(project_dir, ide, board[0]) pg.generate() @@ -116,8 +126,7 @@ def cli(ctx, project_dir, board, ide, # pylint: disable=R0913 "`platformio run --target clean` - clean project (remove compiled " "files)\n" "`platformio run --help` - additional information", - fg="green" - ) + fg="green") def get_first_board(project_dir): @@ -132,8 +141,9 @@ def get_first_board(project_dir): 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")) + copyfile( + join(util.get_source_dir(), "projectconftpl.ini"), + join(project_dir, "platformio.ini")) lib_dir = join(project_dir, "lib") src_dir = join(project_dir, "src") @@ -275,8 +285,8 @@ def init_cvs_ignore(project_dir): def fill_project_envs( # pylint: disable=too-many-arguments,too-many-locals - ctx, project_dir, board_ids, enable_auto_uploading, - env_prefix, force_download): + ctx, project_dir, board_ids, enable_auto_uploading, env_prefix, + force_download): installed_boards = PlatformManager().get_installed_boards() content = [] used_boards = [] @@ -291,8 +301,8 @@ def fill_project_envs( # pylint: disable=too-many-arguments,too-many-locals for id_ in board_ids: manifest = None - for boards in ( - installed_boards, PlatformManager.get_registered_boards()): + for boards in (installed_boards, + PlatformManager.get_registered_boards()): for b in boards: if b['id'] == id_: manifest = b @@ -329,10 +339,10 @@ def fill_project_envs( # pylint: disable=too-many-arguments,too-many-locals def _install_dependent_platforms(ctx, platforms): installed_platforms = [ - p['name'] for p in PlatformManager().get_installed()] + p['name'] for p in PlatformManager().get_installed() + ] if set(platforms) <= set(installed_platforms): return ctx.invoke( cli_platform_install, - platforms=list(set(platforms) - set(installed_platforms)) - ) + platforms=list(set(platforms) - set(installed_platforms))) diff --git a/platformio/commands/run.py b/platformio/commands/run.py index c662e012..9f4043e0 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -33,14 +33,26 @@ from platformio.managers.platform import PlatformFactory @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=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("-v", "--verbose", is_flag=True) @click.option("--disable-auto-clean", is_flag=True) @click.pass_context -def cli(ctx, environment, target, upload_port, # pylint: disable=R0913,R0914 - project_dir, verbose, disable_auto_clean): +def cli(ctx, # pylint: disable=R0913,R0914 + environment, + target, + upload_port, + project_dir, + verbose, + disable_auto_clean): assert check_project_envs(project_dir, environment) with util.cd(project_dir): # clean obsolete .pioenvs dir @@ -59,7 +71,8 @@ def cli(ctx, environment, target, upload_port, # pylint: disable=R0913,R0914 if config.has_option("platformio", "env_default"): env_default = [ e.strip() - for e in config.get("platformio", "env_default").split(",")] + for e in config.get("platformio", "env_default").split(",") + ] results = [] for section in config.sections(): @@ -71,9 +84,10 @@ def cli(ctx, environment, target, upload_port, # pylint: disable=R0913,R0914 raise exception.InvalidEnvName(section) envname = section[4:] - if ((environment and envname not in environment) or - (not environment and env_default and - envname not in env_default)): + skipenv = any([environment and envname not in environment, + not environment and env_default and + envname not in env_default]) + if skipenv: # echo("Skipped %s environment" % style(envname, fg="yellow")) continue @@ -86,8 +100,8 @@ def cli(ctx, environment, target, upload_port, # pylint: disable=R0913,R0914 if "piotest" not in options and "piotest" in ctx.meta: options['piotest'] = ctx.meta['piotest'] - ep = EnvironmentProcessor( - ctx, envname, options, target, upload_port, verbose) + ep = EnvironmentProcessor(ctx, envname, options, target, + upload_port, verbose) results.append(ep.process()) if not all(results): @@ -96,10 +110,7 @@ def cli(ctx, environment, target, upload_port, # pylint: disable=R0913,R0914 class EnvironmentProcessor(object): - REMAPED_OPTIONS = { - "FRAMEWORK": "PIOFRAMEWORK", - "PLATFORM": "PIOPLATFORM" - } + REMAPED_OPTIONS = {"FRAMEWORK": "PIOFRAMEWORK", "PLATFORM": "PIOPLATFORM"} RENAMED_OPTIONS = { "INSTALL_LIBS": "LIB_INSTALL", @@ -107,8 +118,13 @@ class EnvironmentProcessor(object): "LIB_USE": "LIB_FORCE" } - def __init__(self, cmd_ctx, name, options, # pylint: disable=R0913 - targets, upload_port, verbose): + def __init__(self, # pylint: disable=R0913 + cmd_ctx, + name, + options, + targets, + upload_port, + verbose): self.cmd_ctx = cmd_ctx self.name = name self.options = self._validate_options(options) @@ -121,21 +137,21 @@ class EnvironmentProcessor(object): start_time = time() click.echo("[%s] Processing %s (%s)" % ( - datetime.now().strftime("%c"), - click.style(self.name, fg="cyan", bold=True), - ", ".join(["%s: %s" % (k, v) for k, v in self.options.iteritems()]) - )) + datetime.now().strftime("%c"), click.style( + self.name, fg="cyan", bold=True), ", ".join( + ["%s: %s" % (k, v) for k, v in self.options.iteritems()]))) click.secho("-" * terminal_width, bold=True) result = self._run() is_error = result['returncode'] != 0 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) + 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 @@ -148,10 +164,8 @@ class EnvironmentProcessor(object): click.secho( "Warning! `%s` option is deprecated and will be " "removed in the next release! Please use " - "`%s` instead." % ( - k, self.RENAMED_OPTIONS[_k].lower()), - fg="yellow" - ) + "`%s` instead." % (k, self.RENAMED_OPTIONS[_k].lower()), + fg="yellow") k = self.RENAMED_OPTIONS[_k].lower() result[k] = v return result @@ -249,12 +263,10 @@ def check_project_envs(project_dir, environments): if not config.sections(): raise exception.ProjectEnvsNotAvailable() - known = set([s[4:] for s in config.sections() - if s.startswith("env:")]) + 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)) + raise exception.UnknownEnvNames(", ".join(unknown), ", ".join(known)) return True diff --git a/platformio/commands/serialports.py b/platformio/commands/serialports.py index 4371b15c..a42e59f6 100644 --- a/platformio/commands/serialports.py +++ b/platformio/commands/serialports.py @@ -46,41 +46,72 @@ def serialports_list(json_output): if int(PYSERIAL_VERSION[0]) == 3: + @cli.command("monitor", short_help="Monitor Serial port") @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.Choice(["0", "1"]), - help="Set initial RTS line state") - @click.option("--dtr", default=None, type=click.Choice(["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("--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=29, - help="ASCII code of special character that is used to exit " - "the application, default=29 (DEC)") - @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( + "--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.Choice(["0", "1"]), + help="Set initial RTS line state") + @click.option( + "--dtr", + default=None, + type=click.Choice(["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( + "--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=29, + help="ASCII code of special character that is used to exit " + "the application, default=29 (DEC)") + @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") def serialports_monitor(**kwargs): if not kwargs['port']: for item in get_serialports(): @@ -107,47 +138,78 @@ if int(PYSERIAL_VERSION[0]) == 3: default_port=kwargs['port'], default_baudrate=kwargs['baud'], default_rts=kwargs['rts'], - default_dtr=kwargs['dtr'] - ) + default_dtr=kwargs['dtr']) except Exception as e: # pylint: disable=W0702 raise MinitermException(e) else: + @cli.command("monitor", short_help="Monitor Serial port") @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.Choice(["0", "1"]), - help="Set initial RTS line state, default=0") - @click.option("--dtr", default=None, type=click.Choice(["0", "1"]), - help="Set initial DTR line state, default=0") - @click.option("--echo", is_flag=True, - help="Enable local echo, default=Off") - @click.option("--cr", is_flag=True, - help="Do not send CR+LF, send CR only, default=Off") - @click.option("--lf", is_flag=True, - help="Do not send CR+LF, send LF only, default=Off") - @click.option("--debug", "-d", count=True, - help="""Debug received data (escape non-printable chars) + @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.Choice(["0", "1"]), + help="Set initial RTS line state, default=0") + @click.option( + "--dtr", + default=None, + type=click.Choice(["0", "1"]), + help="Set initial DTR line state, default=0") + @click.option( + "--echo", is_flag=True, help="Enable local echo, default=Off") + @click.option( + "--cr", + is_flag=True, + help="Do not send CR+LF, send CR only, default=Off") + @click.option( + "--lf", + is_flag=True, + help="Do not send CR+LF, send LF only, default=Off") + @click.option( + "--debug", + "-d", + count=True, + help="""Debug received data (escape non-printable chars) # --debug can be given multiple times: # 0: just print what is received # 1: escape non-printable characters, do newlines as unusual # 2: escape non-printable characters, newlines too # 3: hex dump everything""") - @click.option("--exit-char", type=int, default=29, - help="ASCII code of special character that is used to exit " - "the application, default=29 (DEC)") - @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( + "--exit-char", + type=int, + default=29, + help="ASCII code of special character that is used to exit " + "the application, default=29 (DEC)") + @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") def serialports_monitor(**kwargs): sys.argv = app.get_session_var("command_ctx").args[1:] diff --git a/platformio/commands/settings.py b/platformio/commands/settings.py index 34e460d3..478ed527 100644 --- a/platformio/commands/settings.py +++ b/platformio/commands/settings.py @@ -29,12 +29,14 @@ def settings_get(name): list_tpl = "{name:<40} {value:<35} {description}" terminal_width, _ = click.get_terminal_size() - 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( + 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()): @@ -55,11 +57,12 @@ def settings_get(name): else: _value_str += click.style(" ", fg="yellow") - click.echo(list_tpl.format( - name=click.style(_name, fg="cyan"), - value=_value_str, - description=_data['description'] - )) + click.echo( + list_tpl.format( + name=click.style( + _name, fg="cyan"), + value=_value_str, + description=_data['description'])) @cli.command("set", short_help="Set new value for the setting") diff --git a/platformio/commands/test.py b/platformio/commands/test.py index 3b16d7a6..3f9ae9c3 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -32,9 +32,16 @@ from platformio.managers.platform import PlatformFactory @click.option("--environment", "-e", multiple=True, metavar="") @click.option("--skip", multiple=True, metavar="") @click.option("--upload-port", metavar="") -@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("--verbose", "-v", is_flag=True) @click.pass_context def cli(ctx, environment, skip, upload_port, project_dir, verbose): @@ -85,16 +92,17 @@ def cli(ctx, environment, skip, upload_port, project_dir, verbose): elif status is None: status_str = click.style("IGNORED", fg="yellow") - click.echo("test:%s/env:%s\t%s" % ( - click.style(testname, fg="yellow"), - click.style(envname, fg="cyan"), - status_str), err=status is False) + click.echo( + "test:%s/env:%s\t%s" % (click.style( + testname, fg="yellow"), click.style( + envname, fg="cyan"), status_str), + err=status is False) - print_header("[%s] Took %.2f seconds" % ( - (click.style("PASSED", fg="green", bold=True) if passed - else click.style("FAILED", fg="red", bold=True)), - time() - start_time - ), is_error=not passed) + print_header( + "[%s] Took %.2f seconds" % ((click.style( + "PASSED", fg="green", bold=True) if passed else click.style( + "FAILED", fg="red", bold=True)), time() - start_time), + is_error=not passed) if not passed: raise exception.ReturnErrorCode() @@ -122,41 +130,42 @@ class TestProcessor(object): return self._run_hardware_test() def _progress(self, text, is_error=False): - print_header("[test::%s] %s" % ( - click.style(self.test_name, fg="yellow", bold=True), - text - ), is_error=is_error) + print_header( + "[test::%s] %s" % (click.style( + self.test_name, fg="yellow", bold=True), text), + is_error=is_error) click.echo() def _build_or_upload(self, target): if self.test_name != "*": self.cmd_ctx.meta['piotest'] = self.test_name return self.cmd_ctx.invoke( - cmd_run, project_dir=self.options['project_dir'], + cmd_run, + project_dir=self.options['project_dir'], upload_port=self.options['upload_port'], verbose=self.options['verbose'], environment=[self.env_name], - target=target - ) + target=target) def _run_hardware_test(self): click.echo("If you don't see any output for the first 10 secs, " "please reset board (press reset button)") click.echo() - ser = serial.Serial(self.get_serial_port(), self.SERIAL_BAUDRATE, - timeout=self.SERIAL_TIMEOUT) + ser = serial.Serial( + self.get_serial_port(), + self.SERIAL_BAUDRATE, + timeout=self.SERIAL_TIMEOUT) passed = True while True: line = ser.readline().strip() if not line: continue if line.endswith(":PASS"): - click.echo("%s\t%s" % ( - line[:-5], click.style("PASSED", fg="green"))) + click.echo("%s\t%s" % (line[:-5], click.style( + "PASSED", fg="green"))) elif ":FAIL:" in line: passed = False - click.echo("%s\t%s" % ( - line, click.style("FAILED", fg="red"))) + click.echo("%s\t%s" % (line, click.style("FAILED", fg="red"))) else: click.echo(line) if all([l in line for l in ("Tests", "Failures", "Ignored")]): diff --git a/platformio/commands/update.py b/platformio/commands/update.py index d97ae99d..422ac3d9 100644 --- a/platformio/commands/update.py +++ b/platformio/commands/update.py @@ -19,8 +19,8 @@ from platformio.commands.platform import platform_update as cmd_platform_update from platformio.managers.lib import LibraryManager -@click.command("update", - short_help="Update installed Platforms, Packages and Libraries") +@click.command( + "update", short_help="Update installed Platforms, Packages and Libraries") @click.option( "-c", "--only-check", diff --git a/platformio/commands/upgrade.py b/platformio/commands/upgrade.py index ddac25c1..9a8f8dbf 100644 --- a/platformio/commands/upgrade.py +++ b/platformio/commands/upgrade.py @@ -22,26 +22,22 @@ import requests from platformio import VERSION, __version__, exception, util -@click.command("upgrade", - short_help="Upgrade PlatformIO to the latest version") +@click.command( + "upgrade", short_help="Upgrade PlatformIO to the latest version") def cli(): latest = get_latest_version() if __version__ == latest: return click.secho( "You're up-to-date!\nPlatformIO %s is currently the " - "newest version available." % __version__, fg="green" - ) + "newest version available." % __version__, + fg="green") else: - click.secho("Please wait while upgrading PlatformIO ...", - fg="yellow") + 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/archive/develop.zip" - if to_develop else "platformio"], - ["platformio", "--version"] - ) + cmds = (["pip", "install", "--upgrade", + "https://github.com/platformio/platformio/archive/develop.zip" + if to_develop else "platformio"], ["platformio", "--version"]) cmd = None r = None @@ -63,21 +59,19 @@ def cli(): actual_version = r['out'].strip().split("version", 1)[1].strip() click.secho( "PlatformIO has been successfully upgraded to %s" % - actual_version, fg="green") + actual_version, + fg="green") click.echo("Release notes: ", nl=False) - click.secho("http://docs.platformio.org/en/stable/history.html", - fg="cyan") + click.secho( + "http://docs.platformio.org/en/stable/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" - ) + 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(""" + click.secho( + """ ----------------- Permission denied ----------------- @@ -86,11 +80,13 @@ You need the `sudo` permission to install Python packages. Try > sudo pip install -U platformio WARNING! Don't use `sudo` for the rest PlatformIO commands. -""", fg="yellow", err=True) +""", + fg="yellow", + err=True) raise exception.ReturnErrorCode() else: - raise exception.UpgradeError( - "\n".join([str(cmd), r['out'], r['err']])) + raise exception.UpgradeError("\n".join([str(cmd), r['out'], r[ + 'err']])) def get_latest_version(): @@ -107,11 +103,9 @@ def get_latest_version(): def get_develop_latest_version(): version = None - r = requests.get( - "https://raw.githubusercontent.com/platformio/platformio" - "/develop/platformio/__init__.py", - headers=util.get_request_defheaders() - ) + r = requests.get("https://raw.githubusercontent.com/platformio/platformio" + "/develop/platformio/__init__.py", + headers=util.get_request_defheaders()) r.raise_for_status() for line in r.text.split("\n"): line = line.strip() @@ -129,9 +123,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.python.org/pypi/platformio/json", + headers=util.get_request_defheaders()) r.raise_for_status() return r.json()['info']['version'] diff --git a/platformio/downloader.py b/platformio/downloader.py index bce15dea..e91f75db 100644 --- a/platformio/downloader.py +++ b/platformio/downloader.py @@ -41,7 +41,8 @@ class FileDownloader(object): self._request = None # make connection - self._request = requests.get(url, stream=True, + self._request = requests.get(url, + stream=True, headers=util.get_request_defheaders()) if self._request.status_code != 200: raise FDUnrecognizedStatusCode(self._request.status_code, url) diff --git a/platformio/ide/projectgenerator.py b/platformio/ide/projectgenerator.py index 093508f7..762dfbc4 100644 --- a/platformio/ide/projectgenerator.py +++ b/platformio/ide/projectgenerator.py @@ -59,19 +59,14 @@ class ProjectGenerator(object): @util.memoized def get_project_build_data(self): - data = { - "defines": [], - "includes": [], - "cxx_path": None - } + data = {"defines": [], "includes": [], "cxx_path": None} envdata = self.get_project_env() if "env_name" not in envdata: return data cmd = [ normpath(sys.executable), "-m", - "platformio" + ( - ".__main__" if sys.version_info < (2, 7, 0) else ""), - "-f" + "platformio" + (".__main__" + if sys.version_info < (2, 7, 0) else ""), "-f" ] if app.get_session_var("caller_id"): cmd.extend(["-c", app.get_session_var("caller_id")]) @@ -80,8 +75,8 @@ class ProjectGenerator(object): result = util.exec_command(cmd) if result['returncode'] != 0 or '"includes":' not in result['out']: - raise exception.PlatformioException( - "\n".join([result['out'], result['err']])) + raise exception.PlatformioException("\n".join([result['out'], + result['err']])) output = result['out'] start_index = output.index('{"') @@ -125,8 +120,7 @@ class ProjectGenerator(object): file_name = basename(tpl_path)[:-4] self._merge_contents( join(dst_dir, file_name), - self._render_tpl(tpl_path).encode("utf8") - ) + self._render_tpl(tpl_path).encode("utf8")) def _render_tpl(self, tpl_path): content = "" @@ -161,13 +155,13 @@ class ProjectGenerator(object): "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")), + "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) + return (re.sub(r"[\\]+", '\\' * 4, path) + if "windows" in util.get_systype() else path) diff --git a/platformio/maintenance.py b/platformio/maintenance.py index 3fc980ac..0f959a23 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -56,8 +56,10 @@ def on_platformio_end(ctx, result): # pylint: disable=W0613 check_internal_updates(ctx, "platforms") check_internal_updates(ctx, "libraries") except (exception.GetLatestVersionError, exception.APIRequestError): - click.secho("Failed to check for PlatformIO upgrades. " - "Please check your Internet connection.", fg="red") + click.secho( + "Failed to check for PlatformIO upgrades. " + "Please check your Internet connection.", + fg="red") def on_platformio_exception(e): @@ -100,8 +102,7 @@ class Upgrader(object): continue os.remove(join(boards_dir, item)) for key, value in data.items(): - with open(join(boards_dir, "%s.json" % key), - "w") as f: + with open(join(boards_dir, "%s.json" % key), "w") as f: json.dump(value, f, sort_keys=True, indent=2) # re-install PlatformIO 2.0 development platforms @@ -120,8 +121,7 @@ def after_upgrade(ctx): if last_version == "0.0.0": app.set_state_item("last_version", __version__) else: - click.secho("Please wait while upgrading PlatformIO ...", - fg="yellow") + click.secho("Please wait while upgrading PlatformIO ...", fg="yellow") u = Upgrader(last_version, __version__) if u.run(ctx): @@ -132,11 +132,15 @@ def after_upgrade(ctx): for manifest in pm.get_installed(): pm.update(manifest['name'], "^" + manifest['version']) - click.secho("PlatformIO has been successfully upgraded to %s!\n" % - __version__, fg="green") + click.secho( + "PlatformIO has been successfully upgraded to %s!\n" % + __version__, + fg="green") - telemetry.on_event(category="Auto", action="Upgrade", - label="%s > %s" % (last_version, __version__)) + telemetry.on_event( + category="Auto", + action="Upgrade", + label="%s > %s" % (last_version, __version__)) else: raise exception.UpgradeError("Auto upgrading...") click.echo("") @@ -144,29 +148,24 @@ def after_upgrade(ctx): # PlatformIO banner terminal_width, _ = click.get_terminal_size() click.echo("*" * terminal_width) - click.echo("If you like %s, please:" % ( - click.style("PlatformIO", fg="cyan") - )) - click.echo( - "- %s us on Twitter to stay up-to-date " - "on the latest project news > %s" % - (click.style("follow", fg="cyan"), - click.style("https://twitter.com/PlatformIO_Org", fg="cyan")) - ) - click.echo("- %s it on GitHub > %s" % ( - click.style("star", fg="cyan"), - click.style("https://github.com/platformio/platformio", fg="cyan") - )) + click.echo("If you like %s, please:" % (click.style( + "PlatformIO", fg="cyan"))) + click.echo("- %s us on Twitter to stay up-to-date " + "on the latest project news > %s" % (click.style( + "follow", fg="cyan"), click.style( + "https://twitter.com/PlatformIO_Org", fg="cyan"))) + click.echo("- %s it on GitHub > %s" % (click.style( + "star", fg="cyan"), click.style( + "https://github.com/platformio/platformio", fg="cyan"))) if not getenv("PLATFORMIO_IDE"): - click.echo("- %s PlatformIO IDE for IoT development > %s" % ( - click.style("try", fg="cyan"), - click.style("http://platformio.org/platformio-ide", fg="cyan") - )) + click.echo("- %s PlatformIO IDE for IoT development > %s" % + (click.style( + "try", fg="cyan"), click.style( + "http://platformio.org/platformio-ide", fg="cyan"))) if not util.is_ci(): - click.echo("- %s to keep PlatformIO alive! > %s" % ( - click.style("donate", fg="cyan"), - click.style("http://platformio.org/donate", fg="cyan") - )) + click.echo("- %s to keep PlatformIO alive! > %s" % (click.style( + "donate", fg="cyan"), click.style( + "http://platformio.org/donate", fg="cyan"))) click.echo("*" * terminal_width) click.echo("") @@ -191,12 +190,14 @@ def check_platformio_upgrade(): click.echo("") click.echo("*" * terminal_width) - click.secho("There is a new version %s of PlatformIO available.\n" - "Please upgrade it via `" % latest_version, - fg="yellow", nl=False) + click.secho( + "There is a new version %s of PlatformIO available.\n" + "Please upgrade it via `" % latest_version, + fg="yellow", + nl=False) if getenv("PLATFORMIO_IDE"): - click.secho("PlatformIO IDE Menu: Upgrade PlatformIO", - fg="cyan", nl=False) + click.secho( + "PlatformIO IDE Menu: Upgrade PlatformIO", fg="cyan", nl=False) click.secho("`.", fg="yellow") elif join("Cellar", "platformio") in util.get_source_dir(): click.secho("brew update && brew upgrade", fg="cyan", nl=False) @@ -235,20 +236,29 @@ def check_internal_updates(ctx, what): click.echo("") click.echo("*" * terminal_width) - click.secho("There are the new updates for %s (%s)" % - (what, ", ".join(outdated_items)), fg="yellow") + click.secho( + "There are the new updates for %s (%s)" % + (what, ", ".join(outdated_items)), + fg="yellow") if not app.get_setting("auto_update_" + what): click.secho("Please update them via ", fg="yellow", nl=False) - click.secho("`platformio %s update`" % - ("lib --global" if what == "libraries" else "platform"), - fg="cyan", nl=False) + click.secho( + "`platformio %s update`" % + ("lib --global" if what == "libraries" else "platform"), + fg="cyan", + nl=False) click.secho(" command.\n", fg="yellow") - click.secho("If you want to manually check for the new versions " - "without updating, please use ", fg="yellow", nl=False) - click.secho("`platformio %s update --only-check`" % - ("lib --global" if what == "libraries" else "platform"), - fg="cyan", nl=False) + click.secho( + "If you want to manually check for the new versions " + "without updating, please use ", + fg="yellow", + nl=False) + click.secho( + "`platformio %s update --only-check`" % + ("lib --global" if what == "libraries" else "platform"), + fg="cyan", + nl=False) click.secho(" command.", fg="yellow") else: click.secho("Please wait while updating %s ..." % what, fg="yellow") diff --git a/platformio/telemetry.py b/platformio/telemetry.py index f7c06102..964cc707 100644 --- a/platformio/telemetry.py +++ b/platformio/telemetry.py @@ -210,8 +210,7 @@ class MPDataPusher(object): "https://ssl.google-analytics.com/collect", data=data, headers=util.get_request_defheaders(), - timeout=1 - ) + timeout=1) r.raise_for_status() return True except: # pylint: disable=W0702 @@ -233,11 +232,7 @@ def on_command(): def measure_ci(): - event = { - "category": "CI", - "action": "NoName", - "label": None - } + event = {"category": "CI", "action": "NoName", "label": None} envmap = { "APPVEYOR": {"label": getenv("APPVEYOR_REPO_NAME")}, @@ -258,11 +253,7 @@ def measure_ci(): def measure_caller(calller_id): calller_id = str(calller_id)[:20].lower() - event = { - "category": "Caller", - "action": "Misc", - "label": calller_id - } + event = {"category": "Caller", "action": "Misc", "label": calller_id} if calller_id in (["atom", "vim"] + ProjectGenerator.get_supported_ides()): event['action'] = "IDE" on_event(**event) diff --git a/platformio/unpacker.py b/platformio/unpacker.py index 1011fe4c..67ca78a7 100644 --- a/platformio/unpacker.py +++ b/platformio/unpacker.py @@ -64,8 +64,7 @@ class ZIPArchive(ArchiveBase): def preserve_mtime(item, dest_dir): util.change_filemtime( join(dest_dir, item.filename), - mktime(list(item.date_time) + [0] * 3) - ) + mktime(list(item.date_time) + [0] * 3)) def get_items(self): return self._afo.infolist() @@ -97,8 +96,8 @@ class FileUnpacker(object): for item in self._unpacker.get_items(): self._unpacker.extract_item(item, self._dest_dir) else: - with click.progressbar(self._unpacker.get_items(), - label="Unpacking") as pb: + items = self._unpacker.get_items() + with click.progressbar(items, label="Unpacking") as pb: for item in pb: self._unpacker.extract_item(item, self._dest_dir) return True diff --git a/platformio/util.py b/platformio/util.py index 8a389717..eeb02caf 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -81,7 +81,6 @@ class cd(object): class memoized(object): - ''' Decorator. Caches a function's return value each time it is called. If called later with the same arguments, the cached value is returned @@ -122,6 +121,7 @@ def singleton(cls): if cls not in _instances: _instances[cls] = cls(*args, **kwargs) return _instances[cls] + return get_instance @@ -162,10 +162,8 @@ def _get_projconf_option_dir(name, default=None): def get_home_dir(): - home_dir = _get_projconf_option_dir( - "home_dir", - join(expanduser("~"), ".platformio") - ) + home_dir = _get_projconf_option_dir("home_dir", + join(expanduser("~"), ".platformio")) if "windows" in get_systype(): try: @@ -234,10 +232,8 @@ URL=http://docs.platformio.org/en/stable/projectconf.html#envs-dir def get_projectdata_dir(): - return _get_projconf_option_dir( - "data_dir", - join(get_project_dir(), "data") - ) + return _get_projconf_option_dir("data_dir", + join(get_project_dir(), "data")) def load_project_config(project_dir=None): @@ -259,17 +255,12 @@ def is_ci(): def exec_command(*args, **kwargs): - result = { - "out": None, - "err": None, - "returncode": None - } + result = {"out": None, "err": None, "returncode": None} default = dict( stdout=subprocess.PIPE, stderr=subprocess.PIPE, - shell=system() == "Windows" - ) + shell=system() == "Windows") default.update(kwargs) kwargs = default @@ -344,9 +335,8 @@ def get_logicaldisks(): def get_request_defheaders(): import requests - return {"User-Agent": "PlatformIO/%s CI/%d %s" % ( - __version__, int(is_ci()), requests.utils.default_user_agent() - )} + data = (__version__, int(is_ci()), requests.utils.default_user_agent()) + return {"User-Agent": "PlatformIO/%s CI/%d %s" % data} @memoized @@ -364,7 +354,7 @@ def get_api_result(path, params=None, data=None, skipdns=False): url = __apiurl__ if skipdns: url = "http://%s" % __apiip__ - headers['host'] = __apiurl__[__apiurl__.index("://")+3:] + headers['host'] = __apiurl__[__apiurl__.index("://") + 3:] try: if data: @@ -390,8 +380,8 @@ def get_api_result(path, params=None, data=None, skipdns=False): "Could not connect to PlatformIO Registry Service. " "Please try later.") except ValueError: - raise exception.APIRequestError( - "Invalid response: %s" % r.text.encode("utf-8")) + raise exception.APIRequestError("Invalid response: %s" % + r.text.encode("utf-8")) finally: if r: r.close() @@ -401,8 +391,8 @@ def get_api_result(path, params=None, data=None, skipdns=False): @memoized def _lookup_frameworks(): frameworks = {} - frameworks_path = join( - get_source_dir(), "builder", "scripts", "frameworks") + frameworks_path = join(get_source_dir(), "builder", "scripts", + "frameworks") frameworks_list = [f[:-3] for f in os.listdir(frameworks_path) if not f.startswith("__") and f.endswith(".py")] @@ -412,8 +402,8 @@ def _lookup_frameworks(): fcontent = f.read() assert '"""' in fcontent _doc_start = fcontent.index('"""') + 3 - fdoc = fcontent[ - _doc_start:fcontent.index('"""', _doc_start)].strip() + fdoc = fcontent[_doc_start:fcontent.index('"""', + _doc_start)].strip() doclines = [l.strip() for l in fdoc.splitlines() if l.strip()] frameworks[_type] = { "name": doclines[0], @@ -446,8 +436,7 @@ def where_is_program(program, envpath=None): try: result = exec_command( ["where" if "windows" in get_systype() else "which", program], - env=env - ) + env=env) if result['returncode'] == 0 and isfile(result['out'].strip()): return result['out'].strip() except OSError: diff --git a/setup.py b/setup.py index 4c309883..29a759d9 100644 --- a/setup.py +++ b/setup.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - from setuptools import find_packages, setup from platformio import (__author__, __description__, __email__, __license__, @@ -29,9 +27,6 @@ install_requires = [ "pyserial<4" ] -if sys.version_info < (2, 7, 0): - install_requires[-1] = "pyserial<3" - setup( name=__title__, version=__version__, From 941c7ffd07115b219bb0c95fd20fb576f2d8159d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 3 Aug 2016 23:40:04 +0300 Subject: [PATCH 106/284] Remove Python 2.6 code --- platformio/__init__.py | 2 +- platformio/commands/upgrade.py | 2 -- platformio/ide/projectgenerator.py | 6 +----- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 469a4e79..e06d38ef 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev18") +VERSION = (3, 0, "0.dev19") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/commands/upgrade.py b/platformio/commands/upgrade.py index 9a8f8dbf..93f82e6c 100644 --- a/platformio/commands/upgrade.py +++ b/platformio/commands/upgrade.py @@ -43,8 +43,6 @@ def cli(): r = None try: for cmd in cmds: - if sys.version_info < (2, 7, 0): - cmd[0] += ".__main__" cmd = [os.path.normpath(sys.executable), "-m"] + cmd r = None r = util.exec_command(cmd) diff --git a/platformio/ide/projectgenerator.py b/platformio/ide/projectgenerator.py index 762dfbc4..ecd2f868 100644 --- a/platformio/ide/projectgenerator.py +++ b/platformio/ide/projectgenerator.py @@ -63,11 +63,7 @@ class ProjectGenerator(object): envdata = self.get_project_env() if "env_name" not in envdata: return data - cmd = [ - normpath(sys.executable), "-m", - "platformio" + (".__main__" - if sys.version_info < (2, 7, 0) else ""), "-f" - ] + cmd = [normpath(sys.executable), "-m", "platformio", "-f"] if app.get_session_var("caller_id"): cmd.extend(["-c", app.get_session_var("caller_id")]) cmd.extend(["run", "-t", "idedata", "-e", envdata['env_name']]) From d27c31a389899b966ee1968313195cba77dd7ce0 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 4 Aug 2016 00:55:07 +0300 Subject: [PATCH 107/284] Formatter: allow multiline lambdas --- .style.yapf | 3 ++- platformio/commands/ci.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.style.yapf b/.style.yapf index 0a658196..7bc85964 100644 --- a/.style.yapf +++ b/.style.yapf @@ -1,2 +1,3 @@ [style] -blank_line_before_nested_class_or_def = true \ No newline at end of file +blank_line_before_nested_class_or_def = true +allow_multiline_lambdas = true diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index 401b00ff..886c9506 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -121,7 +121,8 @@ def cli(ctx, # pylint: disable=R0913 if not keep_build_dir: rmtree( build_dir, - onerror=lambda action, name, exc: (chmod(name, stat.S_IWRITE), remove(name))) + onerror=lambda action, name, exc: (chmod(name, stat.S_IWRITE), + remove(name))) def _clean_dir(dirpath): From 179a9717707ebc5c7ab8f92b365e846e96d7e2c0 Mon Sep 17 00:00:00 2001 From: Valerii Koval Date: Thu, 4 Aug 2016 12:00:38 +0300 Subject: [PATCH 108/284] Fix OpenOCD upload command for atmelsam // Issue #732 --- platformio/builder/scripts/atmelsam.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/builder/scripts/atmelsam.py b/platformio/builder/scripts/atmelsam.py index d4b25a46..7b3b9412 100644 --- a/platformio/builder/scripts/atmelsam.py +++ b/platformio/builder/scripts/atmelsam.py @@ -146,7 +146,7 @@ if upload_protocol == "openocd": "-c", "\"telnet_port", "disabled;", "program", "{{$SOURCES}}", "verify", "reset", - "%s;" % user_code_section if user_code_section else "", + "%s;" % (user_code_section if user_code_section else ""), "shutdown\"" ] ) From b714fb1be005f49d12904560880a2208149538d2 Mon Sep 17 00:00:00 2001 From: Valeriy Koval Date: Thu, 4 Aug 2016 18:37:52 +0300 Subject: [PATCH 109/284] Update OpenOCD uploading flags // Issue #732 --- platformio/builder/scripts/atmelsam.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/platformio/builder/scripts/atmelsam.py b/platformio/builder/scripts/atmelsam.py index 7b3b9412..0901364e 100644 --- a/platformio/builder/scripts/atmelsam.py +++ b/platformio/builder/scripts/atmelsam.py @@ -121,12 +121,11 @@ if upload_protocol == "openocd": env.Replace( UPLOADER=join("$PIOPACKAGES_DIR", "tool-openocd", "bin", "openocd"), UPLOADERFLAGS=[ - "-d2", "-f", join(BOARD_OPTIONS.get("debug", {}).get("openocdcfg", "")), - "-s", join("$PIOPACKAGES_DIR", "tool-openocd", - "share", "openocd", "scripts"), - "-s", join("$PIOPACKAGES_DIR", "tool-openocd", - "share", "openocd", "scripts", "board") + "-s", '"%s"' % join("$PIOPACKAGES_DIR", "tool-openocd", + "share", "openocd", "scripts"), + "-s", '"%s"' % join("$PIOPACKAGES_DIR", "tool-openocd", + "share", "openocd", "scripts", "board") ], UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS' @@ -135,19 +134,17 @@ if upload_protocol == "openocd": if "zero" in env.subst("$BOARD"): env.Append( UPLOADERFLAGS=[ - "-s", join("$PLATFORMFW_DIR", "variants", - "${BOARD_OPTIONS['build']['variant']}", - "openocd_scripts") + "-s", '"%s"' % join("$PLATFORMFW_DIR", "variants", + "${BOARD_OPTIONS['build']['variant']}", + "openocd_scripts") ] ) env.Append( UPLOADERFLAGS=[ - "-c", "\"telnet_port", "disabled;", - "program", "{{$SOURCES}}", - "verify", "reset", - "%s;" % (user_code_section if user_code_section else ""), - "shutdown\"" + "-c", ("telnet_port disabled; program {{$SOURCES}} " + "verify reset %s; shutdown" % ( + user_code_section if user_code_section else "")) ] ) From dad8f9d80e5be18ae0768c6f1aeeecf648ef6fcd Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 5 Aug 2016 13:10:27 +0300 Subject: [PATCH 110/284] Show valid text when "Checking" packages version --- platformio/managers/package.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 0b57520d..21769fce 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -492,8 +492,10 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): manifest = self.load_manifest(installed_dir) click.echo( - "Updating %s @ %s: \t" % (click.style( - manifest['name'], fg="cyan"), manifest['version']), + "%s %s @ %s: \t" % ("Checking" + if only_check else "Updating", click.style( + manifest['name'], fg="cyan"), + manifest['version']), nl=False) manifest_path = self.get_manifest_path(installed_dir) if manifest_path.endswith(self.VCS_MANIFEST_NAME): From e9ed55b6e91298d47b9a8e69ecc45ec636fe12fc Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 5 Aug 2016 13:51:28 +0300 Subject: [PATCH 111/284] Improve updating of development platforms --- Makefile | 3 +-- platformio/__init__.py | 2 +- platformio/managers/package.py | 1 + platformio/managers/platform.py | 16 +++++++++------- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 2117e072..51b3d166 100644 --- a/Makefile +++ b/Makefile @@ -5,12 +5,11 @@ lint: isort: isort -rc ./platformio isort -rc ./tests - isort -rc ./scripts yapf: yapf --recursive --in-place platformio/ -before-commit: isort yapf pylint +before-commit: isort yapf lint clean-docs: rm -rf docs/_build diff --git a/platformio/__init__.py b/platformio/__init__.py index e06d38ef..8948d92b 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev19") +VERSION = (3, 0, "0.dev20") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 21769fce..3f111d9d 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -522,6 +522,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): click.echo("[%s]" % (click.style("Out-of-date", fg="red"))) if only_check: return + self.uninstall(name, manifest['version'], trigger_event=False) self.install(name, latest_version, trigger_event=False) telemetry.on_event( diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index fbfc0af3..aae99081 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -43,7 +43,8 @@ class PlatformManager(BasePkgManager): return "platform.json" def install(self, # pylint: disable=too-many-arguments,arguments-differ - name, requirements=None, with_packages=None, + name, requirements=None, quiet=False, + trigger_event=True, with_packages=None, without_packages=None, skip_default_package=False): platform_dir = BasePkgManager.install(self, name, requirements) p = PlatformFactory.newPlatform(self.get_manifest_path(platform_dir)) @@ -52,12 +53,14 @@ class PlatformManager(BasePkgManager): self.cleanup_packages(p.packages.keys()) return True - def uninstall( # pylint: disable=arguments-differ - self, name, requirements=None): + def uninstall(self, name, requirements=None, trigger_event=True): name, requirements, _ = self.parse_pkg_name(name, requirements) p = PlatformFactory.newPlatform(name, requirements) BasePkgManager.uninstall(self, name, requirements) - self.cleanup_packages(p.packages.keys()) + # trigger event is disabled when upgrading operation + # don't cleanup packages, "install" will do that + if trigger_event: + self.cleanup_packages(p.packages.keys()) return True def update(self, # pylint: disable=arguments-differ @@ -67,7 +70,6 @@ class PlatformManager(BasePkgManager): BasePkgManager.update(self, name, requirements, only_check) p = PlatformFactory.newPlatform(name, requirements) p.update_packages(only_check) - self.cleanup_packages(p.packages.keys()) return True def is_outdated(self, name, requirements=None): @@ -137,13 +139,13 @@ class PlatformFactory(object): @classmethod def newPlatform(cls, name, requirements=None): - if not requirements and "@" in name: - name, requirements = name.rsplit("@", 1) platform_dir = None if name.endswith("platform.json") and isfile(name): platform_dir = dirname(name) name = util.load_json(name)['name'] else: + if not requirements and "@" in name: + name, requirements = name.rsplit("@", 1) platform_dir = PlatformManager().get_installed_dir(name, requirements) From 795b8be3863996eebca2a03b67cca5cbd363b480 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 5 Aug 2016 13:57:13 +0300 Subject: [PATCH 112/284] Update examples --- examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples b/examples index a657ca42..dc677cf2 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit a657ca4225f55af7239b89486350c9f02bb3ee93 +Subproject commit dc677cf233990929fea1cf36338094837cc5d518 From c1178277caa130742a9c64c8b29ccc81f3341186 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 5 Aug 2016 16:04:10 +0300 Subject: [PATCH 113/284] Print coverage report to terminal --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index a3866532..172bb4c5 100644 --- a/tox.ini +++ b/tox.ini @@ -68,4 +68,4 @@ deps = pytest pytest-cov commands = - py.test --cov=platformio --cov-report xml --ignore=tests/test_examples.py --ignore=tests/test_pkgmanifest.py -v tests + py.test --cov=platformio --cov-report term --cov-report xml --ignore=tests/test_examples.py --ignore=tests/test_pkgmanifest.py -v tests From bf727d6905f6dee471a51aaea31bef772adaca53 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 5 Aug 2016 16:23:39 +0300 Subject: [PATCH 114/284] Update article links --- docs/articles.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/articles.rst b/docs/articles.rst index 7acd3e5a..30ef007f 100644 --- a/docs/articles.rst +++ b/docs/articles.rst @@ -38,18 +38,18 @@ Here are recent articles about PlatformIO: * May 16, 2016 - **Pedro Minatel** - `Controle remoto WiFi com ESP8266 (WiFi remote control using ESP8266, Portuguese) `_ * May 11, 2016 - **Jo Vandeginste** - `Using PlatformIO to compile for Jeelabs' Jeenode Micro `_ * May 08, 2016 - **Radoslaw Bob** - `Touch controlled buzzer (Nodemcu ESP8266) `_ -* May 06, 2016 - **Jean Roux** - `The IoT building blocks I use for my home-automation projects `_ +* May 06, 2016 - **Jean Roux** - `The IoT building blocks I use for my home-automation projects `_ * May 05, 2016 - **Ivan Kravets, Ph.D. / Eclipse Virtual IoT Meetup** - `PlatformIO: a cross-platform IoT solution to build them all! `_ * May 01, 2016 - **Pedro Minatel** - `PlatformIO – Uma alternativa ao Arduino IDE (PlatformIO - An alternative to the Arduino IDE, Portuguese) `_ * Apr 23, 2016 - **Al Williams** - `Hackaday: Atomic Arduino (and Other) Development `_ * Apr 16, 2016 - **Sathittham Sangthong** - `[PlatformIO] มาลองเล่น PlatformIO แทน Arduino IDE กัน (Let's play together with PlatformIO IDE [alternative to Arduino IDE], Thai) `_ -* Apr 15, 2016 - **Daniel Eichhorn** - `ESP8266: Offline Debugging with the Platformio Environment `_ +* Apr 15, 2016 - **Daniel Eichhorn** - `ESP8266: Offline Debugging with the Platformio Environment `_ * Apr 11, 2016 - **Matjaz Trcek** - `Top 5 Arduino integrated development environments `_ * Apr 06, 2016 - **Aleks** - `PlatformIO ausprobiert (Tried PlatformIO, German) `_ * Apr 02, 2016 - **Diego Pinto** - `Você tem coragem de abandonar a IDE do Arduino? PlatformIO + Atom (Do you dare to leave the Arduino IDE? PlatformIO + Atom, Portuguese) `_ * Mar 30, 2016 - **Brandon Cannaday** - `Getting Started with PlatformIO and ESP8266 NodeMcu `_ * Mar 29, 2016 - **Pablo Peñalve** - `PlatformIO + Geany + Raspberry PI, Spanish `_ -* Mar 24, 2016 - **NAzT** - `PlatformIO และการปรับแต่ง เพื่อใช้สำหรับพัฒนา Arduino Library (PlatformIO and advanced development for Arduino Library, Thai) `_ +* Mar 24, 2016 - **NAzT** - `PlatformIO และการปรับแต่ง เพื่อใช้สำหรับพัฒนา Arduino Library (PlatformIO and advanced development for Arduino Library, Thai) `_ * Mar 16, 2016 - **Jakub Skořepa** - `Instalace PlatformIO (PlatformIO IDE Installation, Czech) `_ * Mar 12, 2016 - **Peter Marks** - `PlatformIO, the Arduino IDE for programmers `_ * Mar 12, 2016 - **Richard Arthurs** - `Getting Started With PlatformIO `_ From 39542c4ef209e592ef8679706b3d81c09f0bc6c9 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 5 Aug 2016 17:02:39 +0300 Subject: [PATCH 115/284] Improve platform manager when VCS is used --- platformio/managers/package.py | 49 +++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 3f111d9d..19c4a1a3 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -109,12 +109,7 @@ class PkgInstallerMixin(object): VCS_MANIFEST_NAME = ".piopkgmanager.json" - def get_manifest_path(self, pkg_dir): - if not isdir(pkg_dir): - return None - manifest_path = join(pkg_dir, self.manifest_name) - if isfile(manifest_path): - return manifest_path + def get_vcs_manifest_path(self, pkg_dir): for item in os.listdir(pkg_dir): if not isdir(join(pkg_dir, item)): continue @@ -122,13 +117,27 @@ class PkgInstallerMixin(object): return join(pkg_dir, item, self.VCS_MANIFEST_NAME) return None + def get_manifest_path(self, pkg_dir): + if not isdir(pkg_dir): + return None + manifest_path = join(pkg_dir, self.manifest_name) + if isfile(manifest_path): + return manifest_path + return self.get_vcs_manifest_path(pkg_dir) + def manifest_exists(self, pkg_dir): return self.get_manifest_path(pkg_dir) is not None - def load_manifest(self, pkg_dir): - manifest_path = self.get_manifest_path(pkg_dir) - if manifest_path: - manifest = util.load_json(manifest_path) + def load_manifest(self, path): + pkg_dir = path + if isdir(path): + path = self.get_manifest_path(path) + else: + pkg_dir = dirname(pkg_dir) + if isfile(path) and path.endswith(self.VCS_MANIFEST_NAME): + pkg_dir = dirname(pkg_dir) + if path: + manifest = util.load_json(path) manifest['__pkg_dir'] = pkg_dir return manifest return None @@ -401,8 +410,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): "%s @ %s is not installed" % (name, requirements or "*"), fg="yellow") return - manifest_path = self.get_manifest_path(installed_dir) - if manifest_path.endswith(self.VCS_MANIFEST_NAME): + if self.get_vcs_manifest_path(installed_dir): return False manifest = self.load_manifest(installed_dir) return manifest['version'] != self.get_latest_repo_version( @@ -490,19 +498,24 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): fg="yellow") return - manifest = self.load_manifest(installed_dir) + is_vcs_pkg = False + if self.get_vcs_manifest_path(installed_dir): + is_vcs_pkg = True + manifest_path = self.get_vcs_manifest_path(installed_dir) + else: + manifest_path = self.get_manifest_path(installed_dir) + + manifest = self.load_manifest(manifest_path) click.echo( "%s %s @ %s: \t" % ("Checking" if only_check else "Updating", click.style( - manifest['name'], fg="cyan"), - manifest['version']), + name, fg="cyan"), manifest['version']), nl=False) - manifest_path = self.get_manifest_path(installed_dir) - if manifest_path.endswith(self.VCS_MANIFEST_NAME): + if is_vcs_pkg: if only_check: click.echo("[%s]" % (click.style("Skip", fg="yellow"))) return - click.echo("[%s]" % (click.style("Checking", fg="yellow"))) + click.echo("[%s]" % (click.style("VCS", fg="yellow"))) vcs = VCSClientFactory.newClient(installed_dir, manifest['url']) if not vcs.can_be_updated: click.secho( From 4fc0ab0649cc73ade41c9e0e26cf59b1f3ad5346 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 5 Aug 2016 17:39:32 +0300 Subject: [PATCH 116/284] Fix updating from VCS --- platformio/managers/package.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 19c4a1a3..ea1f6321 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -129,14 +129,15 @@ class PkgInstallerMixin(object): return self.get_manifest_path(pkg_dir) is not None def load_manifest(self, path): + assert path pkg_dir = path if isdir(path): path = self.get_manifest_path(path) else: pkg_dir = dirname(pkg_dir) - if isfile(path) and path.endswith(self.VCS_MANIFEST_NAME): - pkg_dir = dirname(pkg_dir) if path: + if isfile(path) and path.endswith(self.VCS_MANIFEST_NAME): + pkg_dir = dirname(dirname(path)) manifest = util.load_json(path) manifest['__pkg_dir'] = pkg_dir return manifest From 6970c95acabbe24ec7bcb0bd46865bd65e7f77df Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 5 Aug 2016 17:59:10 +0300 Subject: [PATCH 117/284] Fix command lib test --- tests/commands/test_lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/commands/test_lib.py b/tests/commands/test_lib.py index ed4fc603..994417a4 100644 --- a/tests/commands/test_lib.py +++ b/tests/commands/test_lib.py @@ -84,7 +84,7 @@ def test_global_lib_show(clirunner, validate_cliresult, isolated_pio_home): def test_global_lib_update(clirunner, validate_cliresult, isolated_pio_home): result = clirunner.invoke(cli, ["-g", "update"]) validate_cliresult(result) - assert all([s in result.output for s in ("Up-to-date", "Checking")]) + assert all([s in result.output for s in ("[Up-to-date]", "[VCS]")]) def test_global_lib_uninstall(clirunner, validate_cliresult, From c64354ebcc93859933d65997f2c710d764d11b72 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 5 Aug 2016 18:20:09 +0300 Subject: [PATCH 118/284] Add PlatformIO Plus info --- HISTORY.rst | 10 ++++++---- docs/librarymanager/ldf.rst | 6 +++--- docs/platforms/unit_testing.rst | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 327f32e6..2dd9c227 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -7,6 +7,11 @@ PlatformIO 3.0 3.0.0 (2016-??-??) ~~~~~~~~~~~~~~~~~~ +* PlatformIO Plus + + + `Unit Testing `__ for Embedded + (`issue #408 `_) + * Decentralized Development Platforms + Development platform manifest "platform.json" and @@ -19,9 +24,6 @@ PlatformIO 3.0 + Embedded Board compatibility with more than one development platform (`issue #456 `_) -* `Unit Testing `__ for Embedded - (`issue #408 `_) - * Library Manager 3.0 + `Semantic Versioning `__ for library commands and @@ -41,7 +43,7 @@ PlatformIO 3.0 * New Intelligent Library Build System + `Library Dependency Finder `__ - that interprets C Preprocessor conditional macros with deep search behavior + that interprets C/C++ Preprocessor conditional macros with deep search behavior + Check library compatibility with project environment before building (`issue #415 `_) + Control Library Dependency Finder for compatibility using diff --git a/docs/librarymanager/ldf.rst b/docs/librarymanager/ldf.rst index 8744cafb..8c9c32a9 100644 --- a/docs/librarymanager/ldf.rst +++ b/docs/librarymanager/ldf.rst @@ -133,11 +133,11 @@ This mode can be changed using :ref:`projectconf_lib_compat_mode` option in .. _ldf_c_cond_syntax: -C Preprocessor conditional syntax ---------------------------------- +C/C++ Preprocessor conditional syntax +------------------------------------- In spite of the fact that Library Dependency Finder is written in pure Python, -it interprets (emulates) `C Preprocessor conditional syntax `_ +it interprets (emulates) `C/C++ Preprocessor conditional syntax `_ (``#ifdef``, ``if``, ``defined``, ``else``, and ``elif``) without calling ``gcc -E``. For example, diff --git a/docs/platforms/unit_testing.rst b/docs/platforms/unit_testing.rst index 316c17ba..5e6555a5 100644 --- a/docs/platforms/unit_testing.rst +++ b/docs/platforms/unit_testing.rst @@ -14,7 +14,7 @@ Unit Testing ============ -.. versionadded:: 3.0 +.. versionadded:: 3.0 (PlatformIO Plus) `Unit Testing (wiki) `_ is a software testing method by which individual units of source code, sets From db267513ca9f194c9ebdd2f64405549c4bbde5a7 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 5 Aug 2016 18:43:20 +0300 Subject: [PATCH 119/284] Implement custom "rmtree"; resolve issue with Windows and .git --- platformio/__init__.py | 2 +- platformio/commands/ci.py | 16 ++++++---------- platformio/commands/run.py | 5 ++--- platformio/managers/package.py | 12 ++++++------ platformio/util.py | 11 +++++++++++ tests/test_examples.py | 7 +++---- 6 files changed, 29 insertions(+), 24 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 8948d92b..d3eaf0e4 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev20") +VERSION = (3, 0, "0.dev21") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index 886c9506..c7da3943 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -12,16 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -import stat from glob import glob -from os import chmod, getenv, makedirs, remove +from os import getenv, makedirs, remove from os.path import abspath, basename, expanduser, isdir, isfile, join -from shutil import copyfile, copytree, rmtree +from shutil import copyfile, copytree from tempfile import mkdtemp import click -from platformio import app +from platformio import app, util 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 @@ -119,14 +118,11 @@ def cli(ctx, # pylint: disable=R0913 ctx.invoke(cmd_run, project_dir=build_dir, verbose=verbose) finally: if not keep_build_dir: - rmtree( - build_dir, - onerror=lambda action, name, exc: (chmod(name, stat.S_IWRITE), - remove(name))) + util.rmtree_(build_dir) def _clean_dir(dirpath): - rmtree(dirpath) + util.rmtree_(dirpath) makedirs(dirpath) @@ -165,7 +161,7 @@ def _exclude_contents(dst_dir, patterns): for path in contents: path = abspath(path) if isdir(path): - rmtree(path) + util.rmtree_(path) elif isfile(path): remove(path) diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 9f4043e0..cdc8d944 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -16,7 +16,6 @@ from datetime import datetime from hashlib import sha1 from os import getcwd, makedirs, walk from os.path import getmtime, isdir, isfile, join -from shutil import rmtree from time import time import click @@ -234,14 +233,14 @@ def _clean_pioenvs_dir(pioenvs_dir): if (isdir(pioenvs_dir) and getmtime(join(util.get_project_dir(), "platformio.ini")) > getmtime(pioenvs_dir)): - rmtree(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 - rmtree(pioenvs_dir) + util.rmtree_(pioenvs_dir) if not isdir(pioenvs_dir): makedirs(pioenvs_dir) diff --git a/platformio/managers/package.py b/platformio/managers/package.py index ea1f6321..9b8cdc4f 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -15,7 +15,7 @@ import json import os from os.path import basename, dirname, isdir, isfile, islink, join -from shutil import copyfile, copytree, rmtree +from shutil import copyfile, copytree from tempfile import mkdtemp import click @@ -159,7 +159,7 @@ class PkgInstallerMixin(object): copytree(item_path, join(pkg_dir, item), symlinks=True) # remove not used contents while True: - rmtree(root) + util.rmtree_(root) root = dirname(root) if root == pkg_dir: break @@ -205,7 +205,7 @@ class PkgInstallerMixin(object): if isfile(url): self.unpack(url, tmp_dir) else: - rmtree(tmp_dir) + util.rmtree_(tmp_dir) copytree(url, tmp_dir) elif url.startswith(("http://", "https://")): dlpath = self.download(url, tmp_dir, sha1) @@ -228,7 +228,7 @@ class PkgInstallerMixin(object): pkg_dir = self._install_from_tmp_dir(tmp_dir, requirements) finally: if isdir(tmp_dir): - rmtree(tmp_dir) + util.rmtree_(tmp_dir) return pkg_dir def _install_from_tmp_dir(self, tmp_dir, requirements=None): @@ -267,7 +267,7 @@ class PkgInstallerMixin(object): # remove previous/not-satisfied package if isdir(pkg_dir): - rmtree(pkg_dir) + util.rmtree_(pkg_dir) os.rename(tmp_dir, pkg_dir) assert isdir(pkg_dir) return pkg_dir @@ -478,7 +478,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): if islink(installed_dir): os.unlink(installed_dir) else: - rmtree(installed_dir) + util.rmtree_(installed_dir) click.echo("[%s]" % click.style("OK", fg="green")) diff --git a/platformio/util.py b/platformio/util.py index eeb02caf..cd87103c 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -17,12 +17,14 @@ import functools import json import os import re +import stat import subprocess import sys from glob import glob from os.path import (abspath, basename, dirname, expanduser, isdir, isfile, join, splitdrive) from platform import system, uname +from shutil import rmtree from threading import Thread from platformio import __apiip__, __apiurl__, __version__, exception @@ -454,3 +456,12 @@ def where_is_program(program, envpath=None): def pepver_to_semver(pepver): return re.sub(r"(\.\d+)\.?(dev|a|b|rc|post)", r"\1-\2", pepver, 1) + + +def rmtree_(path): + + def _onerror(_, name, __): + os.chmod(name, stat.S_IWRITE) + os.remove(name) + + return rmtree(path, onerror=_onerror) diff --git a/tests/test_examples.py b/tests/test_examples.py index 959d974b..bfe428d9 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -15,11 +15,10 @@ from glob import glob from os import listdir, walk from os.path import dirname, getsize, isdir, isfile, join, normpath -from shutil import rmtree import pytest -from platformio.util import exec_command +from platformio import util def pytest_generate_tests(metafunc): @@ -38,9 +37,9 @@ def pytest_generate_tests(metafunc): @pytest.mark.examples def test_run(platformio_setup, pioproject_dir): if isdir(join(pioproject_dir, ".pioenvs")): - rmtree(join(pioproject_dir, ".pioenvs")) + util.rmtree_(join(pioproject_dir, ".pioenvs")) - result = exec_command( + result = util.exec_command( ["platformio", "--force", "run", "--project-dir", pioproject_dir] ) if result['returncode'] != 0: From 098653aac7e253211cbb0d57b373797aec814689 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 5 Aug 2016 18:52:24 +0300 Subject: [PATCH 120/284] Better explanation with dependencies --- docs/librarymanager/ldf.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/librarymanager/ldf.rst b/docs/librarymanager/ldf.rst index 8c9c32a9..c3dd7504 100644 --- a/docs/librarymanager/ldf.rst +++ b/docs/librarymanager/ldf.rst @@ -61,12 +61,12 @@ Library Dependency Finder starts work from analyzing source files of the project (:ref:`projectconf_pio_src_dir`) and can work in the next modes: * ``0`` - "manual mode", does not process source files of a project and - dependent libraries. Builds only the libraries that are specified in + dependencies. Builds only the libraries that are specified in manifests (:ref:`library_config`, ``module.json``) or in the :ref:`projectconf`. * ``1`` - parses ALL C/C++ source code of the project and follows only by nested includes/chain (``#include ...``) from the libraries. * ``2`` - **default** - parses ALL C/C++ source code of the project and parses - ALL C/C++ source code of the each dependent library (recursively). + ALL C/C++ source code of the each dependency (recursively). This mode can be changed using :ref:`projectconf_lib_ldf_mode` option in :ref:`projectconf`. @@ -110,7 +110,7 @@ A difference between ``1`` and ``2`` modes. For example, there are 2 libraries: Firstly, ``LDF`` finds "Foo" library, then it parses all sources from "Foo" library and finds ``Foo/foo.cpp`` that depends on ``#include ``. Secondly, it will parse all sources from "Bar" library and this operation - continues until all dependent libraries will not be parsed. + continues until all dependencies will not be parsed. .. _ldf_compat_mode: From 80c7a8d1cebb9e4eacce626e7b196d5b9f6471d0 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 8 Aug 2016 14:00:01 +0300 Subject: [PATCH 121/284] Warn about unknown options in project configuration file // Resolve #740 --- platformio/builder/main.py | 2 +- platformio/commands/run.py | 58 +++++++++++++++++++++++++++----------- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 05823c66..5bbabd15 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -96,7 +96,7 @@ DefaultEnvironment( env = DefaultEnvironment() if env.GetOption("silent"): - print "Use `-v, --verbose` option to enable verbose mode" + print "Verbose mode can be enabled via `-v, --verbose` option" Progress(env.ProgressHandler) # decode common variables diff --git a/platformio/commands/run.py b/platformio/commands/run.py index cdc8d944..180d01a9 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -52,7 +52,6 @@ def cli(ctx, # pylint: disable=R0913,R0914 project_dir, verbose, disable_auto_clean): - assert check_project_envs(project_dir, environment) with util.cd(project_dir): # clean obsolete .pioenvs dir if not disable_auto_clean: @@ -66,6 +65,9 @@ def cli(ctx, # pylint: disable=R0913,R0914 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 = [ @@ -109,13 +111,17 @@ def cli(ctx, # pylint: disable=R0913,R0914 class EnvironmentProcessor(object): - REMAPED_OPTIONS = {"FRAMEWORK": "PIOFRAMEWORK", "PLATFORM": "PIOPLATFORM"} + KNOWN_OPTIONS = ( + "platform", "framework", "board", "board_mcu", "board_f_cpu", + "board_f_flash", "board_flash_mode", "build_flags", "src_build_flags", + "build_unflags", "src_filter", "extra_script", "targets", + "upload_port", "upload_protocol", "upload_speed", "upload_flags", + "upload_resetmethod", "lib_install", "lib_force", "lib_ignore", + "lib_extra_dirs", "lib_ldf_mode", "lib_compat_mode", "piotest") - RENAMED_OPTIONS = { - "INSTALL_LIBS": "LIB_INSTALL", - "IGNORE_LIBS": "LIB_IGNORE", - "LIB_USE": "LIB_FORCE" - } + REMAPED_OPTIONS = {"framework": "pioframework", "platform": "pioplatform"} + + RENAMED_OPTIONS = {"lib_use": "lib_force"} def __init__(self, # pylint: disable=R0913 cmd_ctx, @@ -126,7 +132,7 @@ class EnvironmentProcessor(object): verbose): self.cmd_ctx = cmd_ctx self.name = name - self.options = self._validate_options(options) + self.options = options self.targets = targets self.upload_port = upload_port self.verbose = verbose @@ -141,6 +147,7 @@ class EnvironmentProcessor(object): ["%s: %s" % (k, v) for k, v in self.options.iteritems()]))) click.secho("-" * terminal_width, bold=True) + self.options = self._validate_options(self.options) result = self._run() is_error = result['returncode'] != 0 @@ -157,15 +164,20 @@ class EnvironmentProcessor(object): def _validate_options(self, options): result = {} for k, v in options.items(): - _k = k.upper() # process obsolete options - if _k in self.RENAMED_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].lower()), + "`%s` instead." % (k, self.RENAMED_OPTIONS[k]), + fg="yellow") + k = self.RENAMED_OPTIONS[k] + # warn about unknown options + if k not in self.KNOWN_OPTIONS: + click.secho( + "Warning! Ignore unknown `%s` option from `[env:]` section" + % k, fg="yellow") - k = self.RENAMED_OPTIONS[_k].lower() result[k] = v return result @@ -174,9 +186,8 @@ class EnvironmentProcessor(object): if self.upload_port: variables['upload_port'] = self.upload_port for k, v in self.options.items(): - if k.upper() in self.REMAPED_OPTIONS: - k = self.REMAPED_OPTIONS[k.upper()] - k = k.lower() + if k in self.REMAPED_OPTIONS: + k = self.REMAPED_OPTIONS[k] if k == "targets" or (k == "upload_port" and self.upload_port): continue variables[k] = v @@ -256,9 +267,22 @@ def print_header(label, is_error=False): click.echo("%s %s %s" % (half_line, label, half_line), err=is_error) -def check_project_envs(project_dir, environments): - config = util.load_project_config(project_dir) +def check_project_defopts(config): + if not config.has_section("platformio"): + return True + known = ("home_dir", "lib_dir", "libdeps_dir", "src_dir", "env_dir", + "data_dir", "test_dir", "env_default") + 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() From 0b749c3888e0c08934c69199564315bfe8c28d5d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 8 Aug 2016 14:00:23 +0300 Subject: [PATCH 122/284] Warn about unknown options in project configuration file // Resolve #740 --- HISTORY.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index 2dd9c227..395e28be 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -67,7 +67,9 @@ PlatformIO 3.0 (`issue #721 `_) * Added ``license`` field to `library.json `__ (`issue #522 `_) -* Stopped Supporting Python 2.6 +* Warn about unknown options in project configuration file ``platformio.ini`` + (`issue #740 `_) +* Stopped supporting Python 2.6 PlatformIO 2.0 From 65e0daa06dde68e409cd43bf8b7256f48283f9a4 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 8 Aug 2016 16:03:17 +0300 Subject: [PATCH 123/284] Project dependencies per build environment using "lib_deps" option // Resolve #413 --- HISTORY.rst | 4 +- docs/envvars.rst | 4 ++ docs/librarymanager/ldf.rst | 8 ++-- docs/projectconf.rst | 59 ++++++++++++++++++++---------- docs/userguide/lib/cmd_install.rst | 3 +- platformio/__init__.py | 2 +- platformio/commands/run.py | 49 ++++++++++++++++--------- 7 files changed, 85 insertions(+), 44 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 395e28be..9ee0df5c 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -26,10 +26,12 @@ PlatformIO 3.0 * Library Manager 3.0 + + Project dependencies per build environment using `lib_deps `__ option + (`issue #413 `_) + `Semantic Versioning `__ for library commands and dependencies (`issue #410 `_) - + Multiple library storages: project's local, PlatformIO global or custom + + Multiple library storages: Project's Local, PlatformIO's Global or Custom (`issue #475 `_) + Install library by name (`issue #414 `_) diff --git a/docs/envvars.rst b/docs/envvars.rst index 771f043e..5931e391 100644 --- a/docs/envvars.rst +++ b/docs/envvars.rst @@ -57,6 +57,10 @@ Allows to override :ref:`projectconf` option :ref:`projectconf_pio_home_dir`. Allows to override :ref:`projectconf` option :ref:`projectconf_pio_lib_dir`. +.. envvar:: PLATFORMIO_LIBDEPS_DIR + +Allows to override :ref:`projectconf` option :ref:`projectconf_pio_libdeps_dir`. + .. envvar:: PLATFORMIO_SRC_DIR Allows to override :ref:`projectconf` option :ref:`projectconf_pio_src_dir`. diff --git a/docs/librarymanager/ldf.rst b/docs/librarymanager/ldf.rst index c3dd7504..bd5889ff 100644 --- a/docs/librarymanager/ldf.rst +++ b/docs/librarymanager/ldf.rst @@ -30,6 +30,7 @@ Library Dependency Finder has controls that can be set up in :ref:`projectconf`: .. hlist:: :columns: 3 + * :ref:`projectconf_lib_deps` * :ref:`projectconf_lib_extra_dirs` * :ref:`projectconf_lib_force` * :ref:`projectconf_lib_ignore` @@ -43,12 +44,13 @@ Library Dependency Finder has controls that can be set up in :ref:`projectconf`: Storage ------- -There are different storages/folders where Library Dependency Finder looks for -libraries. These folders/path have priority and LDF operates in the next order: +There are different storages where Library Dependency Finder looks for +libraries. These storages (folders) have priority and LDF operates in the next +order: 1. :ref:`projectconf_lib_extra_dirs` - extra storages per build environment 2. :ref:`projectconf_pio_lib_dir` - own/private library storage per project -3. :ref:`projectconf_pio_piolibdeps_dir` - project dependencies storage used by +3. :ref:`projectconf_pio_libdeps_dir` - project dependencies storage used by :ref:`librarymanager` 4. ":ref:`projectconf_pio_home_dir`/lib" - global storage per all projects. diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 439ced3d..09c8f35f 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -102,17 +102,17 @@ Then in ``src/main.c`` you should use: PlatformIO will find your libraries automatically, configure preprocessor's include paths and build them. -.. _projectconf_pio_piolibdeps_dir: +.. _projectconf_pio_libdeps_dir: -``piolibdeps_dir`` -^^^^^^^^^^^^^^^^^^ +``libdeps_dir`` +^^^^^^^^^^^^^^^ -Internal storage where :ref:`librarymanager` will install project dependencies. -A default value is ``.piolibdeps`` that means that folder is located in the root of -project. +Internal storage where :ref:`librarymanager` will install project dependencies +(:ref:`projectconf_lib_deps`). A default value is ``.piolibdeps`` that means +that folder is located in the root of project. This option can be overridden by global environment variable -:envvar:`PLATFORMIO_PIOLIBDEPS_DIR`. +:envvar:`PLATFORMIO_LIBDEPS_DIR`. .. _projectconf_pio_src_dir: @@ -639,21 +639,40 @@ Library options .. contents:: :local: -``lib_install`` -^^^^^^^^^^^^^^^ +.. _projectconf_lib_deps: -Specify dependent libraries which should be installed before environment -process. The only library IDs are allowed. Multiple libraries can be passed -using comma ``,`` sign. +``lib_deps`` +^^^^^^^^^^^^ -You can obtain library IDs using :ref:`cmd_lib_search` command. +Specify project dependencies that should be installed automatically to +:ref:`projectconf_pio_libdeps_dir` before an environment process. +Multiple dependencies are allowed (multi-lines). + +**Valid forms** + +.. code-block:: ini + + [env:***] + lib_deps = + LIBRARY_1 + LIBRARY_2 + LIBRARY_N + +The each line with ``LIBRARY_1... LIBRARY_N`` will be passed automatically to +:ref:`cmd_lib_install` command. Please follow to :ref:`cmd_lib_install` for +detailed documentation about possible values. Example: .. code-block:: ini - [env:depends_on_some_libs] - lib_install = 1,13,19 + [env:depends_on_some_libs] + lib_deps = + 1 + PubSubClient + Json@~5.6,!=5.4 + https://github.com/gioblu/PJON.git@v2.0 + https://github.com/me-no-dev/ESPAsyncTCP.git .. _projectconf_lib_force: @@ -663,12 +682,12 @@ Example: .. seealso:: Please make sure to read :ref:`ldf` guide first. -Force Library Dependency Finder to depend on the specified libraries if -they even are not included in the project source code. Also, these -libraries will be processed in the first order. +Force Library Dependency Finder to depend on the specified library if it even +is not included in the project source code. Also, this library will be +processed in the first order. -The correct value for this option is library name (not -folder name). In the most cases, library name is pre-defined in manifest file +The correct value for this option is library name (not folder name). In the +most cases, library name is pre-defined in manifest file (:ref:`library_config`, ``library.properties``, ``module.json``). The multiple library names are allowed, split them with comma ``,`` separator. diff --git a/docs/userguide/lib/cmd_install.rst b/docs/userguide/lib/cmd_install.rst index c43122c0..6f007bbe 100644 --- a/docs/userguide/lib/cmd_install.rst +++ b/docs/userguide/lib/cmd_install.rst @@ -38,6 +38,7 @@ Usage # [LIBRARY...] forms platformio lib [STORAGE_OPTIONS] install (with no args, project dependencies) platformio lib [STORAGE_OPTIONS] install + platformio lib [STORAGE_OPTIONS] install id= platformio lib [STORAGE_OPTIONS] install @ platformio lib [STORAGE_OPTIONS] install @ platformio lib [STORAGE_OPTIONS] install @@ -47,7 +48,7 @@ Usage platformio lib [STORAGE_OPTIONS] install file:// platformio lib [STORAGE_OPTIONS] install file:// platformio lib [STORAGE_OPTIONS] install - platformio lib [STORAGE_OPTIONS] install (name it should have locally) + platformio lib [STORAGE_OPTIONS] install = (name it should have locally) platformio lib [STORAGE_OPTIONS] install ("tag" can be commit, branch or tag) Description diff --git a/platformio/__init__.py b/platformio/__init__.py index d3eaf0e4..706fe860 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev21") +VERSION = (3, 0, "0.dev22") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 180d01a9..3309cf07 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -111,13 +111,14 @@ def cli(ctx, # pylint: disable=R0913,R0914 class EnvironmentProcessor(object): - KNOWN_OPTIONS = ( - "platform", "framework", "board", "board_mcu", "board_f_cpu", - "board_f_flash", "board_flash_mode", "build_flags", "src_build_flags", - "build_unflags", "src_filter", "extra_script", "targets", - "upload_port", "upload_protocol", "upload_speed", "upload_flags", - "upload_resetmethod", "lib_install", "lib_force", "lib_ignore", - "lib_extra_dirs", "lib_ldf_mode", "lib_compat_mode", "piotest") + KNOWN_OPTIONS = ("platform", "framework", "board", "board_mcu", + "board_f_cpu", "board_f_flash", "board_flash_mode", + "build_flags", "src_build_flags", "build_unflags", + "src_filter", "extra_script", "targets", "upload_port", + "upload_protocol", "upload_speed", "upload_flags", + "upload_resetmethod", "lib_install", "lib_deps", + "lib_force", "lib_ignore", "lib_extra_dirs", + "lib_ldf_mode", "lib_compat_mode", "piotest") REMAPED_OPTIONS = {"framework": "pioframework", "platform": "pioplatform"} @@ -141,10 +142,18 @@ class EnvironmentProcessor(object): terminal_width, _ = click.get_terminal_size() start_time = time() - click.echo("[%s] Processing %s (%s)" % ( - datetime.now().strftime("%c"), click.style( - self.name, fg="cyan", bold=True), ", ".join( - ["%s: %s" % (k, v) for k, v in self.options.iteritems()]))) + process_opts = [] + for k, v in self.options.items(): + if "\n" in v: + process_opts.append((k, "; ".join( + [s.strip() for s in v.split("\n") if s.strip()]))) + else: + process_opts.append((k, v)) + + click.echo("[%s] Processing %s (%s)" % + (datetime.now().strftime("%c"), click.style( + self.name, fg="cyan", bold=True), + ", ".join(["%s: %s" % opts for opts in process_opts]))) click.secho("-" * terminal_width, bold=True) self.options = self._validate_options(self.options) @@ -212,8 +221,15 @@ class EnvironmentProcessor(object): # install dependent libraries if "lib_install" in self.options: - _autoinstall_libs(self.cmd_ctx, self.options['lib_install'], - self.verbose) + _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 d.strip() + ], self.verbose) try: p = PlatformFactory.newPlatform(self.options['platform']) @@ -225,15 +241,12 @@ class EnvironmentProcessor(object): return p.run(build_vars, build_targets, self.verbose) -def _autoinstall_libs(ctx, libids_list, verbose=False): +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) - ctx.invoke( - cmd_lib_install, - libraries=[int(l.strip()) for l in libids_list.split(",")], - quiet=not verbose) + ctx.invoke(cmd_lib_install, libraries=libraries, quiet=not verbose) def _clean_pioenvs_dir(pioenvs_dir): From 1efea0bd27fc57ec0694cade4eb7f59d8e2aed01 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 8 Aug 2016 16:06:12 +0300 Subject: [PATCH 124/284] Mark "lib_deps" as PIO3; first development "alpha" --- docs/projectconf.rst | 4 ++++ platformio/__init__.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 09c8f35f..d0cb2468 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -644,6 +644,10 @@ Library options ``lib_deps`` ^^^^^^^^^^^^ +.. versionadded:: 3.0 +.. seealso:: + Please make sure to read :ref:`ldf` guide first. + Specify project dependencies that should be installed automatically to :ref:`projectconf_pio_libdeps_dir` before an environment process. Multiple dependencies are allowed (multi-lines). diff --git a/platformio/__init__.py b/platformio/__init__.py index 706fe860..98cf88b7 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev22") +VERSION = (3, 0, "0a1") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" From f9ead74b8824fb17aff69d81a9cef6cbd849db40 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 8 Aug 2016 18:57:18 +0300 Subject: [PATCH 125/284] Fix issue when check that LibBuilder contains source file by path --- platformio/builder/tools/piolib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 35fba8cd..4acaab35 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -18,7 +18,7 @@ from __future__ import absolute_import import os import sys -from os.path import basename, commonprefix, isdir, isfile, join, realpath +from os.path import basename, commonprefix, isdir, isfile, join, realpath, sep import SCons.Scanner @@ -93,7 +93,7 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes return "%s(%r)" % (self.__class__, self.path) def __contains__(self, path): - return commonprefix((self.path, path)) == self.path + return commonprefix((self.path + sep, path)) == self.path + sep @property def name(self): From 20e75251185a8b29491955a53abc163bc2f72b18 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 8 Aug 2016 19:44:31 +0300 Subject: [PATCH 126/284] Update links to Library Dependency Finder --- examples | 2 +- platformio/builder/tools/piolib.py | 2 +- platformio/commands/init.py | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/examples b/examples index dc677cf2..ea62e450 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit dc677cf233990929fea1cf36338094837cc5d518 +Subproject commit ea62e450c026f19da620ce5a14240c3ad9f5657f diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 4acaab35..473db360 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -525,7 +525,7 @@ def BuildDependentLibraries(env, src_dir): project.search_deps_recursive(lib_builders) if project.depbuilders: - print "Library Dependency Map" + print "Project Dependencies Graph" print_deps_tree(project) else: print "Project does not have dependencies" diff --git a/platformio/commands/init.py b/platformio/commands/init.py index 7d9fb2ed..9ab78e11 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -198,10 +198,8 @@ Then in `src/main.c` you should use: PlatformIO will find your libraries automatically, configure preprocessor's include paths and build them. -See additional options for PlatformIO Library Dependency Finder `lib_*`: - -http://docs.platformio.org/en/stable/projectconf.html#lib-install - +More information about PlatformIO Library Dependency Finder +- http://docs.platformio.org/en/stable/librarymanager/ldf.html """) From 8b53f6e320bb9effe873c9d6f4c165b486afc2aa Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 8 Aug 2016 19:51:15 +0300 Subject: [PATCH 127/284] Move Unit Testing to the TOP level --- HISTORY.rst | 2 +- docs/index.rst | 2 +- docs/{platforms => }/unit_testing.rst | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename docs/{platforms => }/unit_testing.rst (100%) diff --git a/HISTORY.rst b/HISTORY.rst index 9ee0df5c..0825752f 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -9,7 +9,7 @@ PlatformIO 3.0 * PlatformIO Plus - + `Unit Testing `__ for Embedded + + `Unit Testing `__ for Embedded (`issue #408 `_) * Decentralized Development Platforms diff --git a/docs/index.rst b/docs/index.rst index 13be0abd..387fd68e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -111,7 +111,7 @@ Contents platforms/embedded_boards frameworks/index platforms/custom_platform_and_board - platforms/unit_testing + unit_testing .. toctree:: :caption: Library Manager diff --git a/docs/platforms/unit_testing.rst b/docs/unit_testing.rst similarity index 100% rename from docs/platforms/unit_testing.rst rename to docs/unit_testing.rst From 7f7cf5281fb51e3806e329aeb9a611fbec3907a8 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 8 Aug 2016 20:04:47 +0300 Subject: [PATCH 128/284] Show package name when updating --- platformio/managers/package.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 9b8cdc4f..0a51dcd8 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -510,7 +510,8 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): click.echo( "%s %s @ %s: \t" % ("Checking" if only_check else "Updating", click.style( - name, fg="cyan"), manifest['version']), + manifest['name'], fg="cyan"), + manifest['version']), nl=False) if is_vcs_pkg: if only_check: From 70df551eef20bb90799bd393572a3683ee6f7041 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 8 Aug 2016 23:10:57 +0300 Subject: [PATCH 129/284] Fix platformio test command // Resolve #743 --- platformio/__init__.py | 2 +- platformio/commands/test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 98cf88b7..fe95a14d 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0a1") +VERSION = (3, 0, "0a2") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/commands/test.py b/platformio/commands/test.py index 3f9ae9c3..9ba8e472 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -45,13 +45,13 @@ from platformio.managers.platform import PlatformFactory @click.option("--verbose", "-v", is_flag=True) @click.pass_context def cli(ctx, environment, skip, upload_port, project_dir, verbose): - assert check_project_envs(project_dir, environment) with util.cd(project_dir): test_dir = util.get_projecttest_dir() if not isdir(test_dir): raise exception.TestDirEmpty(test_dir) test_names = get_test_names(test_dir) projectconf = util.load_project_config() + assert check_project_envs(projectconf, environment) click.echo("Collected %d items" % len(test_names)) click.echo() From 239be03a5401b53e446927fd39339ca3ebf225ab Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 8 Aug 2016 23:25:44 +0300 Subject: [PATCH 130/284] Minor changes --- examples | 2 +- platformio/builder/tools/piolib.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples b/examples index ea62e450..9b0c8c32 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit ea62e450c026f19da620ce5a14240c3ad9f5657f +Subproject commit 9b0c8c32ccc7e7cd1d937874c66a92c66bf745f1 diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 473db360..ad81bdeb 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -525,7 +525,7 @@ def BuildDependentLibraries(env, src_dir): project.search_deps_recursive(lib_builders) if project.depbuilders: - print "Project Dependencies Graph" + print "Library Dependency Graph" print_deps_tree(project) else: print "Project does not have dependencies" From 97c58c8dcace05c540ba443efbcbc684e171f2f2 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 9 Aug 2016 10:30:21 +0300 Subject: [PATCH 131/284] Add CI for macOS --- .travis.yml | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 658547ab..8976ec8a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,25 +1,36 @@ language: python -python: - - "2.7" -env: - - TOX_ENV=docs - - TOX_ENV=lint - - TOX_ENV=py27 +matrix: + include: + - os: linux + sudo: required + python: 2.7 + env: TOX_ENV=docs + - os: linux + sudo: required + python: 2.7 + env: TOX_ENV=lint + - os: linux + sudo: required + python: 2.7 + env: TOX_ENV=py27 + - os: osx + language: generic + env: TOX_ENV=py27 install: - git submodule update --init --recursive - - pip install -U pip setuptools tox + - sudo pip install -U pip setuptools tox # temporary hook to fix issue with gcc-pic32 - - sudo apt-get install -qq lib32z1 lib32ncurses5 lib32bz2-1.0 + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -qq lib32z1 lib32ncurses5 lib32bz2-1.0; fi script: - tox -e $TOX_ENV after_success: - - tox -e coverage - - bash <(curl -s https://codecov.io/bash) + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then tox -e coverage; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then bash <(curl -s https://codecov.io/bash); fi notifications: slack: From 20be83ef95228c34bbca2bc7442c3a3d32c75de1 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 9 Aug 2016 14:09:21 +0300 Subject: [PATCH 132/284] Add support for BBC micro:bit board that is built on the ARM mbed and Nordic nrf51 platform // Resolve #709 --- HISTORY.rst | 3 +++ platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 25 +++---------------------- platformio/managers/lib.py | 29 +++++++++++++++++++++++++---- 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 0825752f..1451fd11 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -64,6 +64,9 @@ PlatformIO 3.0 + Support for the 3rd party manifests (Arduino IDE "library.properties" and ARM mbed "module.json") +* Added support for BBC micro:bit board that is built on the ARM mbed and + Nordic nrf51 platform + (`issue #709 `_) * Print human-readable information when processing environments without ``-v, --verbose`` option (`issue #721 `_) diff --git a/platformio/__init__.py b/platformio/__init__.py index fe95a14d..e880489e 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0a2") +VERSION = (3, 0, "0a3") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index ad81bdeb..795f72e6 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -24,6 +24,7 @@ import SCons.Scanner from platformio import util from platformio.builder.tools import platformio as piotool +from platformio.managers.lib import LibraryManager class LibBuilderFactory(object): @@ -105,28 +106,8 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes @property def dependencies(self): - deps = self._manifest.get("dependencies") - if not deps: - return deps - items = [] - if isinstance(deps, dict): - if "name" in deps: - items.append(deps) - else: - for name, version in deps.items(): - items.append({"name": name, "version": version}) - elif isinstance(deps, list): - items = [d for d in deps if "name" in d] - for item in items: - for k in ("frameworks", "platforms"): - if k not in item or isinstance(k, list): - continue - if item[k] == "*": - del item[k] - elif isinstance(item[k], basestring): - item[k] = [i.strip() for i in item[k].split(",") - if i.strip()] - return items + return LibraryManager.normalize_dependencies( + self._manifest.get("dependencies", [])) @property def src_filter(self): diff --git a/platformio/managers/lib.py b/platformio/managers/lib.py index a34a196b..ce1543a8 100644 --- a/platformio/managers/lib.py +++ b/platformio/managers/lib.py @@ -33,6 +33,30 @@ class LibraryManager(BasePkgManager): def manifest_name(self): return ".library.json" + @staticmethod + def normalize_dependencies(dependencies): + if not dependencies: + return [] + items = [] + if isinstance(dependencies, dict): + if "name" in dependencies: + items.append(dependencies) + else: + for name, version in dependencies.items(): + items.append({"name": name, "version": version}) + elif isinstance(dependencies, list): + items = [d for d in dependencies if "name" in d] + for item in items: + for k in ("frameworks", "platforms"): + if k not in item or isinstance(k, list): + continue + if item[k] == "*": + del item[k] + elif isinstance(item[k], basestring): + item[k] = [i.strip() for i in item[k].split(",") + if i.strip()] + return items + @staticmethod def max_satisfying_repo_version(versions, requirements=None): @@ -132,10 +156,7 @@ class LibraryManager(BasePkgManager): if not quiet: click.secho("Installing dependencies", fg="yellow") - _dependencies = manifest['dependencies'] - if not isinstance(_dependencies, list): - _dependencies = [_dependencies] - for filters in _dependencies: + for filters in self.normalize_dependencies(manifest['dependencies']): assert "name" in filters if any([s in filters.get("version", "") for s in ("\\", "/")]): self.install("{name}={version}".format(**filters)) From fe76192590d51e34da73ec6aedab68b5d376ba29 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 9 Aug 2016 14:25:05 +0300 Subject: [PATCH 133/284] Automatically detect Microbit disk for upload // Issue #709 --- platformio/builder/tools/pioupload.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/builder/tools/pioupload.py b/platformio/builder/tools/pioupload.py index 65d80b79..072685b3 100644 --- a/platformio/builder/tools/pioupload.py +++ b/platformio/builder/tools/pioupload.py @@ -84,7 +84,7 @@ def AutodetectUploadPort(*args, **kwargs): # pylint: disable=unused-argument print "Looking for upload port/disk..." def _look_for_mbed_disk(): - msdlabels = ("mbed", "nucleo", "frdm") + msdlabels = ("mbed", "nucleo", "frdm", "microbit") for item in util.get_logicaldisks(): if (not item['name'] or not any([l in item['name'].lower() for l in msdlabels])): From 92e82941fefc99b5d17056b62d5af9972c3c9a6d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 9 Aug 2016 14:37:44 +0300 Subject: [PATCH 134/284] Hint about hard reset for the boards with mbed bootloader // Issue #709 --- platformio/builder/tools/pioupload.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/builder/tools/pioupload.py b/platformio/builder/tools/pioupload.py index 072685b3..728e8883 100644 --- a/platformio/builder/tools/pioupload.py +++ b/platformio/builder/tools/pioupload.py @@ -142,7 +142,7 @@ def UploadToDisk(_, target, source, env): # pylint: disable=W0613,W0621 copyfile(fpath, join( env.subst("$UPLOAD_PORT"), "%s.%s" % (progname, ext))) print("Firmware has been successfully uploaded.\n" - "Please restart your board.") + "(Some boards may require manual hard reset)") def CheckUploadSize(_, target, source, env): # pylint: disable=W0613,W0621 From 5ba20fc6ed4b42c3fedcf014fb4a9da4070e700e Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 9 Aug 2016 15:10:52 +0300 Subject: [PATCH 135/284] Remove prompts from init command; Update template for Project Configuration File --- examples | 2 +- platformio/commands/init.py | 27 +++++++++++++++++---------- platformio/projectconftpl.ini | 8 ++++++-- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/examples b/examples index 9b0c8c32..4b6ddf48 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 9b0c8c32ccc7e7cd1d937874c66a92c66bf745f1 +Subproject commit 4b6ddf489635f332d4871fd4045634a49ad2aac7 diff --git a/platformio/commands/init.py b/platformio/commands/init.py index 9ab78e11..3d271f03 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -77,10 +77,10 @@ def cli(ctx, # pylint: disable=R0913 fg="yellow") click.echo("") - click.echo("The next files/directories will be created in %s" % + click.echo("The next files/directories have been created in %s" % click.style( project_dir, fg="cyan")) - click.echo("%s - Project Configuration File. |-> PLEASE EDIT ME <-|" % + click.echo("%s - Project Configuration File" % click.style( "platformio.ini", fg="cyan")) click.echo("%s - Put your source files here" % click.style( @@ -89,10 +89,6 @@ def cli(ctx, # pylint: disable=R0913 click.style( "lib", fg="cyan")) - if (app.get_setting("enable_prompts") and - not click.confirm("Do you want to continue?")): - raise exception.AbortedByUser() - init_base_project(project_dir) if board: @@ -276,10 +272,21 @@ def init_ci_conf(project_dir): def init_cvs_ignore(project_dir): - if isfile(join(project_dir, ".gitignore")): - return - with open(join(project_dir, ".gitignore"), "w") as f: - f.write(".pioenvs") + ignore_path = join(project_dir, ".gitignore") + default = [ + ".pioenvs\n", + ".piolibdeps\n" + ] + current = [] + if isfile(ignore_path): + with open(ignore_path) as fp: + current = fp.readlines() + print 13, current + for d in default: + if d not in current: + current.append(d) + with open(ignore_path, "w") as fp: + fp.writelines(current) def fill_project_envs( # pylint: disable=too-many-arguments,too-many-locals diff --git a/platformio/projectconftpl.ini b/platformio/projectconftpl.ini index 0e9de3f9..c4b4ae30 100644 --- a/platformio/projectconftpl.ini +++ b/platformio/projectconftpl.ini @@ -1,6 +1,10 @@ # # PlatformIO Project Configuration File # -# Please make sure to read documentation with examples first +# Build options: build flags, source filter, extra scripting +# Upload options: custom port, speed and extra flags +# Library options: dependencies, extra library storages +# +# Please visit documentation for the other options and examples # http://docs.platformio.org/en/stable/projectconf.html -# \ No newline at end of file +# From 0ab7d539913d816bd22ccaed6899f41bbb972a96 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 9 Aug 2016 15:13:55 +0300 Subject: [PATCH 136/284] Add example with Microbit --- examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples b/examples index 4b6ddf48..8f196b57 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 4b6ddf489635f332d4871fd4045634a49ad2aac7 +Subproject commit 8f196b57cb3e6ea94868b406e501da1888b24ea9 From 55c1a90fc91e3ed7ab10c55b8509826efea40364 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 9 Aug 2016 15:24:56 +0300 Subject: [PATCH 137/284] Remove unused import --- platformio/commands/init.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/commands/init.py b/platformio/commands/init.py index 3d271f03..e059b056 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -18,7 +18,7 @@ from shutil import copyfile import click -from platformio import app, exception, util +from platformio import exception, util from platformio.commands.platform import \ platform_install as cli_platform_install from platformio.ide.projectgenerator import ProjectGenerator From bda61d0ae22d423ae16eace39e480056ed37fff4 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 9 Aug 2016 16:53:51 +0300 Subject: [PATCH 138/284] Use semicolons for comment in INI File --- docs/ide/qtcreator.rst | 16 +++++++++------- docs/ide/sublimetext.rst | 16 +++++++++------- docs/ide/visualstudio.rst | 16 +++++++++------- docs/platforms/atmelavr_extra.rst | 4 ++-- docs/platforms/espressif_extra.rst | 4 ++-- docs/projectconf.rst | 12 ++++++------ docs/quickstart.rst | 14 ++++++++------ examples | 2 +- platformio/projectconftpl.ini | 18 ++++++++---------- 9 files changed, 54 insertions(+), 48 deletions(-) diff --git a/docs/ide/qtcreator.rst b/docs/ide/qtcreator.rst index 714d10c7..a40f910a 100644 --- a/docs/ide/qtcreator.rst +++ b/docs/ide/qtcreator.rst @@ -165,14 +165,16 @@ Copy the source code which is described below to file ``main.c``. Edit the content to match the code described below. -.. code-block:: none +.. code-block:: ini - # - # PlatformIO Project Configuration File - # - # Please make sure to read documentation with examples first - # http://docs.platformio.org/en/stable/projectconf.html - # + ; PlatformIO Project Configuration File + ; + ; Build options: build flags, source filter, extra scripting + ; Upload options: custom port, speed and extra flags + ; Library options: dependencies, extra library storages + ; + ; Please visit documentation for the other options and examples + ; http://docs.platformio.org/en/stable/projectconf.html [env:arduino_uno] platform = atmelavr diff --git a/docs/ide/sublimetext.rst b/docs/ide/sublimetext.rst index 7e58b2fc..3342f5d4 100644 --- a/docs/ide/sublimetext.rst +++ b/docs/ide/sublimetext.rst @@ -164,14 +164,16 @@ Let's create new file named ``main.c`` using ``Menu: File > New File`` or shortc 2. Project Configuration File named ``platformio.ini`` must be located in the project root directory. Copy the source code which is described below to it. -.. code-block:: none +.. code-block:: ini - # - # PlatformIO Project Configuration File - # - # Please make sure to read documentation with examples first - # http://docs.platformio.org/en/stable/projectconf.html - # + ; PlatformIO Project Configuration File + ; + ; Build options: build flags, source filter, extra scripting + ; Upload options: custom port, speed and extra flags + ; Library options: dependencies, extra library storages + ; + ; Please visit documentation for the other options and examples + ; http://docs.platformio.org/en/stable/projectconf.html [env:arduino_uno] platform = atmelavr diff --git a/docs/ide/visualstudio.rst b/docs/ide/visualstudio.rst index 46323421..ae58d2f5 100644 --- a/docs/ide/visualstudio.rst +++ b/docs/ide/visualstudio.rst @@ -124,14 +124,16 @@ Copy the source code which is described below to file ``main.cpp``. Copy the source code which is described below to it. -.. code-block:: none +.. code-block:: ini - # - # PlatformIO Project Configuration File - # - # Please make sure to read documentation with examples first - # http://docs.platformio.org/en/stable/projectconf.html - # + ; PlatformIO Project Configuration File + ; + ; Build options: build flags, source filter, extra scripting + ; Upload options: custom port, speed and extra flags + ; Library options: dependencies, extra library storages + ; + ; Please visit documentation for the other options and examples + ; http://docs.platformio.org/en/stable/projectconf.html [env:arduino_uno] platform = atmelavr diff --git a/docs/platforms/atmelavr_extra.rst b/docs/platforms/atmelavr_extra.rst index 7d97a4d8..ac6691bd 100644 --- a/docs/platforms/atmelavr_extra.rst +++ b/docs/platforms/atmelavr_extra.rst @@ -30,7 +30,7 @@ Configuration for the programmers: upload_protocol = stk500v1 upload_flags = -P$UPLOAD_PORT - # edit this line with valid upload port + ; edit this line with valid upload port upload_port = SERIAL_PORT_HERE * AVRISP mkII @@ -91,7 +91,7 @@ Configuration for the programmers: upload_protocol = stk500v1 upload_flags = -P$UPLOAD_PORT -b$UPLOAD_SPEED - # edit these lines + ; edit these lines upload_port = SERIAL_PORT_HERE upload_speed = 19200 diff --git a/docs/platforms/espressif_extra.rst b/docs/platforms/espressif_extra.rst index b6315b4e..16d0343e 100644 --- a/docs/platforms/espressif_extra.rst +++ b/docs/platforms/espressif_extra.rst @@ -17,7 +17,7 @@ See :ref:`projectconf_board_f_cpu` option from :ref:`projectconf` .. code-block:: ini [env:myenv] - # set frequency to 160MHz + ; set frequency to 160MHz board_f_cpu = 160000000L Custom FLASH Frequency @@ -34,7 +34,7 @@ values: .. code-block:: ini [env:myenv] - # set frequency to 80MHz + ; set frequency to 80MHz board_f_flash = 80000000L Custom FLASH Mode diff --git a/docs/projectconf.rst b/docs/projectconf.rst index d0cb2468..dab41cb4 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -440,7 +440,7 @@ Example: build_flags = -Wl,-T/path/to/ld_script.ld [env:exec_command] - # get VCS revision "on-the-fly" + ; get VCS revision "on-the-fly" build_flags = !echo "-DPIO_SRC_REV="$(git rev-parse HEAD) @@ -569,7 +569,7 @@ The list with available targets is located in :option:`platformio run --target`. # clean project platformio run -t clean - # dump curent build environment + # dump current build environment platformio run --target envdump When no targets are defined, *PlatformIO* will build only sources by default. @@ -806,7 +806,7 @@ Examples framework = arduino board = uno - # enable auto-uploading + ; enable auto-uploading targets = upload @@ -821,12 +821,12 @@ Examples board_f_cpu = 16000000L upload_port = /dev/ttyUSB0 - # for Windows OS - # upload_port = COM3 + ; for Windows OS + ; upload_port = COM3 upload_protocol = arduino upload_speed = 19200 - # enable auto-uploading + ; enable auto-uploading targets = upload diff --git a/docs/quickstart.rst b/docs/quickstart.rst index f6d8600b..c3e61cfa 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -145,12 +145,14 @@ The result of just generated ``platformio.ini``: .. code-block:: ini - # - # PlatformIO Project Configuration File - # - # Please make sure to read documentation with examples first - # http://docs.platformio.org/en/stable/projectconf.html - # + ; PlatformIO Project Configuration File + ; + ; Build options: build flags, source filter, extra scripting + ; Upload options: custom port, speed and extra flags + ; Library options: dependencies, extra library storages + ; + ; Please visit documentation for the other options and examples + ; http://docs.platformio.org/en/stable/projectconf.html [env:uno] platform = atmelavr diff --git a/examples b/examples index 8f196b57..3cc5a6cf 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 8f196b57cb3e6ea94868b406e501da1888b24ea9 +Subproject commit 3cc5a6cf883343b41917d036a8673606dfabd945 diff --git a/platformio/projectconftpl.ini b/platformio/projectconftpl.ini index c4b4ae30..fa77ae29 100644 --- a/platformio/projectconftpl.ini +++ b/platformio/projectconftpl.ini @@ -1,10 +1,8 @@ -# -# PlatformIO Project Configuration File -# -# Build options: build flags, source filter, extra scripting -# Upload options: custom port, speed and extra flags -# Library options: dependencies, extra library storages -# -# Please visit documentation for the other options and examples -# http://docs.platformio.org/en/stable/projectconf.html -# +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter, extra scripting +; Upload options: custom port, speed and extra flags +; Library options: dependencies, extra library storages +; +; Please visit documentation for the other options and examples +; http://docs.platformio.org/en/stable/projectconf.html From f1e65869f38cfcba47499c8bbfe2048450b8e3f6 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 9 Aug 2016 16:55:14 +0300 Subject: [PATCH 139/284] Remove "#" from platformio.ini docs --- docs/projectconf.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/projectconf.rst b/docs/projectconf.rst index dab41cb4..57b3ca86 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -18,7 +18,7 @@ The Project configuration file is named ``platformio.ini``. This is a `INI-style `_ file. ``platformio.ini`` has sections (each denoted by a ``[header]``) and -key / value pairs within the sections. Lines beginning with ``#`` or ``;`` +key / value pairs within the sections. Lines beginning with ``;`` are ignored and may be used to provide comments. The sections and their allowable values are described below. From 0264c4eeea29bc64ec9a93cab46cef4d0c715148 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 9 Aug 2016 17:12:30 +0300 Subject: [PATCH 140/284] Remove debug code --- platformio/commands/init.py | 1 - 1 file changed, 1 deletion(-) diff --git a/platformio/commands/init.py b/platformio/commands/init.py index e059b056..8a77a24c 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -281,7 +281,6 @@ def init_cvs_ignore(project_dir): if isfile(ignore_path): with open(ignore_path) as fp: current = fp.readlines() - print 13, current for d in default: if d not in current: current.append(d) From 9177c6f210753cfab86ddb3e526ca88d1711fdbe Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 9 Aug 2016 23:44:40 +0300 Subject: [PATCH 141/284] Fix typo with known default options for [platformio] section --- platformio/commands/run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 3309cf07..95bd4ca6 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -283,7 +283,7 @@ def print_header(label, is_error=False): def check_project_defopts(config): if not config.has_section("platformio"): return True - known = ("home_dir", "lib_dir", "libdeps_dir", "src_dir", "env_dir", + known = ("home_dir", "lib_dir", "libdeps_dir", "src_dir", "envs_dir", "data_dir", "test_dir", "env_default") unknown = set([k for k, _ in config.items("platformio")]) - set(known) if not unknown: From a395b171e3879dd3fe931eba4bd93d5e1ed9091c Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 10 Aug 2016 15:50:01 +0300 Subject: [PATCH 142/284] Add Support for local ("PC") unit tests // Resolve #519 --- HISTORY.rst | 5 +- docs/projectconf.rst | 49 ++++++++++++- docs/unit_testing.rst | 106 +++++++++++++++++++++------ docs/userguide/cmd_test.rst | 10 ++- platformio/__init__.py | 2 +- platformio/builder/tools/piotest.py | 13 +++- platformio/commands/init.py | 10 +-- platformio/commands/run.py | 16 ++-- platformio/commands/test.py | 109 +++++++++++++++++++--------- platformio/managers/platform.py | 11 +-- tests/commands/test_test.py | 26 +++++++ 11 files changed, 269 insertions(+), 88 deletions(-) create mode 100644 tests/commands/test_test.py diff --git a/HISTORY.rst b/HISTORY.rst index 1451fd11..5b7e7d47 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -9,8 +9,9 @@ PlatformIO 3.0 * PlatformIO Plus - + `Unit Testing `__ for Embedded - (`issue #408 `_) + + Local and Embedded `Unit Testing `__ + (`issue #408 `_, + `issue #519 `_) * Decentralized Development Platforms diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 57b3ca86..6ccb5484 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -656,7 +656,7 @@ Multiple dependencies are allowed (multi-lines). .. code-block:: ini - [env:***] + [env:myenv] lib_deps = LIBRARY_1 LIBRARY_2 @@ -784,6 +784,53 @@ Finder. More details :ref:`ldf_compat_mode`. By default, this value is set to ``lib_compat_mode = 1`` and means that LDF will check only for framework compatibility. + +Test options +~~~~~~~~~~~~ + +.. contents:: + :local: + +.. _projectconf_test_ignore: + +``test_ignore`` +^^^^^^^^^^^^^^^ + +.. versionadded:: 3.0 +.. seealso:: + Please make sure to read :ref:`unit_testing` guide first. + +Ignore tests where the name matches specified patterns. +More than one pattern is allowed (multi-lines). Also, you can ignore some +tests using :option:`platformio test --ignore` command. + +.. list-table:: + :header-rows: 1 + + * - Pattern + - Meaning + + * - ``*`` + - matches everything + + * - ``?`` + - matches any single character + + * - ``[seq]`` + - matches any character in seq + + * - ``[!seq]`` + - matches any character not in seq + +**Example** + +.. code-block:: ini + + [env:myenv] + test_ignore = + mytest* + test[13] + ----------- .. _projectconf_examples: diff --git a/docs/unit_testing.rst b/docs/unit_testing.rst index 5e6555a5..e50b6cdb 100644 --- a/docs/unit_testing.rst +++ b/docs/unit_testing.rst @@ -22,19 +22,30 @@ 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. -PlatformIO Test System is very interesting for embedded development. -It allows you to write tests locally and run them directly on the target -device (hardware unit testing). Also, you will be able to run the same tests -on the different target devices (:ref:`embedded_boards`). +PlatformIO Test System supports 2 different test types: + +1. **Local Test** - *[host, native]*, process test on the host machine + using :ref:`platform_native`. +2. **Embedded Test** - *[remote, hardware]*, prepare special firmware for the + target device and upload it. Run test on the embedded device and collect + results. Process test results on the host machine. + + You will be able to run the same test on the different target devices + (:ref:`embedded_boards`). PlatformIO Test System consists of: * Project builder * Test builder -* Firmware uploader +* Firmware uploader (is used only for embedded test) * Test processor There is special command :ref:`cmd_test` to run tests from PlatformIO Project. +It allows to process specific environments or to ignore some tests using +"Glob patterns". + +Also, is possible to ignore some tests for specific environment using +:ref:`projectconf_test_ignore` option from :ref:`projectconf`. .. contents:: @@ -55,38 +66,74 @@ PlatformIO Test System design is based on a few isolated components: Workflow -------- -1. Create PlatformIO project using :ref:`cmd_init` command. +1. Create PlatformIO project using :ref:`cmd_init` command. For Local Unit + Testing (on the host machine), need to use :ref:`platform_native`. + + .. code-block:: ini + + ; PlatformIO Project Configuration File + ; + ; Build options: build flags, source filter, extra scripting + ; Upload options: custom port, speed and extra flags + ; Library options: dependencies, extra library storages + ; + ; Please visit documentation for the other options and examples + ; http://docs.platformio.org/en/stable/projectconf.html + + ; + ; Embedded platforms + ; + + [env:uno] + platform = atmelavr + framework = arduino + board = uno + + [env:nodemcu] + platform = espressif + framework = arduino + board = nodemcuv2 + + ; + ; Local (PC, native) platforms + ; + + [env:local] + platform = native + 2. Place source code of main program to ``src`` directory. 3. Wrap ``main()`` or ``setup()/loop()`` methods of main program in ``UNIT_TEST`` guard: .. code-block:: c - /** + /** * Arduino Wiring-based Framework */ - #ifndef UNIT_TEST - void setup () { + #ifndef UNIT_TEST + #include + void setup () { // some code... - } + } - void loop () { + void loop () { // some code... - } - #endif + } + #endif - /** + /** * Generic C/C++ */ - #ifndef UNIT_TEST - int main() { + #ifndef UNIT_TEST + int main(int argc, char **argv) { // setup code... while (1) { // loop code... } - } - #endif + return 0 + } + #endif 4. Create ``test`` directory in the root of project. See :ref:`projectconf_pio_test_dir`. 5. Write test using :ref:`unit_testing_api`. The each test is a small @@ -183,8 +230,8 @@ The summary of `Unity Test API `_ +* `Local & Embedded: Calculator `_ For the other examples and source code please follow to -`PlatformIO Unit Testing Examples `_ repository. +`PlatformIO Unit Testing Examples `_ repository. diff --git a/docs/userguide/cmd_test.rst b/docs/userguide/cmd_test.rst index c42bda6c..7c74361d 100644 --- a/docs/userguide/cmd_test.rst +++ b/docs/userguide/cmd_test.rst @@ -45,10 +45,12 @@ Options Process specified environments. More details :option:`platformio run --environment` .. option:: - --skip + -i, --ignore -Skip over tests where the name matches specified patterns. More than one -option/pattern is allowed. +Ignore tests where the name matches specified patterns. More than one +pattern is allowed. If you need to ignore some tests for the specific +environment, please take a look at :ref:`projectconf_test_ignore` option from +:ref:`projectconf`. .. list-table:: :header-rows: 1 @@ -68,7 +70,7 @@ option/pattern is allowed. * - ``[!seq]`` - matches any character not in seq -For example, ``platformio test --skip "mytest*" -i "test[13]"`` +For example, ``platformio test --ignore "mytest*" -i "test[13]"`` .. option:: --upload-port diff --git a/platformio/__init__.py b/platformio/__init__.py index e880489e..7114b1f3 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0a3") +VERSION = (3, 0, "0a4") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piotest.py b/platformio/builder/tools/piotest.py index 3789e73f..3b72f7ce 100644 --- a/platformio/builder/tools/piotest.py +++ b/platformio/builder/tools/piotest.py @@ -43,6 +43,14 @@ FRAMEWORK_PARAMETERS = { "serial_flush": "Serial.flush()", "serial_begin": "Serial.begin(9600)", "serial_end": "Serial.end()" + }, + "native": { + "framework": "stdio.h", + "serial_obj": "", + "serial_putc": "putchar(a)", + "serial_flush": "fflush(stdout)", + "serial_begin": "", + "serial_end": "" } } @@ -114,7 +122,10 @@ void output_complete(void) print("Warning: Could not remove temporary file '%s'. " "Please remove it manually." % file_) - framework = env.subst("$PIOFRAMEWORK").lower() + if env['PIOPLATFORM'] == "native": + framework = "native" + else: + framework = env.subst("$PIOFRAMEWORK").lower() if framework not in FRAMEWORK_PARAMETERS: env.Exit("Error: %s framework doesn't support testing feature!" % framework) diff --git a/platformio/commands/init.py b/platformio/commands/init.py index 8a77a24c..1ccc590a 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -80,9 +80,8 @@ def cli(ctx, # pylint: disable=R0913 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 - 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 here project specific (private) libraries" % @@ -273,10 +272,7 @@ def init_ci_conf(project_dir): def init_cvs_ignore(project_dir): ignore_path = join(project_dir, ".gitignore") - default = [ - ".pioenvs\n", - ".piolibdeps\n" - ] + default = [".pioenvs\n", ".piolibdeps\n"] current = [] if isfile(ignore_path): with open(ignore_path) as fp: diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 95bd4ca6..e130393f 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -111,14 +111,14 @@ def cli(ctx, # pylint: disable=R0913,R0914 class EnvironmentProcessor(object): - KNOWN_OPTIONS = ("platform", "framework", "board", "board_mcu", - "board_f_cpu", "board_f_flash", "board_flash_mode", - "build_flags", "src_build_flags", "build_unflags", - "src_filter", "extra_script", "targets", "upload_port", - "upload_protocol", "upload_speed", "upload_flags", - "upload_resetmethod", "lib_install", "lib_deps", - "lib_force", "lib_ignore", "lib_extra_dirs", - "lib_ldf_mode", "lib_compat_mode", "piotest") + KNOWN_OPTIONS = ( + "platform", "framework", "board", "board_mcu", "board_f_cpu", + "board_f_flash", "board_flash_mode", "build_flags", "src_build_flags", + "build_unflags", "src_filter", "extra_script", "targets", + "upload_port", "upload_protocol", "upload_speed", "upload_flags", + "upload_resetmethod", "lib_install", "lib_deps", "lib_force", + "lib_ignore", "lib_extra_dirs", "lib_ldf_mode", "lib_compat_mode", + "test_ignore", "piotest") REMAPED_OPTIONS = {"framework": "pioframework", "platform": "pioplatform"} diff --git a/platformio/commands/test.py b/platformio/commands/test.py index 9ba8e472..a1b73262 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -30,7 +30,7 @@ from platformio.managers.platform import PlatformFactory @click.command("test", short_help="Unit Testing") @click.option("--environment", "-e", multiple=True, metavar="") -@click.option("--skip", multiple=True, metavar="") +@click.option("--ignore", "-i", multiple=True, metavar="") @click.option("--upload-port", metavar="") @click.option( "-d", @@ -44,7 +44,7 @@ from platformio.managers.platform import PlatformFactory resolve_path=True)) @click.option("--verbose", "-v", is_flag=True) @click.pass_context -def cli(ctx, environment, skip, upload_port, project_dir, verbose): +def cli(ctx, environment, ignore, upload_port, project_dir, verbose): with util.cd(project_dir): test_dir = util.get_projecttest_dir() if not isdir(test_dir): @@ -59,19 +59,30 @@ def cli(ctx, environment, skip, upload_port, project_dir, verbose): start_time = time() results = [] for testname in test_names: - for envname in projectconf.sections(): - if not envname.startswith("env:"): + for section in projectconf.sections(): + if not section.startswith("env:"): continue - envname = envname[4:] + + envname = section[4:] if environment and envname not in environment: continue - # check skip patterns - if testname != "*" and any([fnmatch(testname, p) for p in skip]): + # check ignore patterns + _ignore = list(ignore) + if projectconf.has_option(section, "test_ignore"): + _ignore.extend([p.strip() + for p in projectconf.get( + section, "test_ignore").split("\n") + if p.strip()]) + if testname != "*" and \ + any([fnmatch(testname, p) for p in _ignore]): results.append((None, testname, envname)) continue - tp = TestProcessor(ctx, testname, envname, { + cls = (LocalTestProcessor + if projectconf.get(section, "platform") == "native" else + EmbeddedTestProcessor) + tp = cls(ctx, testname, envname, { "project_config": projectconf, "project_dir": project_dir, "upload_port": upload_port, @@ -93,7 +104,7 @@ def cli(ctx, environment, skip, upload_port, project_dir, verbose): status_str = click.style("IGNORED", fg="yellow") click.echo( - "test:%s/env:%s\t%s" % (click.style( + "test:%s/env:%s\t[%s]" % (click.style( testname, fg="yellow"), click.style( envname, fg="cyan"), status_str), err=status is False) @@ -108,10 +119,7 @@ def cli(ctx, environment, skip, upload_port, project_dir, verbose): raise exception.ReturnErrorCode() -class TestProcessor(object): - - SERIAL_TIMEOUT = 600 - SERIAL_BAUDRATE = 9600 +class TestProcessorBase(object): def __init__(self, cmd_ctx, testname, envname, options): self.cmd_ctx = cmd_ctx @@ -119,24 +127,16 @@ class TestProcessor(object): self.test_name = testname self.env_name = envname self.options = options + self._run_failed = False - def process(self): - self._progress("Building... (1/3)") - self._build_or_upload(["test"]) - self._progress("Uploading... (2/3)") - self._build_or_upload(["test", "upload"]) - self._progress("Testing... (3/3)") - sleep(1.0) # wait while board is starting... - return self._run_hardware_test() - - def _progress(self, text, is_error=False): + def print_progress(self, text, is_error=False): print_header( "[test::%s] %s" % (click.style( self.test_name, fg="yellow", bold=True), text), is_error=is_error) click.echo() - def _build_or_upload(self, target): + def build_or_upload(self, target): if self.test_name != "*": self.cmd_ctx.meta['piotest'] = self.test_name return self.cmd_ctx.invoke( @@ -147,7 +147,54 @@ class TestProcessor(object): environment=[self.env_name], target=target) - def _run_hardware_test(self): + def run(self): + raise NotImplementedError + + def on_run_out(self, line): + 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) + + +class LocalTestProcessor(TestProcessorBase): + + def process(self): + self.print_progress("Building... (1/2)") + self.build_or_upload(["test"]) + self.print_progress("Testing... (2/2)") + return self.run() + + def run(self): + with util.cd(self.options['project_dir']): + pioenvs_dir = util.get_projectpioenvs_dir() + result = util.exec_command( + [join(pioenvs_dir, self.env_name, "program")], + stdout=util.AsyncPipe(self.on_run_out), + stderr=util.AsyncPipe(self.on_run_out)) + assert "returncode" in result + return result['returncode'] == 0 and not self._run_failed + + +class EmbeddedTestProcessor(TestProcessorBase): + + SERIAL_TIMEOUT = 600 + SERIAL_BAUDRATE = 9600 + + def process(self): + self.print_progress("Building... (1/3)") + self.build_or_upload(["test"]) + self.print_progress("Uploading... (2/3)") + self.build_or_upload(["test", "upload"]) + self.print_progress("Testing... (3/3)") + sleep(1.0) # wait while board is starting... + 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() @@ -155,23 +202,15 @@ class TestProcessor(object): self.get_serial_port(), self.SERIAL_BAUDRATE, timeout=self.SERIAL_TIMEOUT) - passed = True while True: line = ser.readline().strip() if not line: continue - if line.endswith(":PASS"): - click.echo("%s\t%s" % (line[:-5], click.style( - "PASSED", fg="green"))) - elif ":FAIL:" in line: - passed = False - click.echo("%s\t%s" % (line, click.style("FAILED", fg="red"))) - else: - click.echo(line) + self.on_run_out(line) if all([l in line for l in ("Tests", "Failures", "Ignored")]): break ser.close() - return passed + return not self._run_failed def get_serial_port(self): config = self.options['project_config'] diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index aae99081..8bfee505 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -362,14 +362,15 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): @property def packages(self): - packages = self._manifest.get("packages", {}) - if "tool-scons" not in packages: - packages['tool-scons'] = { + if "packages" not in self._manifest: + self._manifest['packages'] = {} + if "tool-scons" not in self._manifest['packages']: + self._manifest['packages']['tool-scons'] = { "version": self._manifest.get("engines", {}).get( "scons", ">=2.3.0,<2.6.0"), "optional": False } - return packages + return self._manifest['packages'] def get_dir(self): return dirname(self.manifest_path) @@ -476,7 +477,7 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): if "test" in targets and "tool-unity" not in self.packages: self.packages['tool-unity'] = { - "version": "~1.20302.0", + "version": "~1.20302.1", "optional": False } diff --git a/tests/commands/test_test.py b/tests/commands/test_test.py new file mode 100644 index 00000000..482f20f4 --- /dev/null +++ b/tests/commands/test_test.py @@ -0,0 +1,26 @@ +# Copyright 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from os.path import join + +from platformio.commands.test import cli as cli_test + + +def test_local_env(clirunner, validate_cliresult): + result = clirunner.invoke( + cli_test, + ["-d", join("examples", "unit-testing", "calculator"), "-e", "local"]) + result.exit_code == -1 + assert all( + [s in result.output for s in ("[PASSED]", "[IGNORED]", "[FAILED]")]) From ef0322019f2410cf6d59eb61a6daf2011b18653a Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 10 Aug 2016 15:51:53 +0300 Subject: [PATCH 143/284] Add Unit Testing example with Calculator // Issue #519 --- examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples b/examples index 3cc5a6cf..3f42a778 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 3cc5a6cf883343b41917d036a8673606dfabd945 +Subproject commit 3f42a7788101a0d57c934d2ab0d07158b6333a94 From 4b50a9c7211e61d64088895f83537920d258f734 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 10 Aug 2016 16:10:26 +0300 Subject: [PATCH 144/284] Skip Calculator example from generic test --- examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples b/examples index 3f42a778..db884f2f 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 3f42a7788101a0d57c934d2ab0d07158b6333a94 +Subproject commit db884f2fcfb88926d176ac09cbb4e0a72087d351 From 6ac2abfc3bc59cb96a0efff9e5995964edb5224d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 10 Aug 2016 17:15:51 +0300 Subject: [PATCH 145/284] Fix docs warning --- docs/unit_testing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/unit_testing.rst b/docs/unit_testing.rst index e50b6cdb..93883fee 100644 --- a/docs/unit_testing.rst +++ b/docs/unit_testing.rst @@ -454,4 +454,4 @@ Examples * `Local & Embedded: Calculator `_ For the other examples and source code please follow to -`PlatformIO Unit Testing Examples `_ repository. +`PlatformIO Unit Testing Examples `__ repository. From 9299b6716a4123b46e99088ce0d9738e036af5db Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 10 Aug 2016 17:50:02 +0300 Subject: [PATCH 146/284] Fix broken link to Unit Testing examples --- docs/unit_testing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/unit_testing.rst b/docs/unit_testing.rst index 93883fee..1ea3e74c 100644 --- a/docs/unit_testing.rst +++ b/docs/unit_testing.rst @@ -454,4 +454,4 @@ Examples * `Local & Embedded: Calculator `_ For the other examples and source code please follow to -`PlatformIO Unit Testing Examples `__ repository. +`PlatformIO Unit Testing Examples `_ repository. From 3ba0d25f277589f51b2041f57cefcef14e2fba5b Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 10 Aug 2016 19:39:17 +0300 Subject: [PATCH 147/284] Fix updating project libraries // Resolve #745 --- platformio/commands/lib.py | 10 +++-- platformio/managers/package.py | 5 ++- tests/commands/test_lib.py | 68 ++++++++++++++++++++++++++-------- 3 files changed, 63 insertions(+), 20 deletions(-) diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index 67c8ff59..e77a9641 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -47,8 +47,11 @@ def cli(ctx, **options): (len(ctx.args) == 2 and ctx.args[1] in ("-h", "--help")): return storage_dir = options['storage_dir'] - if not storage_dir and options['global']: - storage_dir = join(util.get_home_dir(), "lib") + 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() if not storage_dir and not util.is_platformio_project(): raise exception.PlatformioException( @@ -59,7 +62,8 @@ def cli(ctx, **options): ctx.invoked_subcommand)) ctx.obj = LibraryManager(storage_dir) - click.echo("Library Storage: " + storage_dir) + if "--json-output" not in ctx.args: + click.echo("Library Storage: " + storage_dir) @cli.command("install", short_help="Install library") diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 0a51dcd8..d271de15 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -357,7 +357,10 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): return BasePkgManager._INSTALLED_CACHE[self.package_dir] items = [] for p in sorted(os.listdir(self.package_dir)): - manifest = self.load_manifest(join(self.package_dir, p)) + pkg_dir = join(self.package_dir, p) + if not isdir(pkg_dir): + continue + manifest = self.load_manifest(pkg_dir) if not manifest: continue assert set(["name", "version"]) <= set(manifest.keys()) diff --git a/tests/commands/test_lib.py b/tests/commands/test_lib.py index 994417a4..08063b7d 100644 --- a/tests/commands/test_lib.py +++ b/tests/commands/test_lib.py @@ -12,18 +12,23 @@ # See the License for the specific language governing permissions and # limitations under the License. +import json import re +from os.path import basename -from platformio.commands.lib import cli +from platformio import util +from platformio.commands.init import cli as cmd_init +from platformio.commands.lib import cli as cmd_lib def test_search(clirunner, validate_cliresult): - result = clirunner.invoke(cli, ["search", "DHT22"]) + result = clirunner.invoke(cmd_lib, ["search", "DHT22"]) validate_cliresult(result) match = re.search(r"Found\s+(\d+)\slibraries:", result.output) assert int(match.group(1)) > 2 - result = clirunner.invoke(cli, ["search", "DHT22", "--platform=timsp430"]) + result = clirunner.invoke(cmd_lib, + ["search", "DHT22", "--platform=timsp430"]) validate_cliresult(result) match = re.search(r"Found\s+(\d+)\slibraries:", result.output) assert int(match.group(1)) == 1 @@ -32,7 +37,7 @@ def test_search(clirunner, validate_cliresult): def test_global_install_registry(clirunner, validate_cliresult, isolated_pio_home): result = clirunner.invoke( - cli, ["-g", "install", "58", "OneWire", "Json@5.4.0", "Json@>5.4"]) + cmd_lib, ["-g", "install", "58", "OneWire", "Json@5.4.0", "Json@>5.4"]) validate_cliresult(result) items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] items2 = ["DHT22_ID58", "Json_ID64", "Json_ID64@5.4.0", "OneWire_ID1"] @@ -42,10 +47,10 @@ def test_global_install_registry(clirunner, validate_cliresult, def test_global_install_repository(clirunner, validate_cliresult, isolated_pio_home): result = clirunner.invoke( - cli, ["-g", "install", "https://github.com/gioblu/PJON.git#3.0", - "https://developer.mbed.org/users/simon/code/TextLCD/", - "http://dl.platformio.org/libraries/archives/3/3756.tar.gz", - "knolleary/pubsubclient"]) + cmd_lib, ["-g", "install", "https://github.com/gioblu/PJON.git#3.0", + "https://developer.mbed.org/users/simon/code/TextLCD/", + "http://dl.platformio.org/libraries/archives/3/3756.tar.gz", + "knolleary/pubsubclient"]) validate_cliresult(result) items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] items2 = ["PJON", "TextLCD", "ESPAsyncTCP", "PubSubClient"] @@ -53,36 +58,39 @@ def test_global_install_repository(clirunner, validate_cliresult, def test_global_lib_list(clirunner, validate_cliresult, isolated_pio_home): - result = clirunner.invoke(cli, ["-g", "list"]) + result = clirunner.invoke(cmd_lib, ["-g", "list"]) validate_cliresult(result) assert all([n in result.output for n in ("OneWire", "DHT22", "64")]) - result = clirunner.invoke(cli, ["-g", "list", "--json-output"]) - validate_cliresult(result) + result = clirunner.invoke(cmd_lib, ["-g", "list", "--json-output"]) assert all( [n in result.output for n in ("PJON", "https://developer.mbed.org/users/simon/code/TextLCD/")]) + items1 = [i['name'] for i in json.loads(result.output)] + items2 = ["OneWire", "DHT22", "PJON", "ESPAsyncTCP", "Json", "TextLCD", + "pubsubclient"] + assert set(items1) == set(items2) def test_global_lib_show(clirunner, validate_cliresult, isolated_pio_home): - result = clirunner.invoke(cli, ["-g", "show", "64@5.4.0"]) + result = clirunner.invoke(cmd_lib, ["-g", "show", "64@5.4.0"]) validate_cliresult(result) assert all( [s in result.output for s in ("Json", "arduino", "atmelavr", "5.4.0")]) - result = clirunner.invoke(cli, ["-g", "show", "Json@>5.4.0"]) + result = clirunner.invoke(cmd_lib, ["-g", "show", "Json@>5.4.0"]) validate_cliresult(result) assert all([s in result.output for s in ("Json", "arduino", "atmelavr")]) assert "5.4.0" not in result.output - result = clirunner.invoke(cli, ["-g", "show", "1"]) + result = clirunner.invoke(cmd_lib, ["-g", "show", "1"]) validate_cliresult(result) assert "OneWire" in result.output def test_global_lib_update(clirunner, validate_cliresult, isolated_pio_home): - result = clirunner.invoke(cli, ["-g", "update"]) + result = clirunner.invoke(cmd_lib, ["-g", "update"]) validate_cliresult(result) assert all([s in result.output for s in ("[Up-to-date]", "[VCS]")]) @@ -90,9 +98,37 @@ def test_global_lib_update(clirunner, validate_cliresult, isolated_pio_home): def test_global_lib_uninstall(clirunner, validate_cliresult, isolated_pio_home): result = clirunner.invoke( - cli, ["-g", "uninstall", "1", "Json@!=5.4.0", "TextLCD"]) + cmd_lib, ["-g", "uninstall", "1", "Json@!=5.4.0", "TextLCD"]) validate_cliresult(result) items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] items2 = ["DHT22_ID58", "Json_ID64@5.4.0", "ESPAsyncTCP_ID305", "pubsubclient", "PJON"] assert set(items1) == set(items2) + + +def test_project_lib_complex(clirunner, validate_cliresult, tmpdir): + with util.cd(str(tmpdir)): + # init + result = clirunner.invoke(cmd_init) + validate_cliresult(result) + + # isntall + result = clirunner.invoke(cmd_lib, ["install", "54", "Json"]) + validate_cliresult(result) + items1 = [d.basename + for d in tmpdir.join(basename(util.get_projectlibdeps_dir( + ))).listdir()] + items2 = ["DallasTemperature_ID54", "OneWire_ID1", "Json_ID64"] + assert set(items1) == set(items2) + + # list + result = clirunner.invoke(cmd_lib, ["list", "--json-output"]) + validate_cliresult(result) + items1 = [i['name'] for i in json.loads(result.output)] + items2 = ["DallasTemperature", "OneWire", "Json"] + assert set(items1) == set(items2) + + # update + result = clirunner.invoke(cmd_lib, ["update"]) + validate_cliresult(result) + assert "[Up-to-date]" in result.output From 473c8211326fe3ee3f250c7a0f8212f5e9ae2872 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 10 Aug 2016 21:58:12 +0300 Subject: [PATCH 148/284] Cover init command with tests --- platformio/commands/init.py | 1 + tests/commands/test_init.py | 87 +++++++++++++++++++++++++++---------- tests/commands/test_lib.py | 2 +- 3 files changed, 65 insertions(+), 25 deletions(-) diff --git a/platformio/commands/init.py b/platformio/commands/init.py index 1ccc590a..2f6482b2 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -312,6 +312,7 @@ def fill_project_envs( # pylint: disable=too-many-arguments,too-many-locals used_platforms.append(manifest['platform']) if id_ in used_boards: continue + used_boards.append(id_) content.append("") content.append("[env:%s%s]" % (env_prefix, id_)) diff --git a/tests/commands/test_init.py b/tests/commands/test_init.py index 9c8c1189..6a9984b9 100644 --- a/tests/commands/test_init.py +++ b/tests/commands/test_init.py @@ -16,9 +16,9 @@ import json from os import getcwd, makedirs from os.path import getsize, isdir, isfile, join -from platformio import util +from platformio import util, exception from platformio.commands.boards import cli as cmd_boards -from platformio.commands.init import cli +from platformio.commands.init import cli as cmd_init def validate_pioproject(pioproject_dir): @@ -28,33 +28,74 @@ def validate_pioproject(pioproject_dir): join(pioproject_dir, "lib")) -def test_init_default(platformio_setup, clirunner, validate_cliresult): +def test_init_default(clirunner, validate_cliresult): with clirunner.isolated_filesystem(): - result = clirunner.invoke(cli) + result = clirunner.invoke(cmd_init) validate_cliresult(result) validate_pioproject(getcwd()) -def test_init_ext_folder(platformio_setup, clirunner, validate_cliresult): +def test_init_ext_folder(clirunner, validate_cliresult): with clirunner.isolated_filesystem(): ext_folder_name = "ext_folder" makedirs(ext_folder_name) - result = clirunner.invoke(cli, ["-d", ext_folder_name]) + result = clirunner.invoke(cmd_init, ["-d", ext_folder_name]) validate_cliresult(result) validate_pioproject(join(getcwd(), ext_folder_name)) -def test_init_ide_eclipse(platformio_setup, clirunner, validate_cliresult): +def test_init_duplicated_boards(clirunner, validate_cliresult, tmpdir): + with tmpdir.as_cwd(): + for _ in range(2): + result = clirunner.invoke(cmd_init, ["-b", "uno", "-b", "uno"]) + validate_cliresult(result) + validate_pioproject(str(tmpdir)) + config = util.load_project_config() + assert set(config.sections()) == set(["env:uno"]) + + +def test_init_ide_without_board(clirunner, validate_cliresult, tmpdir): + with tmpdir.as_cwd(): + result = clirunner.invoke(cmd_init, ["--ide", "atom"]) + assert result.exit_code == -1 + assert isinstance(result.exception, exception.BoardNotDefined) + + +def test_init_ide_atom(clirunner, validate_cliresult, tmpdir): + with tmpdir.as_cwd(): + result = clirunner.invoke( + cmd_init, ["--ide", "atom", "-b", "uno", "-b", "teensy31"]) + validate_cliresult(result) + validate_pioproject(str(tmpdir)) + assert all([tmpdir.join(f).check() + for f in (".clang_complete", ".gcc-flags.json")]) + assert "arduinoavr" in tmpdir.join(".clang_complete").read() + + # switch to NodeMCU + result = clirunner.invoke( + cmd_init, ["--ide", "atom", "-b", "nodemcuv2", "-b", "uno"]) + validate_cliresult(result) + validate_pioproject(str(tmpdir)) + assert "arduinoespressif" in tmpdir.join(".clang_complete").read() + + # switch to the first board + result = clirunner.invoke(cmd_init, ["--ide", "atom"]) + validate_cliresult(result) + validate_pioproject(str(tmpdir)) + assert "arduinoavr" in tmpdir.join(".clang_complete").read() + + +def test_init_ide_eclipse(clirunner, validate_cliresult): with clirunner.isolated_filesystem(): - result = clirunner.invoke(cli, ["-b", "uno", "--ide", "eclipse"]) + result = clirunner.invoke(cmd_init, ["-b", "uno", "--ide", "eclipse"]) validate_cliresult(result) validate_pioproject(getcwd()) assert all([isfile(f) for f in (".cproject", ".project")]) -def test_init_special_board(platformio_setup, clirunner, validate_cliresult): +def test_init_special_board(clirunner, validate_cliresult): with clirunner.isolated_filesystem(): - result = clirunner.invoke(cli, ["-b", "uno"]) + result = clirunner.invoke(cmd_init, ["-b", "uno"]) validate_cliresult(result) validate_pioproject(getcwd()) @@ -65,36 +106,34 @@ def test_init_special_board(platformio_setup, clirunner, validate_cliresult): config = util.load_project_config() expected_result = [ ("platform", str(boards[0]['platform'])), - ("framework", str(boards[0]['frameworks'][0])), - ("board", "uno") + ("framework", str(boards[0]['frameworks'][0])), ("board", "uno") ] assert config.has_section("env:uno") - assert len(set(expected_result).symmetric_difference( - set(config.items("env:uno")))) == 0 + assert len( + set(expected_result).symmetric_difference( + set(config.items("env:uno")))) == 0 -def test_init_enable_auto_uploading(platformio_setup, clirunner, - validate_cliresult): +def test_init_enable_auto_uploading(clirunner, validate_cliresult): with clirunner.isolated_filesystem(): - result = clirunner.invoke(cli, + result = clirunner.invoke(cmd_init, ["-b", "uno", "--enable-auto-uploading"]) validate_cliresult(result) validate_pioproject(getcwd()) config = util.load_project_config() expected_result = [ - ("platform", "atmelavr"), - ("framework", "arduino"), - ("board", "uno"), - ("targets", "upload") + ("platform", "atmelavr"), ("framework", "arduino"), + ("board", "uno"), ("targets", "upload") ] assert config.has_section("env:uno") - assert len(set(expected_result).symmetric_difference( - set(config.items("env:uno")))) == 0 + assert len( + set(expected_result).symmetric_difference( + set(config.items("env:uno")))) == 0 def test_init_incorrect_board(clirunner): - result = clirunner.invoke(cli, ["-b", "missed_board"]) + result = clirunner.invoke(cmd_init, ["-b", "missed_board"]) assert result.exit_code == 2 assert 'Error: Invalid value for "-b" / "--board' in result.output assert isinstance(result.exception, SystemExit) diff --git a/tests/commands/test_lib.py b/tests/commands/test_lib.py index 08063b7d..9bd5b8ec 100644 --- a/tests/commands/test_lib.py +++ b/tests/commands/test_lib.py @@ -107,7 +107,7 @@ def test_global_lib_uninstall(clirunner, validate_cliresult, def test_project_lib_complex(clirunner, validate_cliresult, tmpdir): - with util.cd(str(tmpdir)): + with tmpdir.as_cwd(): # init result = clirunner.invoke(cmd_init) validate_cliresult(result) From d3e2b2bde4b05bdca28f5ff086e6117784522d41 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 10 Aug 2016 23:00:46 +0300 Subject: [PATCH 149/284] Cover CI command with tests --- platformio/commands/ci.py | 3 ++- tests/commands/test_ci.py | 54 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 tests/commands/test_ci.py diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index c7da3943..038943c3 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -52,7 +52,8 @@ def validate_path(ctx, param, value): # pylint: disable=W0613 @click.command("ci", short_help="Continuous Integration") @click.argument("src", nargs=-1, callback=validate_path) -@click.option("-l", "--lib", multiple=True, callback=validate_path) +@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) diff --git a/tests/commands/test_ci.py b/tests/commands/test_ci.py new file mode 100644 index 00000000..290c9720 --- /dev/null +++ b/tests/commands/test_ci.py @@ -0,0 +1,54 @@ +# Copyright 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from os.path import join + +from platformio import exception +from platformio.commands.ci import cli as cmd_ci + + +def test_ci_empty(clirunner): + result = clirunner.invoke(cmd_ci) + assert result.exit_code == -1 + assert isinstance(result.exception, exception.CIBuildEnvsEmpty) + + +def test_ci_boards(clirunner, validate_cliresult): + result = clirunner.invoke(cmd_ci, [ + join("examples", "atmelavr-and-arduino", "arduino-internal-libs", + "src", "ChatServer.ino"), "-b", "uno", "-b", "leonardo" + ]) + validate_cliresult(result) + + +def test_ci_project_conf(clirunner, validate_cliresult): + project_dir = join("examples", "atmelavr-and-arduino", + "arduino-internal-libs") + result = clirunner.invoke(cmd_ci, [ + join(project_dir, "src", "ChatServer.ino"), "--project-conf", + join(project_dir, "platformio.ini") + ]) + validate_cliresult(result) + assert all([s in result.output for s in ("ethernet", "leonardo", "yun")]) + + +def test_ci_lib_and_board(clirunner, validate_cliresult): + example_dir = join("examples", "atmelavr-and-arduino", + "arduino-external-libs") + result = clirunner.invoke(cmd_ci, [ + join(example_dir, "lib", "OneWire", "examples", "DS2408_Switch", + "DS2408_Switch.pde"), "-l", join(example_dir, "lib", "OneWire"), + "-b", "uno" + ]) + validate_cliresult(result) From 30f6d456af827d1e2bc75f51629602fd4fa07dc2 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 11 Aug 2016 10:54:28 +0300 Subject: [PATCH 150/284] Update platform command --- platformio/telemetry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/telemetry.py b/platformio/telemetry.py index 964cc707..b863f862 100644 --- a/platformio/telemetry.py +++ b/platformio/telemetry.py @@ -118,7 +118,7 @@ class MeasurementProtocol(TelemetryBase): args = [str(s).lower() for s in ctx_args if not str(s).startswith("-")] if not args: return - if args[0] in ("lib", "platforms", "serialports", "settings"): + if args[0] in ("lib", "platform", "serialports", "settings"): cmd_path = args[:2] else: cmd_path = args[:1] From 3eadadf63882ec3cef7e87c60a43de7926079600 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 11 Aug 2016 12:41:03 +0300 Subject: [PATCH 151/284] Improve CI command for Windows OS --- platformio/builder/tools/piolib.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 795f72e6..0ffda5e3 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -19,6 +19,7 @@ from __future__ import absolute_import import os import sys from os.path import basename, commonprefix, isdir, isfile, join, realpath, sep +from platform import system import SCons.Scanner @@ -94,7 +95,12 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes return "%s(%r)" % (self.__class__, self.path) def __contains__(self, path): - return commonprefix((self.path + sep, path)) == self.path + sep + p1 = self.path + p2 = path + if system() == "Windows": + p1 = p1.lower() + p2 = p2.lower() + return commonprefix((p1 + sep, p2)) == p1 + sep @property def name(self): From 31fdc76f253b9e923eaf6ae19a24c142e6792c93 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 11 Aug 2016 15:23:36 +0300 Subject: [PATCH 152/284] Implement "LIBSOURCE_EXTRA" environment variable for extra libraries --- platformio/builder/tools/piolib.py | 45 +++++++++++++++++++----------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 0ffda5e3..37929d81 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -460,6 +460,26 @@ def GetLibBuilders(env): compat_mode = int(env.get("LIB_COMPAT_MODE", 1)) verbose = not (env.GetOption("silent") or env.GetOption('clean')) + def _init_lib_builder(src_dir): + lb = LibBuilderFactory.new(env, src_dir) + if lb.name in env.get("LIB_IGNORE", []): + if verbose: + sys.stderr.write("Ignored library %s\n" % lb.path) + return + if compat_mode > 1 and not lb.is_platform_compatible(env[ + 'PIOPLATFORM']): + if verbose: + sys.stderr.write("Platform incompatible library %s\n" % + lb.path) + return + if compat_mode > 0 and not any([lb.is_framework_compatible(f) + for f in env_frameworks]): + if verbose: + sys.stderr.write("Framework incompatible library %s\n" % + lb.path) + return + return lb + for libs_dir in env['LIBSOURCE_DIRS']: libs_dir = env.subst(libs_dir) if not isdir(libs_dir): @@ -467,24 +487,15 @@ def GetLibBuilders(env): for item in sorted(os.listdir(libs_dir)): if item == "__cores__" or not isdir(join(libs_dir, item)): continue - lb = LibBuilderFactory.new(env, join(libs_dir, item)) - if lb.name in env.get("LIB_IGNORE", []): - if verbose: - sys.stderr.write("Ignored library %s\n" % lb.path) - continue - if compat_mode > 1 and not lb.is_platform_compatible(env[ - 'PIOPLATFORM']): - if verbose: - sys.stderr.write("Platform incompatible library %s\n" % - lb.path) - continue - if compat_mode > 0 and not any([lb.is_framework_compatible(f) - for f in env_frameworks]): - if verbose: - sys.stderr.write("Framework incompatible library %s\n" % - lb.path) - continue + lb = _init_lib_builder(join(libs_dir, item)) + if lb: + items += (lb, ) + + for lib_dir in env.get("LIBSOURCE_EXTRA", []): + lb = _init_lib_builder(lib_dir) + if lb: items += (lb, ) + return items From 9a959a0aa486c741b6875bfdfe329226ac8f5f34 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 11 Aug 2016 19:20:54 +0300 Subject: [PATCH 153/284] Cover maintenance operations with tests --- platformio/commands/upgrade.py | 2 +- platformio/maintenance.py | 2 +- platformio/managers/platform.py | 3 +- tests/test_maintenance.py | 193 ++++++++++++++++++++++++++++++++ 4 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 tests/test_maintenance.py diff --git a/platformio/commands/upgrade.py b/platformio/commands/upgrade.py index 93f82e6c..5f81807d 100644 --- a/platformio/commands/upgrade.py +++ b/platformio/commands/upgrade.py @@ -89,7 +89,7 @@ WARNING! Don't use `sudo` for the rest PlatformIO commands. def get_latest_version(): try: - if not isinstance(VERSION[2], int): + if not str(VERSION[2]).isdigit(): try: return get_develop_latest_version() except: # pylint: disable=bare-except diff --git a/platformio/maintenance.py b/platformio/maintenance.py index 0f959a23..0d6ac489 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -75,7 +75,7 @@ class Upgrader(object): util.pepver_to_semver(to_version)) self._upgraders = [ - (semantic_version.Version("3.0.0"), self._upgrade_to_3_0_0) + (semantic_version.Version("3.0.0-a1"), self._upgrade_to_3_0_0) ] def run(self, ctx): diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 8bfee505..00af2d37 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -524,7 +524,8 @@ class PlatformBoardConfig(object): "name": self._manifest['name'], "platform": self._manifest.get("platform"), "mcu": self._manifest.get("build", {}).get("mcu", "").upper(), - "fcpu": int(self._manifest.get("build", {}).get("f_cpu", "")[:-1]), + "fcpu": + int(self._manifest.get("build", {}).get("f_cpu", "0L")[:-1]), "ram": self._manifest.get("upload", {}).get("maximum_ram_size", 0), "rom": self._manifest.get("upload", {}).get("maximum_size", 0), "frameworks": self._manifest.get("frameworks"), diff --git a/tests/test_maintenance.py b/tests/test_maintenance.py new file mode 100644 index 00000000..d444fe1c --- /dev/null +++ b/tests/test_maintenance.py @@ -0,0 +1,193 @@ +# Copyright 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +from time import time + +from platformio import app, maintenance +from platformio.__main__ import cli as cli_pio +from platformio.commands import upgrade as cmd_upgrade +from platformio.managers.platform import PlatformManager + + +def test_after_upgrade_2_to_3(clirunner, validate_cliresult, + isolated_pio_home): + app.set_state_item("last_version", "2.11.2") + app.set_state_item("installed_platforms", ["native"]) + + # generate PlatformIO 2.0 boards + boards = isolated_pio_home.mkdir("boards") + board_ids = set() + for prefix in ("foo", "bar"): + data = {} + for i in range(3): + board_id = "board_%s_%d" % (prefix, i) + board_ids.add(board_id) + data[board_id] = { + "name": "Board %s #%d" % (prefix, i), + "url": "", + "vendor": "" + } + boards.join(prefix + ".json").write(json.dumps(data)) + + result = clirunner.invoke(cli_pio, ["settings", "get"]) + validate_cliresult(result) + assert "upgraded to 3" + assert isolated_pio_home.join("platforms", "native", + "platform.json").check() + + # check PlatformIO 3.0 boards + assert board_ids == set([p.basename[:-5] for p in boards.listdir()]) + + result = clirunner.invoke(cli_pio, + ["boards", "--installed", "--json-output"]) + validate_cliresult(result) + assert board_ids == set([b['id'] for b in json.loads(result.output)]) + + +def test_after_upgrade_silence(clirunner, validate_cliresult, + isolated_pio_home): + app.set_state_item("last_version", "2.11.2") + result = clirunner.invoke(cli_pio, ["boards", "--json-output"]) + validate_cliresult(result) + boards = json.loads(result.output) + assert any([b['id'] == "uno" for b in boards]) + + +def test_check_pio_upgrade(clirunner, validate_cliresult, isolated_pio_home): + + def _patch_pio_version(version): + maintenance.__version__ = version + cmd_upgrade.VERSION = version.split(".", 3) + + interval = int(app.get_setting("check_platformio_interval")) * 3600 * 24 + last_check = {"platformio_upgrade": time() - interval - 1} + origin_version = maintenance.__version__ + + # check development version + _patch_pio_version("3.0.0-a1") + app.set_state_item("last_check", last_check) + result = clirunner.invoke(cli_pio, ["platform", "list"]) + validate_cliresult(result) + assert "There is a new version" in result.output + assert "Please upgrade" in result.output + + # check stable version + _patch_pio_version("2.11.0") + app.set_state_item("last_check", last_check) + result = clirunner.invoke(cli_pio, ["platform", "list"]) + validate_cliresult(result) + assert "There is a new version" in result.output + assert "Please upgrade" in result.output + + # restore original version + _patch_pio_version(origin_version) + + +def test_check_lib_updates(clirunner, validate_cliresult, isolated_pio_home): + # install obsolete library + result = clirunner.invoke(cli_pio, ["lib", "-g", "install", "Json@<5.4"]) + validate_cliresult(result) + + # reset check time + interval = int(app.get_setting("check_libraries_interval")) * 3600 * 24 + last_check = {"libraries_update": time() - interval - 1} + app.set_state_item("last_check", last_check) + + result = clirunner.invoke(cli_pio, ["lib", "-g", "list"]) + validate_cliresult(result) + assert "There are the new updates for libraries (Json)" in result.output + + +def test_check_and_update_libraries(clirunner, validate_cliresult, + isolated_pio_home): + # enable library auto-updates + result = clirunner.invoke( + cli_pio, ["settings", "set", "auto_update_libraries", "Yes"]) + + # reset check time + interval = int(app.get_setting("check_libraries_interval")) * 3600 * 24 + last_check = {"libraries_update": time() - interval - 1} + app.set_state_item("last_check", last_check) + + # fetch installed version + result = clirunner.invoke(cli_pio, ["lib", "-g", "list", "--json-output"]) + validate_cliresult(result) + prev_data = json.loads(result.output) + assert len(prev_data) == 1 + + # initiate auto-updating + result = clirunner.invoke(cli_pio, ["lib", "-g", "show", "Json"]) + validate_cliresult(result) + assert "There are the new updates for libraries (Json)" in result.output + assert "Please wait while updating libraries" in result.output + assert "[Out-of-date]" in result.output + + # check updated version + result = clirunner.invoke(cli_pio, ["lib", "-g", "list", "--json-output"]) + validate_cliresult(result) + assert prev_data[0]['version'] != json.loads(result.output)[0]['version'] + + +def test_check_platform_updates(clirunner, validate_cliresult, + isolated_pio_home): + # install obsolete platform + result = clirunner.invoke(cli_pio, ["platform", "install", "native"]) + validate_cliresult(result) + manifest_path = isolated_pio_home.join("platforms", "native", + "platform.json") + manifest = json.loads(manifest_path.read()) + manifest['version'] = "0.0.0" + manifest_path.write(json.dumps(manifest)) + # reset cached manifests + PlatformManager().reset_cache() + + # reset check time + interval = int(app.get_setting("check_platforms_interval")) * 3600 * 24 + last_check = {"platforms_update": time() - interval - 1} + app.set_state_item("last_check", last_check) + + result = clirunner.invoke(cli_pio, ["platform", "list"]) + validate_cliresult(result) + assert "There are the new updates for platforms (native)" in result.output + + +def test_check_and_update_platforms(clirunner, validate_cliresult, + isolated_pio_home): + # enable library auto-updates + result = clirunner.invoke( + cli_pio, ["settings", "set", "auto_update_platforms", "Yes"]) + + # reset check time + interval = int(app.get_setting("check_platforms_interval")) * 3600 * 24 + last_check = {"platforms_update": time() - interval - 1} + app.set_state_item("last_check", last_check) + + # fetch installed version + result = clirunner.invoke(cli_pio, ["platform", "list", "--json-output"]) + validate_cliresult(result) + prev_data = json.loads(result.output) + assert len(prev_data) == 1 + + # initiate auto-updating + result = clirunner.invoke(cli_pio, ["platform", "show", "native"]) + validate_cliresult(result) + assert "There are the new updates for platforms (native)" in result.output + assert "Please wait while updating platforms" in result.output + assert "[Out-of-date]" in result.output + + # check updated version + result = clirunner.invoke(cli_pio, ["platform", "list", "--json-output"]) + validate_cliresult(result) + assert prev_data[0]['version'] != json.loads(result.output)[0]['version'] From d28e8a06b51748024cf35a762873af12c0e3aee6 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 11 Aug 2016 20:55:18 +0300 Subject: [PATCH 154/284] Add new article --- docs/articles.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/articles.rst b/docs/articles.rst index 30ef007f..026c1b44 100644 --- a/docs/articles.rst +++ b/docs/articles.rst @@ -23,6 +23,7 @@ Here are recent articles about PlatformIO: 2016 ^^^^ +* Jul 26, 2016 - **Embedded Systems Laboratory** - `แนะนำการใช้งาน PlatformIO IDE สำหรับบอร์ด Arduino และ ESP8266 (Get started with PlatformIO IDE for Arduino board and ESP8266, Thai) `_ * Jul 5, 2016 - **Ivan Kravets, Ph.D.** - `Explore the new development instruments for Arduino with PlatformIO ecosystem `_ * Jul 5, 2016 - **Belinda** - `Monte Bianco Arduino Developer Summit `_ * Jul 1, 2016 - **Tam Hanna** - `Mikrocontroller-Gipfel in den Alpen: Arduino Developer Summit, Tag eins (Microcontroller peaks in the Alps: Arduino Developer Summit, Day One, German) `_ From 317c7272cd4e7fba646520776bced8092f8c21c9 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 13 Aug 2016 10:33:03 +0300 Subject: [PATCH 155/284] Explain how to use "uploading" with CI command // Resolve #686 --- docs/projectconf.rst | 2 ++ docs/userguide/cmd_ci.rst | 33 ++++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 6ccb5484..16e352d6 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -553,6 +553,8 @@ Example, specify own upload command for :ref:`platform_atmelavr`: - `#351 Specific reset method for ESP8266 `_ - `#247 Specific options for avrdude `_. +.. _projectconf_targets: + ``targets`` ^^^^^^^^^^^ diff --git a/docs/userguide/cmd_ci.rst b/docs/userguide/cmd_ci.rst index 283744c6..72d647c2 100644 --- a/docs/userguide/cmd_ci.rst +++ b/docs/userguide/cmd_ci.rst @@ -35,19 +35,34 @@ with the build environments (using :option:`platformio ci --board` or :option:`platformio ci --project-conf`) and processes them via :ref:`cmd_run` command. +:ref:`cmd_ci` command accepts **multiple** ``SRC`` arguments, +:option:`platformio ci --lib` and :option:`platformio ci --exclude` options +which can be a path to directory, file or +`Glob Pattern `_. +Also, you can omit ``SRC`` argument and set path (multiple paths are allowed +denoting with ``:``) to +``PLATFORMIO_CI_SRC`` `Environment variable `_ + For more details as for integration with the popular Continuous Integration Systems please follow to :ref:`ci` page. .. note:: - :ref:`cmd_ci` command accepts **multiple** ``SRC`` arguments, - :option:`platformio ci --lib` and :option:`platformio ci --exclude` options - which can be a path to directory, file or - `Glob Pattern `_. + :ref:`cmd_ci` command is useful for library developers. It allows to build + different examples without creating own project per them. Also, is possible + to upload firmware to the target device. In this case, need to create + :ref:`projectconf` where specify "upload" :ref:`projectconf_targets`. Custom + upload port can be overridden with :ref:`projectconf_upload_port` option. + Then need to specify the path to this :ref:`projectconf` to + :option:`platformio ci --project-conf`. For example, -.. note:: - You can omit ``SRC`` argument and set path (multiple paths are allowed - denoting with ``:``) to - ``PLATFORMIO_CI_SRC`` `Environment variable `_ + .. code-block:: ini + + [env:uno] + platform = atmelavr + framework = arduino + targets = upload + ; custom upload port + ; upload_port = ... Options ------- @@ -120,4 +135,4 @@ or by environment variable :envvar:`PLATFORMIO_SETTING_FORCE_VERBOSE`. Examples -------- -For the examples please follow to :ref:`ci` page. +For the others examples please follow to :ref:`ci` page. From bb01ec9a1e0aa9abee56b83189d01deff8e55c9b Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 15 Aug 2016 19:24:31 +0300 Subject: [PATCH 156/284] Fix test for lib command --- .travis.yml | 12 ++++++------ tests/commands/{test_lib.py => test__lib.py} | 0 2 files changed, 6 insertions(+), 6 deletions(-) rename tests/commands/{test_lib.py => test__lib.py} (100%) diff --git a/.travis.yml b/.travis.yml index 8976ec8a..e745f7dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,11 +3,11 @@ language: python matrix: include: - os: linux - sudo: required + sudo: false python: 2.7 env: TOX_ENV=docs - os: linux - sudo: required + sudo: false python: 2.7 env: TOX_ENV=lint - os: linux @@ -20,17 +20,17 @@ matrix: install: - git submodule update --init --recursive - - sudo pip install -U pip setuptools tox + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo pip install -U tox; else pip install -U tox; fi # temporary hook to fix issue with gcc-pic32 - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -qq lib32z1 lib32ncurses5 lib32bz2-1.0; fi + - if [[ "$TOX_ENV" == "py27" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -qq lib32z1 lib32ncurses5 lib32bz2-1.0; fi script: - tox -e $TOX_ENV after_success: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then tox -e coverage; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then bash <(curl -s https://codecov.io/bash); fi + - 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: slack: diff --git a/tests/commands/test_lib.py b/tests/commands/test__lib.py similarity index 100% rename from tests/commands/test_lib.py rename to tests/commands/test__lib.py From 94299139cfadb00af7091902837eae697317d0d5 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 15 Aug 2016 19:49:15 +0300 Subject: [PATCH 157/284] Allow to pass extra "EXTRA_LIB_BUILDERS" for Library Builder --- platformio/builder/tools/piolib.py | 18 ++++++++---------- tests/commands/test_init.py | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 37929d81..70eefecb 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -460,8 +460,7 @@ def GetLibBuilders(env): compat_mode = int(env.get("LIB_COMPAT_MODE", 1)) verbose = not (env.GetOption("silent") or env.GetOption('clean')) - def _init_lib_builder(src_dir): - lb = LibBuilderFactory.new(env, src_dir) + def _check_lib_builder(lb): if lb.name in env.get("LIB_IGNORE", []): if verbose: sys.stderr.write("Ignored library %s\n" % lb.path) @@ -471,14 +470,14 @@ def GetLibBuilders(env): if verbose: sys.stderr.write("Platform incompatible library %s\n" % lb.path) - return + return False if compat_mode > 0 and not any([lb.is_framework_compatible(f) for f in env_frameworks]): if verbose: sys.stderr.write("Framework incompatible library %s\n" % lb.path) - return - return lb + return False + return True for libs_dir in env['LIBSOURCE_DIRS']: libs_dir = env.subst(libs_dir) @@ -487,13 +486,12 @@ def GetLibBuilders(env): for item in sorted(os.listdir(libs_dir)): if item == "__cores__" or not isdir(join(libs_dir, item)): continue - lb = _init_lib_builder(join(libs_dir, item)) - if lb: + lb = LibBuilderFactory.new(env, join(libs_dir, item)) + if _check_lib_builder(lb): items += (lb, ) - for lib_dir in env.get("LIBSOURCE_EXTRA", []): - lb = _init_lib_builder(lib_dir) - if lb: + for lb in env.get("EXTRA_LIB_BUILDERS", []): + if _check_lib_builder(lb): items += (lb, ) return items diff --git a/tests/commands/test_init.py b/tests/commands/test_init.py index 6a9984b9..6064fd49 100644 --- a/tests/commands/test_init.py +++ b/tests/commands/test_init.py @@ -16,7 +16,7 @@ import json from os import getcwd, makedirs from os.path import getsize, isdir, isfile, join -from platformio import util, exception +from platformio import exception, util from platformio.commands.boards import cli as cmd_boards from platformio.commands.init import cli as cmd_init From 8d8a0efdb9b12b0e3905b8c5430b33d1c581d0fc Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 15 Aug 2016 20:14:09 +0300 Subject: [PATCH 158/284] Refactor long command hook for GCC and Windows CMD limitations --- platformio/builder/main.py | 4 ++-- .../builder/tools/{pioar.py => longcmdhook.py} | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) rename platformio/builder/tools/{pioar.py => longcmdhook.py} (77%) diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 5bbabd15..f245d5d2 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -68,8 +68,8 @@ commonvars.AddVariables( DefaultEnvironment( tools=[ "ar", "as", "gcc", "g++", "gnulink", - "platformio", "pioplatform", - "piolib", "piotest", "pioupload", "pioar", "piomisc" + "longcmdhook", "platformio", "pioplatform", + "piolib", "piotest", "pioupload", "piomisc" ], # yapf: disable toolpath=[join(util.get_source_dir(), "builder", "tools")], variables=commonvars, diff --git a/platformio/builder/tools/pioar.py b/platformio/builder/tools/longcmdhook.py similarity index 77% rename from platformio/builder/tools/pioar.py rename to platformio/builder/tools/longcmdhook.py index d530892a..bfd14717 100644 --- a/platformio/builder/tools/pioar.py +++ b/platformio/builder/tools/longcmdhook.py @@ -19,12 +19,12 @@ from tempfile import gettempdir MAX_SOURCES_LENGTH = 8000 # Windows CLI has limit with command length to 8192 -def _huge_sources_hook(sources): +def long_cmd_hook(sources): _sources = str(sources).replace("\\", "/") if len(str(_sources)) < MAX_SOURCES_LENGTH: return sources - tmp_file = join(gettempdir(), "pioarargs-%s" % md5(_sources).hexdigest()) + tmp_file = join(gettempdir(), "longcmd-%s" % md5(_sources).hexdigest()) with open(tmp_file, "w") as f: # fix space in paths for line in _sources.split(".o "): @@ -41,9 +41,11 @@ def exists(_): def generate(env): - env.Replace( - _huge_sources_hook=_huge_sources_hook, - ARCOM=env.get("ARCOM", "").replace("$SOURCES", - "${_huge_sources_hook(SOURCES)}")) + env.Replace(_long_cmd_hook=long_cmd_hook) + coms = {} + for key in ("ARCOM", "LINKCOM"): + coms[key] = env.get(key, "").replace("$SOURCES", + "${_long_cmd_hook(SOURCES)}") + env.Replace(**coms) return env From 2a3a12b8163fd6417b401fe2140d03e0c623d2d0 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 16 Aug 2016 13:02:57 +0300 Subject: [PATCH 159/284] Handle relative paths for "lib_extra_dirs" // Resolve #749 --- platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 7114b1f3..f034eef9 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0a4") +VERSION = (3, 0, "0a5") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 70eefecb..64075fc1 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -81,7 +81,7 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes def __init__(self, env, path): self.env = env.Clone() self.envorigin = env.Clone() - self.path = env.subst(path) + self.path = realpath(env.subst(path)) self._manifest = self.load_manifest() self._is_dependent = False self._depbuilders = tuple() From 797688dedde6bfc2e377a384e278ece6d542b1be Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 16 Aug 2016 17:27:11 +0300 Subject: [PATCH 160/284] Fix EXTRA_LIB_BUILDERS --- platformio/builder/tools/piolib.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 64075fc1..a5ab68fe 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -78,11 +78,11 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes INC_SCANNER = SCons.Scanner.C.CScanner() - def __init__(self, env, path): + def __init__(self, env, path, manifest=None): self.env = env.Clone() self.envorigin = env.Clone() self.path = realpath(env.subst(path)) - self._manifest = self.load_manifest() + self._manifest = manifest if manifest else self.load_manifest() self._is_dependent = False self._depbuilders = tuple() self._scanned_paths = tuple() @@ -246,7 +246,7 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes return result def depend_recursive(self, lb, lib_builders, search_paths=None): - assert isinstance(lb, LibBuilderBase) + # assert isinstance(lb, LibBuilderBase) if self != lb: if self in lb.depbuilders: sys.stderr.write("Warning! Circular dependencies detected " From 9b08244ed810bc732936e49b6505064b3e958857 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 16 Aug 2016 20:10:03 +0300 Subject: [PATCH 161/284] Add article "ESP8266 Mobile Rick Roll Captive Portal" --- docs/articles.rst | 1 + docs/platforms/espressif_extra.rst | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/articles.rst b/docs/articles.rst index 026c1b44..30631d4e 100644 --- a/docs/articles.rst +++ b/docs/articles.rst @@ -24,6 +24,7 @@ Here are recent articles about PlatformIO: ^^^^ * Jul 26, 2016 - **Embedded Systems Laboratory** - `แนะนำการใช้งาน PlatformIO IDE สำหรับบอร์ด Arduino และ ESP8266 (Get started with PlatformIO IDE for Arduino board and ESP8266, Thai) `_ +* Jul 15, 2016 - **Jaime** - `ESP8266 Mobile Rick Roll Captive Portal `_ * Jul 5, 2016 - **Ivan Kravets, Ph.D.** - `Explore the new development instruments for Arduino with PlatformIO ecosystem `_ * Jul 5, 2016 - **Belinda** - `Monte Bianco Arduino Developer Summit `_ * Jul 1, 2016 - **Tam Hanna** - `Mikrocontroller-Gipfel in den Alpen: Arduino Developer Summit, Tag eins (Microcontroller peaks in the Alps: Arduino Developer Summit, Day One, German) `_ diff --git a/docs/platforms/espressif_extra.rst b/docs/platforms/espressif_extra.rst index 16d0343e..a67cbff9 100644 --- a/docs/platforms/espressif_extra.rst +++ b/docs/platforms/espressif_extra.rst @@ -240,6 +240,7 @@ Using Arduino Framework with Staging version Articles -------- +* Jul 15, 2016 - **Jaime** - `ESP8266 Mobile Rick Roll Captive Portal `_ * Jun 13, 2016 - **Daniel Eichhorn** - `New Weather Station Demo on Github `_ * Jun 3, 2016 - **Daniel Eichhorn** - `ESP8266: Continuous Delivery Pipeline – Push To Production `_ * May 29, 2016 - **Chris Synan** - `Reverse Engineer RF Remote Controller for IoT! `_ From 64cc353455c3920aab46f8449530df43bb865308 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 17 Aug 2016 17:36:05 +0300 Subject: [PATCH 162/284] Implement build hooks for Windows --- platformio/builder/main.py | 2 +- platformio/builder/tools/longcmdhook.py | 51 --------------- platformio/builder/tools/piowinhooks.py | 85 +++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 52 deletions(-) delete mode 100644 platformio/builder/tools/longcmdhook.py create mode 100644 platformio/builder/tools/piowinhooks.py diff --git a/platformio/builder/main.py b/platformio/builder/main.py index f245d5d2..67df1f5c 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -68,7 +68,7 @@ commonvars.AddVariables( DefaultEnvironment( tools=[ "ar", "as", "gcc", "g++", "gnulink", - "longcmdhook", "platformio", "pioplatform", + "platformio", "pioplatform", "piowinhooks", "piolib", "piotest", "pioupload", "piomisc" ], # yapf: disable toolpath=[join(util.get_source_dir(), "builder", "tools")], diff --git a/platformio/builder/tools/longcmdhook.py b/platformio/builder/tools/longcmdhook.py deleted file mode 100644 index bfd14717..00000000 --- a/platformio/builder/tools/longcmdhook.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2014-present PlatformIO -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from hashlib import md5 -from os.path import join -from tempfile import gettempdir - -MAX_SOURCES_LENGTH = 8000 # Windows CLI has limit with command length to 8192 - - -def long_cmd_hook(sources): - _sources = str(sources).replace("\\", "/") - if len(str(_sources)) < MAX_SOURCES_LENGTH: - return sources - - tmp_file = join(gettempdir(), "longcmd-%s" % md5(_sources).hexdigest()) - with open(tmp_file, "w") as f: - # fix space in paths - for line in _sources.split(".o "): - if not line.endswith(".o"): - line += ".o" - f.write('"%s" ' % line) - - return '@"%s"' % tmp_file - - -def exists(_): - return True - - -def generate(env): - - env.Replace(_long_cmd_hook=long_cmd_hook) - coms = {} - for key in ("ARCOM", "LINKCOM"): - coms[key] = env.get(key, "").replace("$SOURCES", - "${_long_cmd_hook(SOURCES)}") - env.Replace(**coms) - - return env diff --git a/platformio/builder/tools/piowinhooks.py b/platformio/builder/tools/piowinhooks.py new file mode 100644 index 00000000..9dc9d6dc --- /dev/null +++ b/platformio/builder/tools/piowinhooks.py @@ -0,0 +1,85 @@ +# Copyright 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from hashlib import md5 +from os import makedirs +from os.path import isdir, isfile, join +from platform import system + +MAX_SOURCES_LENGTH = 8000 # Windows CLI has limit with command length to 8192 + + +def long_sources_hook(env, sources): + _sources = str(sources).replace("\\", "/") + if len(str(_sources)) < MAX_SOURCES_LENGTH: + return sources + + # fix space in paths + data = [] + for line in _sources.split(".o "): + line = line.strip() + if not line.endswith(".o"): + line += ".o" + data.append('"%s"' % line) + + return '@"%s"' % _file_long_data(env, " ".join(data)) + + +def long_incflags_hook(env, incflags): + _incflags = env.subst(incflags).replace("\\", "/") + if len(_incflags) < MAX_SOURCES_LENGTH - 2000: + return incflags + + # fix space in paths + data = [] + for line in _incflags.split(" -I"): + line = line.strip() + if not line.startswith("-I"): + line = "-I" + line + data.append('-I"%s"' % line[2:]) + + return '@"%s"' % _file_long_data(env, " ".join(data)) + + +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()) + if isfile(tmp_file): + return tmp_file + with open(tmp_file, "w") as fp: + fp.write(data) + return tmp_file + + +def exists(_): + return True + + +def generate(env): + if system() != "Windows": + return + + env.Replace(_long_sources_hook=long_sources_hook) + env.Replace(_long_incflags_hook=long_incflags_hook) + coms = {} + for key in ("ARCOM", "LINKCOM"): + coms[key] = env.get(key, "").replace( + "$SOURCES", "${_long_sources_hook(__env__, SOURCES)}") + coms['_CCCOMCOM'] = env.get("_CCCOMCOM", "").replace( + "$_CPPINCFLAGS", "${_long_incflags_hook(__env__, _CPPINCFLAGS)}") + env.Replace(**coms) + + return env From b2e6d162219ec50bdee9a8a3310b728fb834f6e7 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 17 Aug 2016 17:38:20 +0300 Subject: [PATCH 163/284] Don't use shell for Windows and exec commands --- platformio/util.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platformio/util.py b/platformio/util.py index cd87103c..b6f40fd5 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -261,8 +261,7 @@ def exec_command(*args, **kwargs): default = dict( stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=system() == "Windows") + stderr=subprocess.PIPE) default.update(kwargs) kwargs = default From d40d1e4f2b56816ba16b737f0c6dd13ca610f909 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 00:08:55 +0300 Subject: [PATCH 164/284] Rename url to homepage --- docs/librarymanager/config.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index 7f619bcb..e2c64525 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -260,10 +260,8 @@ Example with fixed release/tag on GitHub: See more ``library.json`` :ref:`library_creating_examples`. -.. _libjson_url: - -``url`` -------- +``homepage`` +------------ *Optional* | Type: ``String`` | Max. Length: 255 From f01b858e90ea5cd40d4269a9a996e20c6cd5b2f1 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 00:13:29 +0300 Subject: [PATCH 165/284] Minor fix --- docs/librarymanager/config.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index e2c64525..4a02c0d4 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -139,7 +139,7 @@ Examples: *Required* if :ref:`libjson_downloadurl` field is not defined | Type: ``Object`` -The repository in which the source code can be found. The field consists for the +The repository in which the source code can be found. The field consists of the next items: * ``type`` the only "git", "hg" or "svn" are supported @@ -226,6 +226,8 @@ Example: ``license`` ----------- +*Optional* | Type: ``String`` + A license of the library. You can check `the full list of SPDX license IDs `_. Ideally you should pick one that is `OSI `_ From 0e9050f2e888d3cc93f7d43f5173450f430ae42f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 00:30:51 +0300 Subject: [PATCH 166/284] Update lib search test --- tests/commands/test__lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/commands/test__lib.py b/tests/commands/test__lib.py index 9bd5b8ec..862c7f26 100644 --- a/tests/commands/test__lib.py +++ b/tests/commands/test__lib.py @@ -31,7 +31,7 @@ def test_search(clirunner, validate_cliresult): ["search", "DHT22", "--platform=timsp430"]) validate_cliresult(result) match = re.search(r"Found\s+(\d+)\slibraries:", result.output) - assert int(match.group(1)) == 1 + assert int(match.group(1)) > 1 def test_global_install_registry(clirunner, validate_cliresult, From d630aa4f373908bc3d4481fdfbd3213dba5e08e5 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 12:18:27 +0300 Subject: [PATCH 167/284] Check CI SRC paths passed via system environment variable --- platformio/commands/ci.py | 6 +++--- platformio/util.py | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index 038943c3..5303932a 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -33,7 +33,7 @@ except ImportError: from ConfigParser import ConfigParser -def validate_path(ctx, param, value): # pylint: disable=W0613 +def validate_path(ctx, param, value): # pylint: disable=unused-argument invalid_path = None value = list(value) for i, p in enumerate(value): @@ -87,8 +87,8 @@ def cli(ctx, # pylint: disable=R0913 project_conf, verbose): - if not src: - src = getenv("PLATFORMIO_CI_SRC", "").split(":") + if not src and getenv("PLATFORMIO_CI_SRC"): + src = validate_path(ctx, None, getenv("PLATFORMIO_CI_SRC").split(":")) if not src: raise click.BadParameter("Missing argument 'src'") diff --git a/platformio/util.py b/platformio/util.py index b6f40fd5..c8b8c18f 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -259,9 +259,7 @@ def is_ci(): def exec_command(*args, **kwargs): result = {"out": None, "err": None, "returncode": None} - default = dict( - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + default = dict(stdout=subprocess.PIPE, stderr=subprocess.PIPE) default.update(kwargs) kwargs = default From d410696729171319ff0e53fd0668e2ba4ef98048 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 14:29:54 +0300 Subject: [PATCH 168/284] Push notification to Slack --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e745f7dd..4fece8b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,6 +34,7 @@ after_success: notifications: slack: - secure: ksQmXOP5NVsf8IgoDuxD68Q/YNwDpZuwq0V29h2dxYCr38oYdAkq/Os4LSCs0X6P0cQFf6nC1hM/d+cAvU+SmzcHGxEceHNEGCg3/TAj+68KIwooPU93Lfq1zwdfteZWxANjKlCQy4+wZliHLhL8fvCYgfJww/6qKmqSYleBNM= + rooms: + secure: JD6VGfN4+SLU2CwDdiIOr1VgwD+zbYUCE/srwyGuHavnjIkPItkl6T6Bn8Y4VrU6ysbuKotfdV2TAJJ82ivFbY8BvZBc7FBcYp/AGQ4FaCCV5ySv8RDAcQgdE12oaGzMdODiLqsB85f65zOlAFa+htaXyEiRTcotn6Y2hupatrI= on_failure: always on_success: change From 512ea68dce8b3c94c8edfdf57aa97128b1101309 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 14:47:21 +0300 Subject: [PATCH 169/284] Disable email notification --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4fece8b7..cd1df106 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,8 @@ after_success: - if [[ "$TOX_ENV" == "py27" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then bash <(curl -s https://codecov.io/bash); fi notifications: + email: false + slack: rooms: secure: JD6VGfN4+SLU2CwDdiIOr1VgwD+zbYUCE/srwyGuHavnjIkPItkl6T6Bn8Y4VrU6ysbuKotfdV2TAJJ82ivFbY8BvZBc7FBcYp/AGQ4FaCCV5ySv8RDAcQgdE12oaGzMdODiLqsB85f65zOlAFa+htaXyEiRTcotn6Y2hupatrI= From b0d74c46408bee363371d8144d18dfe1e35d7cd6 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 15:02:56 +0300 Subject: [PATCH 170/284] Extend "examples" default value --- docs/librarymanager/config.rst | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index 4a02c0d4..85116f92 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -435,11 +435,21 @@ A list of example patterns. This field is predefined with default value: .. code-block:: javascript "examples": [ + "[Ee]xamples/*.c", + "[Ee]xamples/*.cpp", + "[Ee]xamples/*.h", + "[Ee]xamples/*.ino", + "[Ee]xamples/*.pde", "[Ee]xamples/*/*.c", "[Ee]xamples/*/*.cpp", "[Ee]xamples/*/*.h", "[Ee]xamples/*/*.ino", - "[Ee]xamples/*/*.pde" + "[Ee]xamples/*/*.pde", + "[Ee]xamples/*/*/*.c", + "[Ee]xamples/*/*/*.cpp", + "[Ee]xamples/*/*/*.h", + "[Ee]xamples/*/*/*.ino", + "[Ee]xamples/*/*/*.pde" ] From ef6952b27a0795cc3f238cb46cac1894f09a6eaf Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 15:11:26 +0300 Subject: [PATCH 171/284] Add Contents to library index page --- docs/librarymanager/index.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/librarymanager/index.rst b/docs/librarymanager/index.rst index 5e2327d4..1268121a 100644 --- a/docs/librarymanager/index.rst +++ b/docs/librarymanager/index.rst @@ -24,3 +24,11 @@ You don't need to bother for finding the latest version of library. Due to :ref:`cmd_lib_update` command you will have up-to-date external libraries. .. image:: ../_static/platformio-demo-lib.gif + +.. toctree:: + :maxdepth: 2 + + User Guide <../userguide/lib/index.rst> + ldf + config + creating From f25e166ea80080cebc77ce8cf129deb213339d81 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 16:05:49 +0300 Subject: [PATCH 172/284] Push notification to Slack --- appveyor.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 845307f6..7b3ba4b7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,3 +11,13 @@ install: test_script: - cmd: tox + +notifications: + - provider: Email + on_build_success: false + on_build_failure: false + on_build_status_changed: false + + - provider: Slack + incoming_webhook: + secure: E9H0SU0Ju7WLDvgxsV8cs3J62T3nTTX7QkEjsczN0Sto/c9hWkVfhc5gGWUkxhlD975cokHByKGJIdwYwCewqOI+7BrcT8U+nlga4Uau7J8= From 9b292e0614473d2ae0a91d47ff5eee8db866a79b Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 16:08:47 +0300 Subject: [PATCH 173/284] Notify only when build changes status --- appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 7b3ba4b7..76bdb526 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -21,3 +21,6 @@ notifications: - provider: Slack incoming_webhook: secure: E9H0SU0Ju7WLDvgxsV8cs3J62T3nTTX7QkEjsczN0Sto/c9hWkVfhc5gGWUkxhlD975cokHByKGJIdwYwCewqOI+7BrcT8U+nlga4Uau7J8= + on_build_success: false + on_build_failure: true + on_build_status_changed: true From fb6df55326773a37cfffa72bb175ad437430c507 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 16:52:31 +0300 Subject: [PATCH 174/284] Don't notify ikravets --- appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 76bdb526..1d704b21 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,6 +14,8 @@ test_script: notifications: - provider: Email + to: + - me@ikravets.com on_build_success: false on_build_failure: false on_build_status_changed: false From dab81291eb6c6f93b7098825f5a8b1f68bcfee41 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 18:51:23 +0300 Subject: [PATCH 175/284] Extend win hooks for ASPPCOM --- platformio/builder/tools/piowinhooks.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platformio/builder/tools/piowinhooks.py b/platformio/builder/tools/piowinhooks.py index 9dc9d6dc..2b2dcf3e 100644 --- a/platformio/builder/tools/piowinhooks.py +++ b/platformio/builder/tools/piowinhooks.py @@ -78,8 +78,9 @@ def generate(env): for key in ("ARCOM", "LINKCOM"): coms[key] = env.get(key, "").replace( "$SOURCES", "${_long_sources_hook(__env__, SOURCES)}") - coms['_CCCOMCOM'] = env.get("_CCCOMCOM", "").replace( - "$_CPPINCFLAGS", "${_long_incflags_hook(__env__, _CPPINCFLAGS)}") + for key in ("_CCCOMCOM", "ASPPCOM"): + coms[key] = env.get(key, "").replace( + "$_CPPINCFLAGS", "${_long_incflags_hook(__env__, _CPPINCFLAGS)}") env.Replace(**coms) return env From 6f8614906db544f695bcf61513029d888362afc5 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 19:01:34 +0300 Subject: [PATCH 176/284] New article "Installing PlatformIO on Arch Linux" --- docs/articles.rst | 1 + docs/ide/atom.rst | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/docs/articles.rst b/docs/articles.rst index 30631d4e..a219d7c8 100644 --- a/docs/articles.rst +++ b/docs/articles.rst @@ -23,6 +23,7 @@ Here are recent articles about PlatformIO: 2016 ^^^^ +* Aug 18, 2016 - **Primal Cortex** - `Installing PlatformIO on Arch Linux `_ * Jul 26, 2016 - **Embedded Systems Laboratory** - `แนะนำการใช้งาน PlatformIO IDE สำหรับบอร์ด Arduino และ ESP8266 (Get started with PlatformIO IDE for Arduino board and ESP8266, Thai) `_ * Jul 15, 2016 - **Jaime** - `ESP8266 Mobile Rick Roll Captive Portal `_ * Jul 5, 2016 - **Ivan Kravets, Ph.D.** - `Explore the new development instruments for Arduino with PlatformIO ecosystem `_ diff --git a/docs/ide/atom.rst b/docs/ide/atom.rst index fdfe142b..0d484c91 100644 --- a/docs/ide/atom.rst +++ b/docs/ide/atom.rst @@ -439,6 +439,11 @@ To force Smart Code Linter to use Arduino files as C++ please 2. Perform all steps from :ref:`ide_atom_knownissues_sclarduino_manually` (without renaming to ``.cpp``). +Arch Linux: PlatformIO IDE Terminal issue +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Please read this article `Installing PlatformIO on Arch Linux `_. + .. _ide_atom_faq: Frequently Asked Questions @@ -478,6 +483,8 @@ package and `C/C++ Uncrustify Code Beautifier `_ +* Jul 26, 2016 - **Embedded Systems Laboratory** - `แนะนำการใช้งาน PlatformIO IDE สำหรับบอร์ด Arduino และ ESP8266 (Get started with PlatformIO IDE for Arduino board and ESP8266, Thai) `_ * May 30, 2016 - **Ron Moerman** - `IoT Development with PlatformIO `_ * May 01, 2016 - **Pedro Minatel** - `PlatformIO – Uma alternativa ao Arduino IDE (PlatformIO - An alternative to the Arduino IDE, Portuguese) `_ * Apr 23, 2016 - **Al Williams** - `Hackaday: Atomic Arduino (and Other) Development `_ From ec897d217c9b7bac4f12e88e2ff7feb900ad3b5f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 20:26:29 +0300 Subject: [PATCH 177/284] Update issue template --- .github/ISSUE_TEMPLATE.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 3e4857dd..be415e99 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -4,14 +4,17 @@ What kind of issue is this? something, or to understand why something isn't working the way you expect it to, use our Community Forums https://community.platformio.org +- [ ] PlatformIO IDE. All issues related to PlatformIO IDE should be reported to appropriate repository + https://github.com/platformio/platformio-atom-ide/issues + +- [ ] Development Platforms. All issues related to Development Platforms should be reported to appropriate repository + https://github.com/platformio?query=platform- + - [ ] Feature Request. Start by telling us what problem you’re trying to solve. Often a solution already exists! Don’t 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 IDE. All issues related to PlatformIO IDE should be reported to appropriate repository - https://github.com/platformio/platformio-atom-ide/issues - -- [ ] Bug report. If you’ve found a bug, please provide information below. +- [ ] PlatformIO Core. If you’ve found a bug, please provide information below. *You can erase any parts of this template not applicable to your Issue.* From 55c627e4ee18e1ecbd8ad04a891d6a3449b2547c Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 20:29:00 +0300 Subject: [PATCH 178/284] Minor changes --- .github/ISSUE_TEMPLATE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index be415e99..71b72011 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -7,14 +7,14 @@ What kind of issue is this? - [ ] PlatformIO IDE. All issues related to PlatformIO IDE should be reported to appropriate repository https://github.com/platformio/platformio-atom-ide/issues -- [ ] Development Platforms. All issues related to Development Platforms should be reported to appropriate repository +- [ ] Development Platform. All issues related to Development Platform should be reported to appropriate repository. Search it using link below https://github.com/platformio?query=platform- - [ ] Feature Request. Start by telling us what problem you’re trying to solve. Often a solution already exists! Don’t 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 you’ve found a bug, please provide information below. +- [ ] PlatformIO Core. If you’ve found a bug, please provide an information below. *You can erase any parts of this template not applicable to your Issue.* From 5c105a9bcbafcae3e3838dd0f39f8cf21d35285b Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 18 Aug 2016 23:51:32 +0300 Subject: [PATCH 179/284] Fix CI test --- tests/commands/test_ci.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/commands/test_ci.py b/tests/commands/test_ci.py index 290c9720..884e9b50 100644 --- a/tests/commands/test_ci.py +++ b/tests/commands/test_ci.py @@ -14,14 +14,13 @@ from os.path import join -from platformio import exception from platformio.commands.ci import cli as cmd_ci def test_ci_empty(clirunner): result = clirunner.invoke(cmd_ci) - assert result.exit_code == -1 - assert isinstance(result.exception, exception.CIBuildEnvsEmpty) + assert result.exit_code == 2 + assert "Invalid value: Missing argument 'src'" in result.output def test_ci_boards(clirunner, validate_cliresult): From e51b8d2f618e8100263f56fc3b95c46b48b413b9 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 19 Aug 2016 17:08:31 +0300 Subject: [PATCH 180/284] Cleanup AppVeyor Config --- appveyor.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 1d704b21..fe1b1e8f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,13 +13,6 @@ test_script: - cmd: tox notifications: - - provider: Email - to: - - me@ikravets.com - on_build_success: false - on_build_failure: false - on_build_status_changed: false - - provider: Slack incoming_webhook: secure: E9H0SU0Ju7WLDvgxsV8cs3J62T3nTTX7QkEjsczN0Sto/c9hWkVfhc5gGWUkxhlD975cokHByKGJIdwYwCewqOI+7BrcT8U+nlga4Uau7J8= From 1a517995a051c95ba41ba246f2ebe3e8a4d9038d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 21 Aug 2016 00:31:58 +0300 Subject: [PATCH 181/284] Rename "quiet" option to "silent" --- docs/userguide/lib/cmd_install.rst | 2 +- platformio/commands/lib.py | 16 ++++++++-------- platformio/commands/run.py | 2 +- platformio/managers/lib.py | 27 +++++++++++++++------------ platformio/managers/package.py | 9 ++++++--- platformio/managers/platform.py | 10 +++++----- 6 files changed, 36 insertions(+), 30 deletions(-) diff --git a/docs/userguide/lib/cmd_install.rst b/docs/userguide/lib/cmd_install.rst index 6f007bbe..880920b2 100644 --- a/docs/userguide/lib/cmd_install.rst +++ b/docs/userguide/lib/cmd_install.rst @@ -90,7 +90,7 @@ Options .. program:: platformio lib install .. option:: - -q, --quiet + -s, --silent Suppress progress reporting diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index e77a9641..3b434e43 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -68,18 +68,18 @@ def cli(ctx, **options): @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( - "--save", - is_flag=True, - help="Save installed libraries into the project's platformio.ini " - "library dependencies") -@click.option( - "-q", "--quiet", is_flag=True, help="Suppress progress reporting") + "-s", "--silent", is_flag=True, help="Suppress progress reporting") @click.pass_obj -def lib_install(lm, libraries, save, quiet): # pylint: disable=unused-argument +def lib_install(lm, libraries, silent): # @TODO "save" option for library in libraries: - lm.install(library, quiet=quiet) + lm.install(library, silent=silent) @cli.command("uninstall", short_help="Uninstall libraries") diff --git a/platformio/commands/run.py b/platformio/commands/run.py index e130393f..22c4307a 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -246,7 +246,7 @@ def _autoinstall_libdeps(ctx, libraries, verbose=False): ctx.obj = LibraryManager(storage_dir) if verbose: click.echo("Library Storage: " + storage_dir) - ctx.invoke(cmd_lib_install, libraries=libraries, quiet=not verbose) + ctx.invoke(cmd_lib_install, libraries=libraries, silent=not verbose) def _clean_pioenvs_dir(pioenvs_dir): diff --git a/platformio/managers/lib.py b/platformio/managers/lib.py index ce1543a8..730d6b7e 100644 --- a/platformio/managers/lib.py +++ b/platformio/managers/lib.py @@ -106,7 +106,7 @@ class LibraryManager(BasePkgManager): name, requirements)), requirements) return item['version'] if item else None - def _get_pkg_id_by_name(self, name, requirements, quiet=False): + def _get_pkg_id_by_name(self, name, requirements, silent=False): if name.startswith("id="): return int(name[3:]) # try to find ID from installed packages @@ -115,7 +115,7 @@ class LibraryManager(BasePkgManager): manifest = self.load_manifest(installed_dir) if "id" in manifest: return int(manifest['id']) - return int(self.search_for_library({"name": name}, quiet)['id']) + return int(self.search_for_library({"name": name}, silent)['id']) def _install_from_piorepo(self, name, requirements): assert name.startswith("id=") @@ -136,15 +136,18 @@ class LibraryManager(BasePkgManager): requirements) return pkg_dir - def install(self, name, requirements=None, quiet=False, + def install(self, + name, + requirements=None, + silent=False, trigger_event=True): _name, _requirements, _url = self.parse_pkg_name(name, requirements) if not _url: _name = "id=%d" % self._get_pkg_id_by_name( - _name, _requirements, quiet=quiet) + _name, _requirements, silent=silent) already_installed = self.get_installed_dir(_name, _requirements, _url) pkg_dir = BasePkgManager.install(self, _name if not _url else name, - _requirements, quiet, trigger_event) + _requirements, silent, trigger_event) if already_installed: return @@ -153,7 +156,7 @@ class LibraryManager(BasePkgManager): if "dependencies" not in manifest: return pkg_dir - if not quiet: + if not silent: click.secho("Installing dependencies", fg="yellow") for filters in self.normalize_dependencies(manifest['dependencies']): @@ -161,26 +164,26 @@ class LibraryManager(BasePkgManager): if any([s in filters.get("version", "") for s in ("\\", "/")]): self.install("{name}={version}".format(**filters)) else: - lib_info = self.search_for_library(filters, quiet) + lib_info = self.search_for_library(filters, silent) if filters.get("version"): self.install( lib_info['id'], requirements=filters.get("version"), - quiet=quiet, + silent=silent, trigger_event=trigger_event) else: self.install( lib_info['id'], - quiet=quiet, + silent=silent, trigger_event=trigger_event) return pkg_dir @staticmethod def search_for_library( # pylint: disable=too-many-branches - filters, quiet=False): + filters, silent=False): assert isinstance(filters, dict) assert "name" in filters - if not quiet: + if not silent: click.echo("Looking for %s library in registry" % click.style( filters['name'], fg="cyan")) query = [] @@ -222,7 +225,7 @@ class LibraryManager(BasePkgManager): if not lib_info: raise exception.LibNotFound(str(filters)) - if not quiet: + if not silent: click.echo("Found: %s" % click.style( "http://platformio.org/lib/show/{id}/{name}".format( **lib_info), diff --git a/platformio/managers/package.py b/platformio/managers/package.py index d271de15..424a69a7 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -420,18 +420,21 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): return manifest['version'] != self.get_latest_repo_version( name, requirements) - def install(self, name, requirements=None, quiet=False, + def install(self, + name, + requirements=None, + silent=False, trigger_event=True): name, requirements, url = self.parse_pkg_name(name, requirements) installed_dir = self.get_installed_dir(name, requirements, url) - if not installed_dir or not quiet: + if not installed_dir or not silent: msg = "Installing " + click.style(name, fg="cyan") if requirements: msg += " @ " + requirements self.print_message(msg) if installed_dir: - if not quiet: + if not silent: click.secho( "{name} @ {version} is already installed".format( **self.load_manifest(installed_dir)), diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 00af2d37..a5817c05 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -43,7 +43,7 @@ class PlatformManager(BasePkgManager): return "platform.json" def install(self, # pylint: disable=too-many-arguments,arguments-differ - name, requirements=None, quiet=False, + name, requirements=None, silent=False, trigger_event=True, with_packages=None, without_packages=None, skip_default_package=False): platform_dir = BasePkgManager.install(self, name, requirements) @@ -197,7 +197,7 @@ class PlatformPackagesMixin(object): with_packages=None, without_packages=None, skip_default_package=False, - quiet=False): + silent=False): with_packages = set(self.pkg_types_to_names(with_packages or [])) without_packages = set(self.pkg_types_to_names(without_packages or [])) @@ -213,9 +213,9 @@ class PlatformPackagesMixin(object): not (skip_default_package or opts.get("optional", False))): if any([s in opts.get("version", "") for s in ("\\", "/")]): self.pm.install( - "%s=%s" % (name, opts['version']), quiet=quiet) + "%s=%s" % (name, opts['version']), silent=silent) else: - self.pm.install(name, opts.get("version"), quiet=quiet) + self.pm.install(name, opts.get("version"), silent=silent) return True @@ -240,7 +240,7 @@ class PlatformRunMixin(object): assert isinstance(targets, list) self.configure_default_packages(variables, targets) - self.install_packages(quiet=True) + self.install_packages(silent=True) self._verbose = verbose or app.get_setting("force_verbose") From 3426c01955dbb96b28b42f54c4e2414d7d5bc27f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 21 Aug 2016 13:35:31 +0300 Subject: [PATCH 182/284] Fix invalid example with converting INO to CPP in the Atom docs // Resolve #757 --- docs/ide/atom.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/ide/atom.rst b/docs/ide/atom.rst index 0d484c91..9254e9e1 100644 --- a/docs/ide/atom.rst +++ b/docs/ide/atom.rst @@ -381,11 +381,11 @@ For example, we have the next ``Demo.ino`` file: .. code-block:: cpp - void function setup () { + void setup () { someFunction(13); } - void function loop() { + void loop() { delay(1000); } @@ -406,11 +406,11 @@ The final ``Demo.cpp``: void someFunction(int num); - void function setup () { + void setup () { someFunction(13); } - void function loop() { + void loop() { delay(1000); } From 0f7f301787fd049b90f699998cba3b03e6eceae3 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 21 Aug 2016 19:27:38 +0300 Subject: [PATCH 183/284] Improve unit testing output; fix issue with non-ascii output from embedded device // Issue #753 --- platformio/__init__.py | 2 +- platformio/builder/tools/piomisc.py | 2 +- platformio/commands/run.py | 11 +++++++++-- platformio/commands/test.py | 13 ++++++++++--- platformio/managers/platform.py | 15 +++++++++------ 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index f034eef9..fdc16dd1 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0a5") +VERSION = (3, 0, "0a6") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index b4f4735e..14e99810 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -258,7 +258,7 @@ def GetActualLDScript(env): def ProgressHandler(env, node): item = str(node) - if ("toolchain-" in item or "tool-" in item) or \ + if "toolchain-" in item or "tool-" in item or \ item.endswith((".o", ".h", ".hpp", ".ipp")): return item = item.replace(env['PIOHOME_DIR'], ".platformio") diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 22c4307a..83a62cd3 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -42,6 +42,7 @@ from platformio.managers.platform import PlatformFactory 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 @@ -50,6 +51,7 @@ def cli(ctx, # pylint: disable=R0913,R0914 target, upload_port, project_dir, + silent, verbose, disable_auto_clean): with util.cd(project_dir): @@ -102,11 +104,12 @@ def cli(ctx, # pylint: disable=R0913,R0914 options['piotest'] = ctx.meta['piotest'] ep = EnvironmentProcessor(ctx, envname, options, target, - upload_port, verbose) + upload_port, silent, verbose) results.append(ep.process()) if not all(results): raise exception.ReturnErrorCode() + return True class EnvironmentProcessor(object): @@ -130,12 +133,14 @@ class EnvironmentProcessor(object): 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): @@ -155,6 +160,8 @@ class EnvironmentProcessor(object): self.name, fg="cyan", bold=True), ", ".join(["%s: %s" % opts for opts in process_opts]))) click.secho("-" * terminal_width, bold=True) + if self.silent: + click.echo("Please wait...") self.options = self._validate_options(self.options) result = self._run() @@ -238,7 +245,7 @@ class EnvironmentProcessor(object): cmd_platform_install, platforms=[self.options['platform']]) p = PlatformFactory.newPlatform(self.options['platform']) - return p.run(build_vars, build_targets, self.verbose) + return p.run(build_vars, build_targets, self.silent, self.verbose) def _autoinstall_libdeps(ctx, libraries, verbose=False): diff --git a/platformio/commands/test.py b/platformio/commands/test.py index a1b73262..310caba4 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -53,8 +53,8 @@ def cli(ctx, environment, ignore, upload_port, project_dir, verbose): projectconf = util.load_project_config() assert check_project_envs(projectconf, environment) + click.echo("Verbose mode can be enabled via `-v, --verbose` option") click.echo("Collected %d items" % len(test_names)) - click.echo() start_time = time() results = [] @@ -130,11 +130,11 @@ class TestProcessorBase(object): self._run_failed = False def print_progress(self, text, is_error=False): + click.echo() print_header( "[test::%s] %s" % (click.style( self.test_name, fg="yellow", bold=True), text), is_error=is_error) - click.echo() def build_or_upload(self, target): if self.test_name != "*": @@ -143,7 +143,7 @@ class TestProcessorBase(object): cmd_run, project_dir=self.options['project_dir'], upload_port=self.options['upload_port'], - verbose=self.options['verbose'], + silent=not self.options['verbose'], environment=[self.env_name], target=target) @@ -204,6 +204,13 @@ class EmbeddedTestProcessor(TestProcessorBase): timeout=self.SERIAL_TIMEOUT) while True: line = ser.readline().strip() + + # fix non-ascii output from device + for i, c in enumerate(line[::-1]): + if ord(c) > 127: + line = line[-i:] + break + if not line: continue self.on_run_out(line) diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index a5817c05..600c8b4f 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -235,14 +235,15 @@ class PlatformRunMixin(object): LINE_ERROR_RE = re.compile(r"(\s+error|error[:\s]+)", re.I) - def run(self, variables, targets, verbose): + def run(self, variables, targets, silent, verbose): assert isinstance(variables, dict) assert isinstance(targets, list) self.configure_default_packages(variables, targets) self.install_packages(silent=True) - self._verbose = verbose or app.get_setting("force_verbose") + self.silent = silent + self.verbose = verbose or app.get_setting("force_verbose") if "clean" in targets: targets = ["-c", "."] @@ -276,7 +277,7 @@ class PlatformRunMixin(object): "-j %d" % self.get_job_nums(), "--warn=no-no-parallel-support", "-f", join(util.get_source_dir(), "builder", "main.py") ] - if not self._verbose and "-c" not in targets: + if not self.verbose and "-c" not in targets: cmd.append("--silent") cmd += targets @@ -297,9 +298,10 @@ class PlatformRunMixin(object): is_error = self.LINE_ERROR_RE.search(line) is not None self._echo_line(line, level=3 if is_error else 2) - @staticmethod - def _echo_line(line, level): + def _echo_line(self, line, level): assert 1 <= level <= 3 + if self.silent and (level < 2 or not line): + return fg = (None, "yellow", "red")[level - 1] if level == 1 and "is up to date" in line: fg = "green" @@ -326,7 +328,8 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): join(util.get_home_dir(), "packages"), self._manifest.get("packageRepositories")) - self._verbose = False + self.silent = False + self.verbose = False @property def name(self): From f5b4cb0ae840343ac4e52f35942f767707bafb23 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 21 Aug 2016 19:32:11 +0300 Subject: [PATCH 184/284] Refactor "test_ignore" to accepts test names separated with comma // Resolve #753 --- docs/projectconf.rst | 10 ++++------ platformio/commands/test.py | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 16e352d6..42eb6b8a 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -802,9 +802,9 @@ Test options .. seealso:: Please make sure to read :ref:`unit_testing` guide first. -Ignore tests where the name matches specified patterns. -More than one pattern is allowed (multi-lines). Also, you can ignore some -tests using :option:`platformio test --ignore` command. +Ignore tests where the name matches specified patterns. Multiple names are +allowed. Please separate them using comma ``,`` symbol. Also, you can +ignore some tests using :option:`platformio test --ignore` command. .. list-table:: :header-rows: 1 @@ -829,9 +829,7 @@ tests using :option:`platformio test --ignore` command. .. code-block:: ini [env:myenv] - test_ignore = - mytest* - test[13] + test_ignore = footest, bartest_*, test[13] ----------- diff --git a/platformio/commands/test.py b/platformio/commands/test.py index 310caba4..6afe1bcd 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -72,7 +72,7 @@ def cli(ctx, environment, ignore, upload_port, project_dir, verbose): if projectconf.has_option(section, "test_ignore"): _ignore.extend([p.strip() for p in projectconf.get( - section, "test_ignore").split("\n") + section, "test_ignore").split(",") if p.strip()]) if testname != "*" and \ any([fnmatch(testname, p) for p in _ignore]): From d420e956e937ab59693108cf5a6385944d525705 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 22 Aug 2016 00:03:27 +0300 Subject: [PATCH 185/284] Mode "include" and "exclude" options to "export" field for the library.json --- docs/librarymanager/config.rst | 57 ++++++++++++++++++++------------ docs/librarymanager/creating.rst | 9 ++--- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index 85116f92..2ab3c7f7 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -25,8 +25,8 @@ to keep project in own structure and define: * advanced build settings PlatformIO Library Crawler uses ``library.json`` manifest to extract -source code from developer's location and keeps cleaned library in own -Library Storage. +source code from developer's location and keeps a cleaned library in own +Library Registry. A data in ``library.json`` should be represented in `JSON-style `_ via @@ -270,17 +270,32 @@ See more ``library.json`` :ref:`library_creating_examples`. Home page of library (if is different from :ref:`libjson_repository` url). -.. _libjson_include: +.. _libjson_export: + +``export`` +---------- + +*Optional* | Type: ``Object`` + +Explain PlatformIO Library Crawler which content from the repository/archive +should be exported as "source code" of the library. This option is useful if +need to exclude extra data (test code, docs, images, PDFs, etc). It allows to +reduce size of the final archive. + +Possible options: + +* ``include`` +* ``exclude`` ``include`` ------------ +~~~~~~~~~~~ *Optional* | Type: ``String`` or ``Array`` | `Glob Pattern `_ -If :ref:`libjson_include` field is a type of ``String``, then -|PIOAPICR| will recognize it like a "relative path inside -repository/archive to library source code". See example below where the only +If ``include`` field is a type of ``String``, then |PIOAPICR| will recognize +it like a "relative path inside repository/archive to library source code". +See example below where the only source code from the relative directory ``LibrarySourceCodeHere`` will be included. @@ -288,21 +303,23 @@ included. "include": "some/child/dir/LibrarySourceCodeHere" -If :ref:`libjson_include` field is a type of ``Array``, then -|PIOAPICR| firstly will apply :ref:`libjson_exclude` filter and -then include only directories/files which match with :ref:`libjson_include` -patterns. +If ``include`` field is a type of ``Array``, then |PIOAPICR| firstly will +apply ``exclude`` filter and then include only directories/files +which match with ``include`` patterns. Example: .. code-block:: javascript - "include": - [ - "dir/*.[ch]pp", - "dir/examples/*", - "*/*/*.h" - ] + "export": { + "include": + [ + "dir/*.[ch]pp", + "dir/examples/*", + "*/*/*.h" + ] + } + Pattern Meaning @@ -322,16 +339,14 @@ Pattern Meaning See more ``library.json`` :ref:`library_creating_examples`. -.. _libjson_exclude: ``exclude`` ------------ +~~~~~~~~~~~ *Optional* | Type: ``String`` or ``Array`` | `Glob Pattern `_ -Exclude the directories and files which match with :ref:`libjson_exclude` -patterns. +Exclude the directories and files which match with ``exclude`` patterns. .. _libjson_frameworks: diff --git a/docs/librarymanager/creating.rst b/docs/librarymanager/creating.rst index 5d150f16..8bdbf5b9 100644 --- a/docs/librarymanager/creating.rst +++ b/docs/librarymanager/creating.rst @@ -32,9 +32,8 @@ There are a several ways how to share your library with the whole world (see `examples `_). You can hold a lot of libraries (split into separated folders) inside one of -the repository/archive. In this case please use :ref:`libjson_include` -field to specify the relative path to your library's source code. - +the repository/archive. In this case, you need to specify ``include`` option of +:ref:`libjson_export` field to relative path to your library's source code. At GitHub ^^^^^^^^^ @@ -132,7 +131,9 @@ of **required** fields in the :ref:`library_config` will look like: }, "version": "2.2", "downloadUrl": "http://www.pjrc.com/teensy/arduino_libraries/OneWire.zip", - "include": "OneWire", + "export": { + "include": "OneWire" + }, "frameworks": "arduino", "platforms": "atmelavr" } From b3abee85138fb3bd3826d959e14308e68f708b71 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 23 Aug 2016 00:09:28 +0300 Subject: [PATCH 186/284] Ignore broken libraries; show link to the docs with lib_compat_mode // Resolve #759 --- platformio/builder/tools/piolib.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index a5ab68fe..cf4c31e4 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -479,6 +479,7 @@ def GetLibBuilders(env): return False return True + found_incompat = False for libs_dir in env['LIBSOURCE_DIRS']: libs_dir = env.subst(libs_dir) if not isdir(libs_dir): @@ -486,13 +487,28 @@ def GetLibBuilders(env): for item in sorted(os.listdir(libs_dir)): if item == "__cores__" or not isdir(join(libs_dir, item)): continue - lb = LibBuilderFactory.new(env, join(libs_dir, item)) + try: + lb = LibBuilderFactory.new(env, join(libs_dir, item)) + except ValueError: + sys.stderr.write("Skip library with broken manifest: %s\n" % + join(libs_dir, item)) + continue if _check_lib_builder(lb): items += (lb, ) + else: + found_incompat = True for lb in env.get("EXTRA_LIB_BUILDERS", []): if _check_lib_builder(lb): items += (lb, ) + else: + found_incompat = True + + if verbose and found_incompat: + sys.stderr.write( + "More details about \"Library Compatibility Mode\": " + "http://docs.platformio.org/en/latest/librarymanager/ldf.html#" + "ldf-compat-mode\n") return items From 81d3b7fd1121ebeab9405c5e0bdc8cdeca71fcee Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 23 Aug 2016 11:14:22 +0300 Subject: [PATCH 187/284] Sync with the latest examples --- examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples b/examples index db884f2f..394b9480 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit db884f2fcfb88926d176ac09cbb4e0a72087d351 +Subproject commit 394b9480ef1bc920fe7ad9aa57bd0134f18ce458 From 5a630606991916caed287442d0f958906fff8222 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 23 Aug 2016 13:40:32 +0300 Subject: [PATCH 188/284] Improve support for "library.properties" manifest --- platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index fdc16dd1..78fde02c 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0a6") +VERSION = (3, 0, "0a7") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index cf4c31e4..104ba7ab 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -33,7 +33,9 @@ class LibBuilderFactory(object): @staticmethod def new(env, path): clsname = "UnknownLibBuilder" - if isfile(join(path, "library.json")): + if isfile(join(path, "library.properties")): + clsname = "ArduinoLibBuilder" + elif isfile(join(path, "library.json")): clsname = "PlatformIOLibBuilder" else: env_frameworks = [ @@ -354,8 +356,12 @@ class ArduinoLibBuilder(LibBuilderBase): def src_filter(self): if isdir(join(self.path, "src")): return LibBuilderBase.src_filter.fget(self) - return ["+<*.%s>" % ext - for ext in piotool.SRC_BUILD_EXT + piotool.SRC_HEADER_EXT] + src_filter = [ + "+<*.%s>" % ext + for ext in piotool.SRC_BUILD_EXT + piotool.SRC_HEADER_EXT + ] + src_filter.append("+" + sep) + return src_filter def is_framework_compatible(self, framework): return framework.lower() in ("arduino", "energia") From f1a14a03afd1fab35f478b493c14385bd9c34d7a Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 23 Aug 2016 14:37:14 +0300 Subject: [PATCH 189/284] Update `pio platform` command titles --- platformio/commands/platform.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index fd72f402..a8174436 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -43,7 +43,7 @@ def _print_platforms(platforms): click.echo() -@cli.command("search", short_help="Search for development platforms") +@cli.command("search", short_help="Search for development platform") @click.argument("query", required=False) @click.option("--json-output", is_flag=True) def platform_search(query, json_output): @@ -70,7 +70,7 @@ def platform_search(query, json_output): _print_platforms(platforms) -@cli.command("install", short_help="Install new platforms") +@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) @@ -91,7 +91,7 @@ def platform_install(platforms, with_package, without_package, fg="green") -@cli.command("uninstall", short_help="Uninstall platforms") +@cli.command("uninstall", short_help="Uninstall development platform") @click.argument("platforms", nargs=-1, required=True, metavar="[PLATFORM...]") def platform_uninstall(platforms): pm = PlatformManager() @@ -103,7 +103,7 @@ def platform_uninstall(platforms): fg="green") -@cli.command("update", short_help="Update installed Platforms") +@cli.command("update", short_help="Update installed development platforms") @click.argument("platforms", nargs=-1, required=False, metavar="[PLATFORM...]") @click.option( "-p", @@ -126,7 +126,7 @@ def platform_update(platforms, only_packages, only_check): click.echo() -@cli.command("list", short_help="List installed platforms") +@cli.command("list", short_help="List installed development platforms") @click.option("--json-output", is_flag=True) def platform_list(json_output): platforms = [] @@ -148,7 +148,7 @@ def platform_list(json_output): _print_platforms(platforms) -@cli.command("show", short_help="Show details about installed Platform") +@cli.command("show", short_help="Show details about installed platform") @click.argument("platform") @click.pass_context def platform_show(ctx, platform): From e6fc0e30ec00768ab32b2e97081d51e8d36613d8 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 24 Aug 2016 00:26:28 +0300 Subject: [PATCH 190/284] Update docs for Library Manager --- docs/librarymanager/index.rst | 51 +++++++++++++++++++++++++---------- docs/projectconf.rst | 4 +-- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/docs/librarymanager/index.rst b/docs/librarymanager/index.rst index 1268121a..cb44bd46 100644 --- a/docs/librarymanager/index.rst +++ b/docs/librarymanager/index.rst @@ -14,21 +14,44 @@ Library Manager =============== -*PlatformIO Library Manager* allows you to organize external embedded libraries. -You can search for new libraries via +*PlatformIO Library Manager* is a tool for managing libraries of +`PlatformIO Registry `__ and VCS repositories (Git, +Hg, SVN). It makes it exceedingly simple to find, install and keep libraries +up-to-date. PlatformIO Library Manager supports +`Semantic Versioning `_ and its rules. -* :ref:`Command Line interface ` -* `Web 2.0 Library Search `_ +There 2 options how to find library: -You don't need to bother for finding the latest version of library. Due to -:ref:`cmd_lib_update` command you will have up-to-date external libraries. +* :ref:`Command Line Interface ` +* `Web-based Library Search `__ + +*PlatformIO Library Manager* allows to manage different library storages using +:option:`platformio lib --global` or :option:`platformio lib --storage-dir` +options. + +Project dependencies +-------------------- + +*PlatformIO Library Manager* allows to specify project dependencies +(:ref:`projectconf_lib_deps`) that will be installed automatically per project +before environment processing. You do not need to install libraries manually. +The only one simple step is to define dependencies in :ref:`projectconf`. +You can use library ID, Name or even repository URL. For example, + +.. code-block:: ini + + [env:myenv] + platform = ... + framework = ... + board = ... + lib_deps = + 13 + PubSubClient + Json@~5.6,!=5.4 + https://github.com/gioblu/PJON.git@v2.0 + https://github.com/me-no-dev/ESPAsyncTCP.git + +Please follow to :ref:`cmd_lib_install` for detailed documentation about +possible values. .. image:: ../_static/platformio-demo-lib.gif - -.. toctree:: - :maxdepth: 2 - - User Guide <../userguide/lib/index.rst> - ldf - config - creating diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 42eb6b8a..65ebc182 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -651,7 +651,7 @@ Library options Please make sure to read :ref:`ldf` guide first. Specify project dependencies that should be installed automatically to -:ref:`projectconf_pio_libdeps_dir` before an environment process. +:ref:`projectconf_pio_libdeps_dir` before environment processing. Multiple dependencies are allowed (multi-lines). **Valid forms** @@ -674,7 +674,7 @@ Example: [env:depends_on_some_libs] lib_deps = - 1 + 13 PubSubClient Json@~5.6,!=5.4 https://github.com/gioblu/PJON.git@v2.0 From 35cc57f263bed64c0eea3f52d3e242d40b397328 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 24 Aug 2016 00:28:22 +0300 Subject: [PATCH 191/284] Skip headers from examples --- docs/librarymanager/config.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index 2ab3c7f7..c7680c03 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -452,17 +452,14 @@ A list of example patterns. This field is predefined with default value: "examples": [ "[Ee]xamples/*.c", "[Ee]xamples/*.cpp", - "[Ee]xamples/*.h", "[Ee]xamples/*.ino", "[Ee]xamples/*.pde", "[Ee]xamples/*/*.c", "[Ee]xamples/*/*.cpp", - "[Ee]xamples/*/*.h", "[Ee]xamples/*/*.ino", "[Ee]xamples/*/*.pde", "[Ee]xamples/*/*/*.c", "[Ee]xamples/*/*/*.cpp", - "[Ee]xamples/*/*/*.h", "[Ee]xamples/*/*/*.ino", "[Ee]xamples/*/*/*.pde" ] From 40dbc6c84923c9e05a56278fba828cc271ad6d81 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 24 Aug 2016 13:41:03 +0300 Subject: [PATCH 192/284] Update lib test according to renaming Json lib to ArduinoJson --- tests/commands/test__lib.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/tests/commands/test__lib.py b/tests/commands/test__lib.py index 862c7f26..1aafde58 100644 --- a/tests/commands/test__lib.py +++ b/tests/commands/test__lib.py @@ -36,11 +36,12 @@ def test_search(clirunner, validate_cliresult): def test_global_install_registry(clirunner, validate_cliresult, isolated_pio_home): - result = clirunner.invoke( - cmd_lib, ["-g", "install", "58", "OneWire", "Json@5.4.0", "Json@>5.4"]) + result = clirunner.invoke(cmd_lib, + ["-g", "install", "58", "OneWire", + "ArduinoJson@5.4.0", "ArduinoJson@>5.4"]) validate_cliresult(result) items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] - items2 = ["DHT22_ID58", "Json_ID64", "Json_ID64@5.4.0", "OneWire_ID1"] + items2 = ["DHT22_ID58", "ArduinoJson_ID64", "Json_ID64", "OneWire_ID1"] assert set(items1) == set(items2) @@ -68,20 +69,20 @@ def test_global_lib_list(clirunner, validate_cliresult, isolated_pio_home): for n in ("PJON", "https://developer.mbed.org/users/simon/code/TextLCD/")]) items1 = [i['name'] for i in json.loads(result.output)] - items2 = ["OneWire", "DHT22", "PJON", "ESPAsyncTCP", "Json", "TextLCD", - "pubsubclient"] + items2 = ["OneWire", "DHT22", "PJON", "ESPAsyncTCP", "Json", "ArduinoJson", + "TextLCD", "pubsubclient"] assert set(items1) == set(items2) def test_global_lib_show(clirunner, validate_cliresult, isolated_pio_home): result = clirunner.invoke(cmd_lib, ["-g", "show", "64@5.4.0"]) validate_cliresult(result) - assert all( - [s in result.output for s in ("Json", "arduino", "atmelavr", "5.4.0")]) + assert all([s in result.output + for s in ("Json", "arduino", "atmelavr", "5.4.0")]) - result = clirunner.invoke(cmd_lib, ["-g", "show", "Json@>5.4.0"]) + result = clirunner.invoke(cmd_lib, ["-g", "show", "ArduinoJson@>5.4.0"]) validate_cliresult(result) - assert all([s in result.output for s in ("Json", "arduino", "atmelavr")]) + assert all([s in result.output for s in ("ArduinoJson", "arduino", "atmelavr")]) assert "5.4.0" not in result.output result = clirunner.invoke(cmd_lib, ["-g", "show", "1"]) @@ -98,11 +99,11 @@ def test_global_lib_update(clirunner, validate_cliresult, isolated_pio_home): def test_global_lib_uninstall(clirunner, validate_cliresult, isolated_pio_home): result = clirunner.invoke( - cmd_lib, ["-g", "uninstall", "1", "Json@!=5.4.0", "TextLCD"]) + cmd_lib, ["-g", "uninstall", "1", "ArduinoJson@!=5.4.0", "TextLCD"]) validate_cliresult(result) items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] - items2 = ["DHT22_ID58", "Json_ID64@5.4.0", "ESPAsyncTCP_ID305", - "pubsubclient", "PJON"] + items2 = ["DHT22_ID58", "Json_ID64", "ESPAsyncTCP_ID305", "pubsubclient", + "PJON"] assert set(items1) == set(items2) @@ -113,19 +114,19 @@ def test_project_lib_complex(clirunner, validate_cliresult, tmpdir): validate_cliresult(result) # isntall - result = clirunner.invoke(cmd_lib, ["install", "54", "Json"]) + result = clirunner.invoke(cmd_lib, ["install", "54", "ArduinoJson"]) validate_cliresult(result) items1 = [d.basename for d in tmpdir.join(basename(util.get_projectlibdeps_dir( ))).listdir()] - items2 = ["DallasTemperature_ID54", "OneWire_ID1", "Json_ID64"] + items2 = ["DallasTemperature_ID54", "OneWire_ID1", "ArduinoJson_ID64"] assert set(items1) == set(items2) # list result = clirunner.invoke(cmd_lib, ["list", "--json-output"]) validate_cliresult(result) items1 = [i['name'] for i in json.loads(result.output)] - items2 = ["DallasTemperature", "OneWire", "Json"] + items2 = ["DallasTemperature", "OneWire", "ArduinoJson"] assert set(items1) == set(items2) # update From 69773fc8387c8e96f13ee30c20c1a6be07d2ac62 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 24 Aug 2016 13:47:16 +0300 Subject: [PATCH 193/284] Fix bug with Arduino based library where utility folder is used --- platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 78fde02c..c6e11380 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0a7") +VERSION = (3, 0, "0a8") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 104ba7ab..01f73d20 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -360,7 +360,7 @@ class ArduinoLibBuilder(LibBuilderBase): "+<*.%s>" % ext for ext in piotool.SRC_BUILD_EXT + piotool.SRC_HEADER_EXT ] - src_filter.append("+" + sep) + src_filter.append("+" % sep) return src_filter def is_framework_compatible(self, framework): From e8643528ea8a73153def8fea13194ac50fef4149 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 24 Aug 2016 15:18:45 +0300 Subject: [PATCH 194/284] Test updates for PubSubClient library --- tests/test_maintenance.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/test_maintenance.py b/tests/test_maintenance.py index d444fe1c..b4f7a97d 100644 --- a/tests/test_maintenance.py +++ b/tests/test_maintenance.py @@ -97,7 +97,8 @@ def test_check_pio_upgrade(clirunner, validate_cliresult, isolated_pio_home): def test_check_lib_updates(clirunner, validate_cliresult, isolated_pio_home): # install obsolete library - result = clirunner.invoke(cli_pio, ["lib", "-g", "install", "Json@<5.4"]) + result = clirunner.invoke(cli_pio, + ["lib", "-g", "install", "PubSubClient@<2.6"]) validate_cliresult(result) # reset check time @@ -107,7 +108,8 @@ def test_check_lib_updates(clirunner, validate_cliresult, isolated_pio_home): result = clirunner.invoke(cli_pio, ["lib", "-g", "list"]) validate_cliresult(result) - assert "There are the new updates for libraries (Json)" in result.output + assert ("There are the new updates for libraries (PubSubClient)" in + result.output) def test_check_and_update_libraries(clirunner, validate_cliresult, @@ -128,9 +130,10 @@ def test_check_and_update_libraries(clirunner, validate_cliresult, assert len(prev_data) == 1 # initiate auto-updating - result = clirunner.invoke(cli_pio, ["lib", "-g", "show", "Json"]) + result = clirunner.invoke(cli_pio, ["lib", "-g", "show", "PubSubClient"]) validate_cliresult(result) - assert "There are the new updates for libraries (Json)" in result.output + assert ("There are the new updates for libraries (PubSubClient)" in + result.output) assert "Please wait while updating libraries" in result.output assert "[Out-of-date]" in result.output From 0751c966c429c90469e72497ffa909d755411951 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 24 Aug 2016 20:54:54 +0300 Subject: [PATCH 195/284] Use base name of library path instead manifest name --- platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index c6e11380..934d4304 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0a8") +VERSION = (3, 0, "0a9") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 01f73d20..1e820327 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -131,7 +131,7 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes @property def build_dir(self): - return join("$BUILD_DIR", "lib", self.name) + return join("$BUILD_DIR", "lib", basename(self.path)) def get_inc_dirs(self, use_build_dir=False): return [self.build_dir if use_build_dir else self.src_dir] From aa19b1c424f9a2baa9462269358cd42a7da889d2 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 24 Aug 2016 23:03:41 +0300 Subject: [PATCH 196/284] Show error message when broken JSON manifest is found --- platformio/exception.py | 5 +++++ platformio/managers/platform.py | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/platformio/exception.py b/platformio/exception.py index 7064b34e..5b30ba24 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -60,6 +60,11 @@ class UnknownBoard(PlatformioException): MESSAGE = "Unknown board ID '{0}'" +class InvalidBoardManifest(PlatformioException): + + MESSAGE = "Invalid board JSON manifest '{0}'" + + class UnknownFramework(PlatformioException): MESSAGE = "Unknown framework '{0}'" diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 600c8b4f..97295e40 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -491,7 +491,10 @@ class PlatformBoardConfig(object): self._id = basename(manifest_path)[:-5] assert isfile(manifest_path) self.manifest_path = manifest_path - self._manifest = util.load_json(manifest_path) + try: + self._manifest = util.load_json(manifest_path) + except ValueError: + raise exception.InvalidBoardManifest(manifest_path) assert set(["name", "url", "vendor"]) <= set(self._manifest.keys()) def get(self, path, default=None): From a57ed939234f6fd12d312d5d6fe879502d4c98f8 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 24 Aug 2016 23:50:15 +0300 Subject: [PATCH 197/284] Add information about C/C++ Index Rebuiding --- docs/ide/atom.rst | 14 +++++++------- docs/librarymanager/index.rst | 5 +++++ docs/userguide/lib/cmd_install.rst | 5 +++++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/docs/ide/atom.rst b/docs/ide/atom.rst index 9254e9e1..dc907b24 100644 --- a/docs/ide/atom.rst +++ b/docs/ide/atom.rst @@ -49,7 +49,7 @@ It's built on top of `GitHub's Atom "hackable" text editor `_. If you have already Atom installed, please install `PlatformIO IDE for Atom package `_. .. note:: - You don't need to install PlatformIO CLI seprately to system. + You don't need to install PlatformIO CLI separately to system. PlatformIO CLI is built into PlatformIO IDE and you will be able to use it within PlatformIO IDE Terminal. @@ -95,9 +95,9 @@ then install it and restart Atom: - **Other Systems**: Download the latest `Clang for the other systems `_. .. warning:: - The libraries which are added/installed after initializing process will - not be reflected in code linter. You need ``Menu: PlatformIO > - Rebuild C/C++ Project Index (Autocomplete, Linter)``. + If some libraries are not visible in :ref:`ide_atom` and Code Completion or + Code Linting does not work properly, please perform ``Menu: PlatformIO > + Rebuild C/C++ Project Index (Autocomplete, Linter)`` 3. IDE Installation ~~~~~~~~~~~~~~~~~~~ @@ -337,9 +337,9 @@ automatically created and preconfigured when you initialize project using ``Menu: PlatformIO > Initialize new PlatformIO Project or update existing...``. .. warning:: - The libraries which are added/installed after initializing process will - not be reflected in code linter. You need ``Menu: PlatformIO > - Rebuild C/C++ Project Index (Autocomplete, Linter)``. + If some libraries are not visible in :ref:`ide_atom` and Code Completion or + Code Linting does not work properly, please perform ``Menu: PlatformIO > + Rebuild C/C++ Project Index (Autocomplete, Linter)`` .. error:: diff --git a/docs/librarymanager/index.rst b/docs/librarymanager/index.rst index cb44bd46..8291dd38 100644 --- a/docs/librarymanager/index.rst +++ b/docs/librarymanager/index.rst @@ -54,4 +54,9 @@ You can use library ID, Name or even repository URL. For example, Please follow to :ref:`cmd_lib_install` for detailed documentation about possible values. +.. warning:: + If some libraries are not visible in :ref:`ide_atom` and Code Completion or + Code Linting does not work properly, please perform ``Menu: PlatformIO > + Rebuild C/C++ Project Index (Autocomplete, Linter)`` + .. image:: ../_static/platformio-demo-lib.gif diff --git a/docs/userguide/lib/cmd_install.rst b/docs/userguide/lib/cmd_install.rst index 880920b2..ae130e38 100644 --- a/docs/userguide/lib/cmd_install.rst +++ b/docs/userguide/lib/cmd_install.rst @@ -51,6 +51,11 @@ Usage platformio lib [STORAGE_OPTIONS] install = (name it should have locally) platformio lib [STORAGE_OPTIONS] install ("tag" can be commit, branch or tag) +.. warning:: + If some libraries are not visible in :ref:`ide_atom` and Code Completion or + Code Linting does not work properly, please perform ``Menu: PlatformIO > + Rebuild C/C++ Project Index (Autocomplete, Linter)`` + Description ----------- From 3979ee33a37e37ef2539e710760abb798d58d3ca Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 25 Aug 2016 00:12:03 +0300 Subject: [PATCH 198/284] Update copyrights --- docs/conf.py | 8 ++++---- examples | 2 +- platformio/__init__.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 2a3116cf..5f9474e6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -45,7 +45,7 @@ master_doc = 'index' # General information about the project. project = u'PlatformIO' -copyright = u'2014-2016, Ivan Kravets' +copyright = u'2014-present, PlatformIO' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -199,7 +199,7 @@ latex_elements = { # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'PlatformIO.tex', u'PlatformIO Documentation', - u'Ivan Kravets', 'manual'), + u'PlatformIO', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -229,7 +229,7 @@ latex_documents = [ # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'platformio', u'PlatformIO Documentation', - [u'Ivan Kravets'], 1) + [u'PlatformIO'], 1) ] # If true, show URL addresses after external links. @@ -243,7 +243,7 @@ man_pages = [ # dir menu entry, description, category) texinfo_documents = [ ('index', 'PlatformIO', u'PlatformIO Documentation', - u'Ivan Kravets', 'PlatformIO', 'One line description of project.', + u'PlatformIO', 'PlatformIO', 'One line description of project.', 'Miscellaneous'), ] diff --git a/examples b/examples index 394b9480..a32b1662 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 394b9480ef1bc920fe7ad9aa57bd0134f18ce458 +Subproject commit a32b166297015fd9cb942c4711801e03e3ee9b94 diff --git a/platformio/__init__.py b/platformio/__init__.py index 934d4304..b8e820b0 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -28,7 +28,7 @@ __author__ = "Ivan Kravets" __email__ = "me@ikravets.com" __license__ = "Apache Software License" -__copyright__ = "Copyright 2014-2016 Ivan Kravets" +__copyright__ = "Copyright 2014-present PlatformIO" __apiurl__ = "http://api.platformio.org" __apiip__ = "198.7.57.247" From 62f1f93ad9dcb4e25235b0f6f57527df56fe2698 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 25 Aug 2016 14:14:58 +0300 Subject: [PATCH 199/284] Update history of development platforms --- HISTORY.rst | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 5b7e7d47..7d63d46c 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -65,9 +65,6 @@ PlatformIO 3.0 + Support for the 3rd party manifests (Arduino IDE "library.properties" and ARM mbed "module.json") -* Added support for BBC micro:bit board that is built on the ARM mbed and - Nordic nrf51 platform - (`issue #709 `_) * Print human-readable information when processing environments without ``-v, --verbose`` option (`issue #721 `_) @@ -77,6 +74,26 @@ PlatformIO 3.0 (`issue #740 `_) * Stopped supporting Python 2.6 +* Development platform `Atmel SAM `__ + + + Fixed missing analog ports for Adafruit Feather M0 Bluefruit + (`issue #2 `_) + +* Development platform `Nordic nRF51 `__ + + + Added support for BBC micro:bit board + (`issue #709 `_) + +* Development platform `ST STM32 `__ + + + Added support for BluePill F103C8 board + (`pull #2 `_) + +* Development platform `Teensy `__ + + + Updated Arduino Framework to v1.29 + (`issue #2 `_) + PlatformIO 2.0 -------------- From a352318f0fefd72c58a3b1c7b92538de24b9c74f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 25 Aug 2016 14:18:09 +0300 Subject: [PATCH 200/284] Update broken links to issues --- HISTORY.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 7d63d46c..c667ba14 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -77,7 +77,7 @@ PlatformIO 3.0 * Development platform `Atmel SAM `__ + Fixed missing analog ports for Adafruit Feather M0 Bluefruit - (`issue #2 `_) + (`issue #2 `_) * Development platform `Nordic nRF51 `__ @@ -92,7 +92,7 @@ PlatformIO 3.0 * Development platform `Teensy `__ + Updated Arduino Framework to v1.29 - (`issue #2 `_) + (`issue #2 `_) PlatformIO 2.0 From b1cebe9e0e550d23107873e5ee31bb700f3c4e6d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 25 Aug 2016 14:21:46 +0300 Subject: [PATCH 201/284] Fix unicode issue when search libraries --- platformio/commands/lib.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index 3b434e43..8f39f7fe 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -127,6 +127,10 @@ def echo_liblist_header(): def echo_liblist_item(item): + description = item.get("description", item.get("url", "")).encode("utf-8") + if "version" in item: + description += " | @" + click.style(item['version'], fg="yellow") + click.echo( LIBLIST_TPL.format( id=click.style( @@ -137,10 +141,9 @@ def echo_liblist_item(item): ", ".join( item.get("frameworks", ["-"]) + item.get("platforms", [])), fg="yellow"), - authornames=", ".join(item.get("authornames", ["Unknown"])), - description=item.get("description", item.get("url", ""))) + - (" | @" + click.style( - item['version'], fg="yellow") if "version" in item else "")) + authornames=", ".join(item.get("authornames", ["Unknown"])).encode( + "utf-8"), + description=description)) @cli.command("search", short_help="Search for library") From f51781c76366ea128720131c0660b841c43a9228 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 25 Aug 2016 18:47:39 +0300 Subject: [PATCH 202/284] Add new article --- docs/articles.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/articles.rst b/docs/articles.rst index a219d7c8..a96f6c40 100644 --- a/docs/articles.rst +++ b/docs/articles.rst @@ -23,6 +23,7 @@ Here are recent articles about PlatformIO: 2016 ^^^^ +* Aug 24, 2016 - **Primal Cortex** `Cloud based continuous integration and delivery for IOT using PlatformIO `_ * Aug 18, 2016 - **Primal Cortex** - `Installing PlatformIO on Arch Linux `_ * Jul 26, 2016 - **Embedded Systems Laboratory** - `แนะนำการใช้งาน PlatformIO IDE สำหรับบอร์ด Arduino และ ESP8266 (Get started with PlatformIO IDE for Arduino board and ESP8266, Thai) `_ * Jul 15, 2016 - **Jaime** - `ESP8266 Mobile Rick Roll Captive Portal `_ From 1aabf0ebf5cd89e435c4defb182e1b6778a06696 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 25 Aug 2016 20:40:14 +0300 Subject: [PATCH 203/284] Build System: Attach custom Before/Pre and After/Post actions for targets // Resolve #542 --- HISTORY.rst | 8 +++--- docs/faq.rst | 7 +++++ docs/projectconf.rst | 63 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 68 insertions(+), 10 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index c667ba14..8af993c7 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -65,6 +65,8 @@ PlatformIO 3.0 + Support for the 3rd party manifests (Arduino IDE "library.properties" and ARM mbed "module.json") +* Build System: Attach custom Before/Pre and After/Post actions for targets + (`issue #542 `_) * Print human-readable information when processing environments without ``-v, --verbose`` option (`issue #721 `_) @@ -77,7 +79,7 @@ PlatformIO 3.0 * Development platform `Atmel SAM `__ + Fixed missing analog ports for Adafruit Feather M0 Bluefruit - (`issue #2 `_) + (`issue #2 `__) * Development platform `Nordic nRF51 `__ @@ -87,12 +89,12 @@ PlatformIO 3.0 * Development platform `ST STM32 `__ + Added support for BluePill F103C8 board - (`pull #2 `_) + (`pull #2 `__) * Development platform `Teensy `__ + Updated Arduino Framework to v1.29 - (`issue #2 `_) + (`issue #2 `__) PlatformIO 2.0 diff --git a/docs/faq.rst b/docs/faq.rst index dd30f4bd..47a55571 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -68,6 +68,13 @@ PlatformIO IDE Please refer to :ref:`PlatformIO IDE Frequently Asked Questions `. +Before/Pre and After/Post build actions +--------------------------------------- + +PlatformIO Build System has rich API that allows to attach different pre-/post +actions (hooks). See features of :ref:`projectconf_extra_script` option for +:ref:`projectconf`. + .. _faq_troubleshooting: Troubleshooting diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 65ebc182..d439414c 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -513,6 +513,9 @@ This option can be set by global environment variable ``extra_script`` ^^^^^^^^^^^^^^^^ +.. contents:: + :local: + Allows to launch extra script using `SCons `_ software construction tool. For more details please follow to "Construction Environments" section of @@ -521,13 +524,23 @@ section of This option can be set by global environment variable :envvar:`PLATFORMIO_EXTRA_SCRIPT`. +Take a look at the multiple snippets/answers for the user questions: + + - `#462 Split C/C++ build flags `_ + - `#365 Extra configuration for ESP8266 uploader `_ + - `#351 Specific reset method for ESP8266 `_ + - `#247 Specific options for avrdude `_. + +Custom Uploader +''''''''''''''' + Example, specify own upload command for :ref:`platform_atmelavr`: ``platformio.ini``: .. code-block:: ini - [env:env_with_specific_extra_script] + [env:env_custom_uploader] platform = atmelavr extra_script = /path/to/extra_script.py custom_option = hello @@ -544,14 +557,50 @@ Example, specify own upload command for :ref:`platform_atmelavr`: # print env.Dump() # print ARGUMENTS +Before/Pre and After/Post actions +''''''''''''''''''''''''''''''''' -* see built-in examples of `PlatformIO build scripts `_. -* take a look at the multiple snippets/answers for the user questions: +PlatformIO Build System has rich API that allows to attach different pre-/post +actions (hooks) using ``env.AddPreAction(target, callback)`` function. A first +argument ``target`` can be a name of target that is passed using +:option:`platformio run --target` command or path to file which PlatformIO +processes (ELF, HEX, BIN, etc.). For example, to call function before HEX file +will be created, need to use as a ``$BUILD_DIR/firmware.hex`` target value. + +The example below demonstrates how to call different functions +when :option:`platformio run --target` is called with ``upload`` value. +`extra_script.py` file is located on the same level as ``platformio.ini``. + +``platformio.ini``: + +.. code-block:: ini + + [env:pre_and_post_hooks] + extra_script = extra_script.py + +``extra_script.py``: + +.. code-block:: python + + Import("env") + + def before_upload(source, target, env): + print "before_upload" + # do some actions + + + def after_uploads(source, target, env): + print "after_uploads" + # do some actions + + print "Current build targets", map(str, BUILD_TARGETS) + + # env.AddPreAction("$BUILD_DIR/firmware.elf", callback...) + # env.AddPostAction("$BUILD_DIR/firmware.hex", callback...) + + env.AddPreAction("upload", before_upload) + env.AddPostAction("upload", after_uploads) - - `#462 Split C/C++ build flags `_ - - `#365 Extra configuration for ESP8266 uploader `_ - - `#351 Specific reset method for ESP8266 `_ - - `#247 Specific options for avrdude `_. .. _projectconf_targets: From 1e4ea2dde9f7451b4ac333f44b42a960282a9a97 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 25 Aug 2016 20:47:39 +0300 Subject: [PATCH 204/284] Minor fix --- docs/projectconf.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/projectconf.rst b/docs/projectconf.rst index d439414c..bf182302 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -589,8 +589,8 @@ when :option:`platformio run --target` is called with ``upload`` value. # do some actions - def after_uploads(source, target, env): - print "after_uploads" + def after_upload(source, target, env): + print "after_upload" # do some actions print "Current build targets", map(str, BUILD_TARGETS) @@ -599,7 +599,7 @@ when :option:`platformio run --target` is called with ``upload`` value. # env.AddPostAction("$BUILD_DIR/firmware.hex", callback...) env.AddPreAction("upload", before_upload) - env.AddPostAction("upload", after_uploads) + env.AddPostAction("upload", after_upload) .. _projectconf_targets: From 012d33146c393763a2e9239ddf21a80cc6ead042 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 25 Aug 2016 21:02:20 +0300 Subject: [PATCH 205/284] Use HTTPS PlatformIO API --- platformio/__init__.py | 2 +- platformio/util.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index b8e820b0..1ae99390 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -30,7 +30,7 @@ __email__ = "me@ikravets.com" __license__ = "Apache Software License" __copyright__ = "Copyright 2014-present PlatformIO" -__apiurl__ = "http://api.platformio.org" +__apiurl__ = "https://api.platformio.org" __apiip__ = "198.7.57.247" if sys.version_info < (2, 7, 0) or sys.version_info >= (3, 0, 0): diff --git a/platformio/util.py b/platformio/util.py index c8b8c18f..f32f96d3 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -352,7 +352,7 @@ def get_api_result(path, params=None, data=None, skipdns=False): headers = get_request_defheaders() url = __apiurl__ if skipdns: - url = "http://%s" % __apiip__ + url = "https://%s" % __apiip__ headers['host'] = __apiurl__[__apiurl__.index("://") + 3:] try: From 8cc54bf9be10927c143bb4fb161341009c9b933a Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 25 Aug 2016 22:57:52 +0300 Subject: [PATCH 206/284] Switch to SSL PlatformIO API --- HISTORY.rst | 1 + docs/envvars.rst | 5 +++++ docs/userguide/cmd_settings.rst | 10 ++++++++++ platformio/__init__.py | 2 +- platformio/app.py | 5 +++++ platformio/managers/platform.py | 3 ++- platformio/util.py | 5 +++++ 7 files changed, 29 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 8af993c7..60e9fbf4 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -65,6 +65,7 @@ PlatformIO 3.0 + Support for the 3rd party manifests (Arduino IDE "library.properties" and ARM mbed "module.json") +* Switched to SSL PlatformIO API * Build System: Attach custom Before/Pre and After/Post actions for targets (`issue #542 `_) * Print human-readable information when processing environments without diff --git a/docs/envvars.rst b/docs/envvars.rst index 5931e391..4aea55c0 100644 --- a/docs/envvars.rst +++ b/docs/envvars.rst @@ -165,3 +165,8 @@ Allows to override setting :ref:`setting_enable_telemetry`. .. envvar:: PLATFORMIO_SETTING_FORCE_VERBOSE Allows to override setting :ref:`setting_force_verbose`. + + +.. envvar:: PLATFORMIO_SETTING_DISABLE_SSL + +Allows to override setting :ref:`setting_disable_ssl`. diff --git a/docs/userguide/cmd_settings.rst b/docs/userguide/cmd_settings.rst index 04be4260..0219b076 100644 --- a/docs/userguide/cmd_settings.rst +++ b/docs/userguide/cmd_settings.rst @@ -87,6 +87,16 @@ Check for the new PlatformIO interval. Check for the platform updates interval. +.. _setting_disable_ssl: + +``disable_ssl`` +^^^^^^^^^^^^^^^ + +:Default: No +:Values: Yes/No + +Disable SSL for PlatformIO API (NOT RECOMMENDED, INSECURE) + .. _setting_force_verbose: ``force_verbose`` diff --git a/platformio/__init__.py b/platformio/__init__.py index 1ae99390..28860527 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0a9") +VERSION = (3, 0, "0a10") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/app.py b/platformio/app.py index 3bacc180..507bf528 100644 --- a/platformio/app.py +++ b/platformio/app.py @@ -48,6 +48,11 @@ DEFAULT_SETTINGS = { "description": "Force verbose output when processing environments", "value": False }, + "disable_ssl": { + "description": ("Disable SSL for PlatformIO API " + "(NOT RECOMMENDED, INSECURE)"), + "value": False + }, "enable_telemetry": { "description": ("Telemetry service Date: Fri, 26 Aug 2016 01:29:26 +0300 Subject: [PATCH 207/284] Show error when boards manifest doesn't contain required fields --- platformio/exception.py | 2 +- platformio/managers/platform.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/platformio/exception.py b/platformio/exception.py index 5b30ba24..6d3a7641 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -45,7 +45,7 @@ class UnknownPlatform(PlatformioException): class PlatformNotInstalledYet(PlatformioException): MESSAGE = "The platform '{0}' has not been installed yet. "\ - "Use `platformio platforms install {0}` command" + "Use `platformio platform install {0}` command" class BoardNotDefined(PlatformioException): diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index ce37665c..fb53d255 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -496,7 +496,10 @@ class PlatformBoardConfig(object): self._manifest = util.load_json(manifest_path) except ValueError: raise exception.InvalidBoardManifest(manifest_path) - assert set(["name", "url", "vendor"]) <= set(self._manifest.keys()) + if not set(["name", "url", "vendor"]) <= set(self._manifest.keys()): + raise exception.PlatformioException( + "Please specify name, url and vendor fields for " + + manifest_path) def get(self, path, default=None): try: From de62e5082eaa30669bc69637085743a2e5975f43 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 26 Aug 2016 01:42:05 +0300 Subject: [PATCH 208/284] Handle WindowsError when can't create .pioenvs directory --- platformio/commands/run.py | 2 +- platformio/util.py | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 83a62cd3..825d09ac 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -63,7 +63,7 @@ def cli(ctx, # pylint: disable=R0913,R0914 click.secho( "Can not remove temporary directory `%s`. Please remove " "`.pioenvs` directory from the project manually to avoid " - "build issues" % util.get_projectpioenvs_dir(), + "build issues" % util.get_projectpioenvs_dir(force=True), fg="yellow") config = util.load_project_config() diff --git a/platformio/util.py b/platformio/util.py index 21b60c2c..b08db611 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -218,18 +218,22 @@ def get_projecttest_dir(): "test")) -def get_projectpioenvs_dir(): +def get_projectpioenvs_dir(force=False): path = _get_projconf_option_dir("envs_dir", join(get_project_dir(), ".pioenvs")) - if not isdir(path): - os.makedirs(path) - dontmod_path = join(path, "do-not-modify-files-here.url") - if not isfile(dontmod_path): - with open(dontmod_path, "w") as fp: - fp.write(""" + try: + if not isdir(path): + os.makedirs(path) + dontmod_path = join(path, "do-not-modify-files-here.url") + if not isfile(dontmod_path): + with open(dontmod_path, "w") as fp: + fp.write(""" [InternetShortcut] URL=http://docs.platformio.org/en/stable/projectconf.html#envs-dir """) + except Exception as e: + if not force: + raise Exception(e) return path From f9e8ea66eaa88540f3a62276376577df40745d86 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 26 Aug 2016 11:46:59 +0300 Subject: [PATCH 209/284] Remove ``enable_prompts`` setting. Now, all PlatformIO CLI is non-blocking! --- .pylintrc | 2 +- HISTORY.rst | 4 ++-- docs/envvars.rst | 8 ++----- docs/faq.rst | 15 ------------- docs/installation.rst | 5 ----- docs/userguide/cmd_settings.rst | 19 ---------------- docs/userguide/index.rst | 3 +-- platformio/__init__.py | 2 +- platformio/app.py | 19 ++-------------- platformio/commands/lib.py | 39 +++++++++++++++++++++++---------- platformio/commands/platform.py | 12 +++------- platformio/commands/test.py | 9 ++++---- platformio/managers/lib.py | 36 ++++++++++++++++++++---------- platformio/managers/package.py | 5 ++++- platformio/managers/platform.py | 11 ++++++---- platformio/telemetry.py | 21 +++++------------- platformio/util.py | 9 ++++---- tests/conftest.py | 2 +- 18 files changed, 91 insertions(+), 130 deletions(-) diff --git a/.pylintrc b/.pylintrc index bdf25c27..66581ace 100644 --- a/.pylintrc +++ b/.pylintrc @@ -20,4 +20,4 @@ confidence= # --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 +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 diff --git a/HISTORY.rst b/HISTORY.rst index 60e9fbf4..6f289027 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -65,6 +65,7 @@ PlatformIO 3.0 + Support for the 3rd party manifests (Arduino IDE "library.properties" and ARM mbed "module.json") +* Removed ``enable_prompts`` setting. Now, all PlatformIO CLI is non-blocking! * Switched to SSL PlatformIO API * Build System: Attach custom Before/Pre and After/Post actions for targets (`issue #542 `_) @@ -1126,8 +1127,7 @@ PlatformIO 0.0 ~~~~~~~~~~~~~~~~~~ * Replaced "dark blue" by "cyan" colour for the texts (`issue #33 `_) -* Added new setting `enable_prompts `_ - and allowed to disable all *PlatformIO* prompts (useful for cloud compilers) +* Added new setting ``enable_prompts`` and allowed to disable all *PlatformIO* prompts (useful for cloud compilers) (`issue #34 `_) * Fixed compilation bug on *Windows* with installed *MSVC* (`issue #18 `_) diff --git a/docs/envvars.rst b/docs/envvars.rst index 4aea55c0..7749e9ce 100644 --- a/docs/envvars.rst +++ b/docs/envvars.rst @@ -35,8 +35,8 @@ PlatformIO handles ``CI`` variable which is setup by `Continuous Integration `_ (Travis, Circle and etc.) systems. PlatformIO uses it to disable prompts and progress bars. In other words, -``CI=true`` automatically setup :envvar:`PLATFORMIO_SETTING_ENABLE_PROMPTS` to -``false`` and :envvar:`PLATFORMIO_DISABLE_PROGRESSBAR` to ``true``. +``CI=true`` automatically setup :envvar:`PLATFORMIO_DISABLE_PROGRESSBAR` to +``true``. .. envvar:: PLATFORMIO_FORCE_COLOR @@ -154,10 +154,6 @@ Allows to override setting :ref:`setting_check_platformio_interval`. Allows to override setting :ref:`setting_check_platforms_interval`. -.. envvar:: PLATFORMIO_SETTING_ENABLE_PROMPTS - -Allows to override setting :ref:`setting_enable_prompts`. - .. envvar:: PLATFORMIO_SETTING_ENABLE_TELEMETRY Allows to override setting :ref:`setting_enable_telemetry`. diff --git a/docs/faq.rst b/docs/faq.rst index 47a55571..8e054883 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -139,21 +139,6 @@ Please upgrade *SetupTools* package: Miscellaneous ~~~~~~~~~~~~~ -.. _faq_troubleshooting_pioblocksprompt: - -PlatformIO blocks command execution using user prompt -''''''''''''''''''''''''''''''''''''''''''''''''''''' - -If you are going to run *PlatformIO* from **subprocess**, you **MUST -DISABLE** all prompts. It will allow you to avoid blocking. -There are a few options: - -- using :option:`platformio --force` option before each command -- using environment variable :envvar:`PLATFORMIO_SETTING_ENABLE_PROMPTS=No ` -- disable global setting ``enable_prompts`` via :ref:`cmd_settings` command -- masking under Continuous Integration system via environment variable - :envvar:`CI=true `. - Serial does not work with panStampAVR board ''''''''''''''''''''''''''''''''''''''''''' diff --git a/docs/installation.rst b/docs/installation.rst index 53dd81ca..81af129a 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -200,11 +200,6 @@ To revert to the latest stable version Troubleshooting --------------- -.. warning:: - If you are going to run *PlatformIO* from **subprocess**, you - :ref:`MUST DISABLE ` all prompts. - It will allow you to avoid blocking. - .. note:: **Linux OS**: Don't forget to install "udev" rules file `99-platformio-udev.rules `_ (an instruction is located in the file). diff --git a/docs/userguide/cmd_settings.rst b/docs/userguide/cmd_settings.rst index 0219b076..2605ed74 100644 --- a/docs/userguide/cmd_settings.rst +++ b/docs/userguide/cmd_settings.rst @@ -111,24 +111,6 @@ Force verbose output when processing environments. This setting overrides * :option:`platformio ci --verbose` * :option:`platformio test --verbose` -.. _setting_enable_prompts: - -``enable_prompts`` -^^^^^^^^^^^^^^^^^^ - -:Default: Yes -:Values: Yes/No - -Can PlatformIO communicate with you via prompts? - -* propose to install platforms which aren't installed yet -* paginate over library search results -* and etc. - -.. warning:: - If you are going to run *PlatformIO* from **subprocess**, you **MUST - DISABLE** all prompts. It will allow you to avoid blocking. - .. _setting_enable_telemetry: ``enable_telemetry`` @@ -172,7 +154,6 @@ Examples check_libraries_interval 7 Check for the library updates interval (days) check_platformio_interval 3 Check for the new PlatformIO interval (days) check_platforms_interval 7 Check for the platform updates interval (days) - enable_prompts Yes Can PlatformIO communicate with you via prompts ... enable_telemetry Yes Telemetry service (Yes/No) diff --git a/docs/userguide/index.rst b/docs/userguide/index.rst index 05ada62a..d6a49049 100644 --- a/docs/userguide/index.rst +++ b/docs/userguide/index.rst @@ -34,8 +34,7 @@ Options .. option:: --force, -f -Force to accept any confirmation prompts. This option allows to avoid an issue -with :ref:`faq_troubleshooting_pioblocksprompt` +Force to accept any confirmation prompts and disable progress bars. .. option:: --version diff --git a/platformio/__init__.py b/platformio/__init__.py index 28860527..f002cab1 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0a10") +VERSION = (3, 0, "0a11") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/app.py b/platformio/app.py index 507bf528..42c8ee8d 100644 --- a/platformio/app.py +++ b/platformio/app.py @@ -58,15 +58,6 @@ DEFAULT_SETTINGS = { ("Telemetry service (Yes/No)"), "value": True - }, - "enable_prompts": { - "description": - ("Can PlatformIO communicate with you via prompts: " - "propose to install platforms which aren't installed yet, " - "paginate over library search results and etc.)? ATTENTION!!! " - "If you call PlatformIO like subprocess, " - "please disable prompts to avoid blocking (Yes/No)"), - "value": True } } @@ -148,12 +139,6 @@ def set_state_item(name, value): def get_setting(name): - if name == "enable_prompts": - # disable prompts for Continuous Integration systems - # and when global "--force" option is set - if any([util.is_ci(), get_session_var("force_option")]): - return False - _env_name = "PLATFORMIO_SETTING_%s" % name.upper() if _env_name in environ: return sanitize_setting(name, getenv(_env_name)) @@ -188,5 +173,5 @@ def set_session_var(name, value): def is_disabled_progressbar(): - return (not get_setting("enable_prompts") or - getenv("PLATFORMIO_DISABLE_PROGRESSBAR") == "true") + return any([get_session_var("force_option"), util.is_ci(), + getenv("PLATFORMIO_DISABLE_PROGRESSBAR") == "true"]) diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index 8f39f7fe..348c3e05 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -14,10 +14,11 @@ import json from os.path import join +from time import sleep import click -from platformio import app, exception, util +from platformio import exception, util from platformio.managers.lib import LibraryManager from platformio.util import get_api_result @@ -75,11 +76,15 @@ def cli(ctx, **options): # "library dependencies") @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.pass_obj -def lib_install(lm, libraries, silent): +def lib_install(lm, libraries, silent, interactive): # @TODO "save" option for library in libraries: - lm.install(library, silent=silent) + lm.install(library, silent=silent, interactive=interactive) @cli.command("uninstall", short_help="Uninstall libraries") @@ -147,6 +152,7 @@ def echo_liblist_item(item): @cli.command("search", short_help="Search for 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("-n", "--name", multiple=True) @@ -154,8 +160,11 @@ def echo_liblist_item(item): @click.option("-k", "--keyword", multiple=True) @click.option("-f", "--framework", multiple=True) @click.option("-p", "--platform", multiple=True) -@click.argument("query", required=False, nargs=-1) -def lib_search(query, json_output, page, **filters): +@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): @@ -205,14 +214,20 @@ def lib_search(query, json_output, page, **filters): int(result['total'])): break - if (app.get_setting("enable_prompts") and - click.confirm("Show next libraries?")): - result = get_api_result( - "/lib/search", - dict( - query=" ".join(query), page=int(result['page']) + 1)) - else: + if noninteractive: + click.echo() + click.secho( + "Loading next %d libraries... Press Ctrl+C to stop!" % + result['perpage'], + fg="yellow") + click.echo() + sleep(5) + elif not click.confirm("Show next libraries?"): break + result = get_api_result( + "/lib/search", + dict( + query=" ".join(query), page=int(result['page']) + 1)) @cli.command("list", short_help="List installed libraries") diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index a8174436..c69c8ceb 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -16,7 +16,7 @@ import json import click -from platformio import app, exception, util +from platformio import exception, util from platformio.managers.platform import PlatformFactory, PlatformManager @@ -150,17 +150,11 @@ def platform_list(json_output): @cli.command("show", short_help="Show details about installed platform") @click.argument("platform") -@click.pass_context -def platform_show(ctx, platform): +def platform_show(platform): try: p = PlatformFactory.newPlatform(platform) except exception.UnknownPlatform: - if (not app.get_setting("enable_prompts") or - click.confirm("The platform '%s' has not been installed yet. " - "Would you like to install it now?" % platform)): - ctx.invoke(platform_install, platforms=[platform]) - else: - raise exception.PlatformNotInstalledYet(platform) + raise exception.PlatformNotInstalledYet(platform) click.echo("{name} ~ {title}".format( name=click.style( diff --git a/platformio/commands/test.py b/platformio/commands/test.py index 6afe1bcd..6820fa31 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -70,10 +70,11 @@ def cli(ctx, environment, ignore, upload_port, project_dir, verbose): # check ignore patterns _ignore = list(ignore) if projectconf.has_option(section, "test_ignore"): - _ignore.extend([p.strip() - for p in projectconf.get( - section, "test_ignore").split(",") - if p.strip()]) + _ignore.extend([ + p.strip() + for p in projectconf.get(section, "test_ignore").split(",") + if p.strip() + ]) if testname != "*" and \ any([fnmatch(testname, p) for p in _ignore]): results.append((None, testname, envname)) diff --git a/platformio/managers/lib.py b/platformio/managers/lib.py index 730d6b7e..a8a5af23 100644 --- a/platformio/managers/lib.py +++ b/platformio/managers/lib.py @@ -18,7 +18,7 @@ from os.path import join import click import semantic_version -from platformio import app, commands, exception, util +from platformio import commands, exception, util from platformio.managers.package import BasePkgManager @@ -106,7 +106,11 @@ class LibraryManager(BasePkgManager): name, requirements)), requirements) return item['version'] if item else None - def _get_pkg_id_by_name(self, name, requirements, silent=False): + def _get_pkg_id_by_name(self, + name, + requirements, + silent=False, + interactive=False): if name.startswith("id="): return int(name[3:]) # try to find ID from installed packages @@ -115,7 +119,8 @@ class LibraryManager(BasePkgManager): manifest = self.load_manifest(installed_dir) if "id" in manifest: return int(manifest['id']) - return int(self.search_for_library({"name": name}, silent)['id']) + return int( + self.search_for_library({"name": name}, silent, interactive)['id']) def _install_from_piorepo(self, name, requirements): assert name.startswith("id=") @@ -136,15 +141,16 @@ class LibraryManager(BasePkgManager): requirements) return pkg_dir - def install(self, + def install(self, # pylint: disable=too-many-arguments name, requirements=None, silent=False, - trigger_event=True): + trigger_event=True, + interactive=False): _name, _requirements, _url = self.parse_pkg_name(name, requirements) if not _url: _name = "id=%d" % self._get_pkg_id_by_name( - _name, _requirements, silent=silent) + _name, _requirements, silent=silent, interactive=interactive) already_installed = self.get_installed_dir(_name, _requirements, _url) pkg_dir = BasePkgManager.install(self, _name if not _url else name, _requirements, silent, trigger_event) @@ -164,7 +170,8 @@ class LibraryManager(BasePkgManager): if any([s in filters.get("version", "") for s in ("\\", "/")]): self.install("{name}={version}".format(**filters)) else: - lib_info = self.search_for_library(filters, silent) + lib_info = self.search_for_library(filters, silent, + interactive) if filters.get("version"): self.install( lib_info['id'], @@ -180,7 +187,9 @@ class LibraryManager(BasePkgManager): @staticmethod def search_for_library( # pylint: disable=too-many-branches - filters, silent=False): + filters, + silent=False, + interactive=False): assert isinstance(filters, dict) assert "name" in filters if not silent: @@ -206,13 +215,18 @@ class LibraryManager(BasePkgManager): click.secho( "Conflict: More than one library has been found " "by request %s:" % json.dumps(filters), - fg="red") + fg="red", + err=True) commands.lib.echo_liblist_header() for item in result['items']: commands.lib.echo_liblist_item(item) - if not app.get_setting("enable_prompts"): - click.echo("Automatically chose the first available library") + if not interactive: + click.secho( + "Automatically chose the first available library " + "(use `--interactive` option to make a choice)", + fg="yellow", + err=True) lib_info = result['items'][0] else: deplib_id = click.prompt( diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 424a69a7..23ff4483 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -27,6 +27,8 @@ from platformio.downloader import FileDownloader from platformio.unpacker import FileUnpacker from platformio.vcsclient import VCSClientFactory +# pylint: disable=too-many-arguments + class PackageRepoIterator(object): @@ -424,7 +426,8 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): name, requirements=None, silent=False, - trigger_event=True): + trigger_event=True, + interactive=False): # pylint: disable=unused-argument name, requirements, url = self.parse_pkg_name(name, requirements) installed_dir = self.get_installed_dir(name, requirements, url) diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index fb53d255..fcfe3038 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -43,10 +43,13 @@ class PlatformManager(BasePkgManager): def manifest_name(self): return "platform.json" - def install(self, # pylint: disable=too-many-arguments,arguments-differ - name, requirements=None, silent=False, - trigger_event=True, with_packages=None, - without_packages=None, skip_default_package=False): + def install(self, # pylint: disable=too-many-arguments + name, + requirements=None, + with_packages=None, + without_packages=None, + skip_default_package=False, + **_): platform_dir = BasePkgManager.install(self, name, requirements) p = PlatformFactory.newPlatform(self.get_manifest_path(platform_dir)) p.install_packages(with_packages, without_packages, diff --git a/platformio/telemetry.py b/platformio/telemetry.py index b863f862..47150149 100644 --- a/platformio/telemetry.py +++ b/platformio/telemetry.py @@ -27,7 +27,6 @@ import click import requests from platformio import __version__, app, exception, util -from platformio.ide.projectgenerator import ProjectGenerator class TelemetryBase(object): @@ -60,7 +59,7 @@ class TelemetryBase(object): class MeasurementProtocol(TelemetryBase): - TRACKING_ID = "UA-1768265-9" + TID = "UA-1768265-9" PARAMS_MAP = { "screen_name": "cd", "event_category": "ec", @@ -72,7 +71,7 @@ class MeasurementProtocol(TelemetryBase): def __init__(self): TelemetryBase.__init__(self) self['v'] = 1 - self['tid'] = self.TRACKING_ID + self['tid'] = self.TID self['cid'] = self.get_cid() self['sr'] = "%dx%d" % click.get_terminal_size() @@ -106,8 +105,9 @@ class MeasurementProtocol(TelemetryBase): self['cd1'] = util.get_systype() self['cd2'] = "Python/%s %s" % (platform.python_version(), platform.platform()) - self['cd4'] = (1 if app.get_setting("enable_prompts") or - app.get_session_var("caller_id") else 0) + self['cd4'] = 1 if not util.is_ci() else 0 + if app.get_session_var("caller_id"): + self['cd5'] = str(app.get_session_var("caller_id")).lower() def _prefill_screen_name(self): self['cd3'] = " ".join([str(s).lower() for s in sys.argv[1:]]) @@ -227,9 +227,6 @@ def on_command(): if util.is_ci(): measure_ci() - if app.get_session_var("caller_id"): - measure_caller(app.get_session_var("caller_id")) - def measure_ci(): event = {"category": "CI", "action": "NoName", "label": None} @@ -251,14 +248,6 @@ def measure_ci(): on_event(**event) -def measure_caller(calller_id): - calller_id = str(calller_id)[:20].lower() - event = {"category": "Caller", "action": "Misc", "label": calller_id} - if calller_id in (["atom", "vim"] + ProjectGenerator.get_supported_ides()): - event['action'] = "IDE" - on_event(**event) - - def on_run_environment(options, targets): opts = ["%s=%s" % (opt, value) for opt, value in sorted(options.items())] targets = [t.title() for t in targets or ["run"]] diff --git a/platformio/util.py b/platformio/util.py index b08db611..dcbf298a 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -231,7 +231,7 @@ def get_projectpioenvs_dir(force=False): [InternetShortcut] URL=http://docs.platformio.org/en/stable/projectconf.html#envs-dir """) - except Exception as e: + except Exception as e: # pylint: disable=broad-except if not force: raise Exception(e) return path @@ -348,9 +348,10 @@ def _api_request_session(): return requests.Session() -def get_api_result(path, params=None, data=None, skipdns=False): +def get_api_result(path, # pylint: disable=too-many-branches + params=None, data=None, skipdns=False): import requests - import app + from platformio.app import get_setting result = None r = None @@ -361,7 +362,7 @@ def get_api_result(path, params=None, data=None, skipdns=False): url = "https://%s" % __apiip__ headers['host'] = __apiurl__[__apiurl__.index("://") + 3:] - if app.get_setting("disable_ssl"): + if get_setting("disable_ssl"): url = url.replace("https://", "http://") try: diff --git a/tests/conftest.py b/tests/conftest.py index 8483d8b9..a6cf052d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -20,7 +20,7 @@ from click.testing import CliRunner @pytest.fixture(scope="session") def platformio_setup(request): - pioenvvars = ("ENABLE_PROMPTS", "ENABLE_TELEMETRY") + pioenvvars = ("ENABLE_TELEMETRY", ) for v in pioenvvars: os.environ["PLATFORMIO_SETTING_%s" % v] = "No" From 6e26ce816263c56b91d3386a8d7aedf5d055d164 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 26 Aug 2016 12:30:37 +0300 Subject: [PATCH 210/284] Better exception handling --- platformio/commands/lib.py | 9 +++------ platformio/exception.py | 10 ++++++++++ platformio/managers/lib.py | 5 ++++- platformio/telemetry.py | 4 +++- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index 348c3e05..ba179b63 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -55,12 +55,9 @@ def cli(ctx, **options): storage_dir = util.get_projectlibdeps_dir() if not storage_dir and not util.is_platformio_project(): - raise exception.PlatformioException( - "The `%s` is not a PlatformIO project.\nTo manage libraries " - "in the global storage `%s`, please use " - "`platformio lib --global %s` instead." % - (util.get_project_dir(), join(util.get_home_dir(), "lib"), - ctx.invoked_subcommand)) + raise exception.NotGlobalLibDir(util.get_project_dir(), + join(util.get_home_dir(), "lib"), + ctx.invoked_subcommand) ctx.obj = LibraryManager(storage_dir) if "--json-output" not in ctx.args: diff --git a/platformio/exception.py b/platformio/exception.py index 6d3a7641..4baf827f 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -156,6 +156,16 @@ class LibNotFound(PlatformioException): MESSAGE = "Library `{0}` has not been found in the registry" +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}'" diff --git a/platformio/managers/lib.py b/platformio/managers/lib.py index a8a5af23..379b6d22 100644 --- a/platformio/managers/lib.py +++ b/platformio/managers/lib.py @@ -238,7 +238,10 @@ class LibraryManager(BasePkgManager): break if not lib_info: - raise exception.LibNotFound(str(filters)) + if filters.keys() == ["name"]: + raise exception.LibNotFound(filters['name']) + else: + raise exception.LibNotFound(str(filters)) if not silent: click.echo("Found: %s" % click.style( "http://platformio.org/lib/show/{id}/{name}".format( diff --git a/platformio/telemetry.py b/platformio/telemetry.py index 47150149..08a8302d 100644 --- a/platformio/telemetry.py +++ b/platformio/telemetry.py @@ -268,7 +268,9 @@ def on_event(category, action, label=None, value=None, screen_name=None): def on_exception(e): - if isinstance(e, exception.AbortedByUser): + if any([isinstance(e, cls) + for cls in (IOError, exception.AbortedByUser, + exception.NotGlobalLibDir)]): return is_crash = any([ not isinstance(e, exception.PlatformioException), From c637729eaed5f73b0d9aa14b5391df06266f8d7b Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 26 Aug 2016 14:25:50 +0300 Subject: [PATCH 211/284] Rename ``platformio serialports`` command to ``platformio device`` --- HISTORY.rst | 1 + docs/index.rst | 2 +- docs/projectconf.rst | 2 +- .../{cmd_serialports.rst => cmd_device.rst} | 34 +++++++++---------- docs/userguide/cmd_run.rst | 2 +- docs/userguide/cmd_test.rst | 2 +- docs/userguide/index.rst | 2 +- platformio/__main__.py | 7 ++-- .../commands/{serialports.py => device.py} | 14 ++++---- platformio/commands/init.py | 3 +- platformio/managers/package.py | 1 + tests/conftest.py | 5 +++ 12 files changed, 43 insertions(+), 32 deletions(-) rename docs/userguide/{cmd_serialports.rst => cmd_device.rst} (91%) rename platformio/commands/{serialports.py => device.py} (95%) diff --git a/HISTORY.rst b/HISTORY.rst index 6f289027..6be89824 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -67,6 +67,7 @@ PlatformIO 3.0 * Removed ``enable_prompts`` setting. Now, all PlatformIO CLI is non-blocking! * Switched to SSL PlatformIO API +* Renamed ``platformio serialports`` command to ``platformio device`` * Build System: Attach custom Before/Pre and After/Post actions for targets (`issue #542 `_) * Print human-readable information when processing environments without diff --git a/docs/index.rst b/docs/index.rst index 387fd68e..abea5247 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -55,7 +55,7 @@ Embedded Development. *Easier Than Ever.* * :ref:`IDE Integration ` with *Arduino, Atom, CLion, Eclipse, Emacs, Energia, Qt Creator, Sublime Text, Vim, Visual Studio* * Cloud compiling and :ref:`ci` with *AppVeyor, Circle CI, Drone, Shippable, Travis CI* -* Built-in :ref:`Serial Port Monitor ` and +* Built-in :ref:`Serial Port Monitor ` and configurable build :ref:`-flags/-options ` * Pre-built toolchains, :ref:`frameworks` for the :ref:`platforms` diff --git a/docs/projectconf.rst b/docs/projectconf.rst index bf182302..dd2c2c0a 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -647,7 +647,7 @@ This option is used by "uploader" tool when sending firmware to board via If ``upload_port`` isn't specified, then *PlatformIO* will try to detect it automatically. -To print all available serial ports use :ref:`cmd_serialports` command. +To print all available serial ports use :ref:`cmd_device` command. This option can be set by global environment variable :envvar:`PLATFORMIO_UPLOAD_PORT`. diff --git a/docs/userguide/cmd_serialports.rst b/docs/userguide/cmd_device.rst similarity index 91% rename from docs/userguide/cmd_serialports.rst rename to docs/userguide/cmd_device.rst index 882a5f02..91d2fcd2 100644 --- a/docs/userguide/cmd_serialports.rst +++ b/docs/userguide/cmd_device.rst @@ -9,14 +9,14 @@ See the License for the specific language governing permissions and limitations under the License. -.. _cmd_serialports: +.. _cmd_device: -platformio serialports +platformio device ====================== .. contents:: -platformio serialports list +platformio device list --------------------------- Usage @@ -24,7 +24,7 @@ Usage .. code-block:: bash - platformio serialports list [OPTIONS] + platformio device list [OPTIONS] Description @@ -35,7 +35,7 @@ List available `Serial Ports `_ Options ~~~~~~~ -.. program:: platformio serialports list +.. program:: platformio device list .. option:: --json-output @@ -50,7 +50,7 @@ Examples .. code-block:: bash - $ platformio serialports list + $ platformio device list /dev/cu.SLAB_USBtoUART ---------- Hardware ID: USB VID:PID=10c4:ea60 SNR=0001 @@ -66,7 +66,7 @@ Examples .. code-block:: bash - $ platformio serialports list + $ platformio device list COM4 ---------- Hardware ID: USB VID:PID=0451:F432 @@ -78,9 +78,9 @@ Examples Description: Silicon Labs CP210x USB to UART Bridge (COM3) -.. _cmd_serialports_monitor: +.. _cmd_device_monitor: -platformio serialports monitor +platformio device monitor ------------------------------ Usage @@ -88,7 +88,7 @@ Usage .. code-block:: bash - platformio serialports monitor [OPTIONS] + platformio device monitor [OPTIONS] Description @@ -112,7 +112,7 @@ To control *monitor* please use these "hot keys": Options ~~~~~~~ -.. program:: platformio serialports monitor +.. program:: platformio device monitor .. option:: -p, --port @@ -194,7 +194,7 @@ ASCII code of special character that is used to exit the application, default ``29`` (DEC). For example, to use ``Ctrl+Q`` run -``platformio serialports monitor --exit-char 17``. +``platformio device monitor --exit-char 17``. .. option:: --menu-char @@ -238,8 +238,8 @@ multiple times: 3. hex dump everything **REMOVED**: Is not available in Miniterm/PySerial 3.0. -See :option:`platformio serialports monitor --encoding` and -:option:`platformio serialports monitor --filter` options. +See :option:`platformio device monitor --encoding` and +:option:`platformio device monitor --filter` options. Examples ~~~~~~~~ @@ -248,8 +248,8 @@ Examples .. code-block:: bash - $ platformio serialports monitor --help - Usage: platformio serialports monitor [OPTIONS] + $ platformio device monitor --help + Usage: platformio device monitor [OPTIONS] Options: -p, --port TEXT Port, a number or a device name @@ -276,7 +276,7 @@ Examples .. code-block:: bash - $ platformio serialports monitor + $ platformio device monitor --- Available ports: --- /dev/cu.Bluetooth-Incoming-Port n/a diff --git a/docs/userguide/cmd_run.rst b/docs/userguide/cmd_run.rst index c5b75ea3..b785a7a5 100644 --- a/docs/userguide/cmd_run.rst +++ b/docs/userguide/cmd_run.rst @@ -64,7 +64,7 @@ Pre-built targets: --upload-port Upload port of embedded board. To print all available ports use -:ref:`cmd_serialports` command. +:ref:`cmd_device` command. If upload port is not specified, PlatformIO will try to detect it automatically. diff --git a/docs/userguide/cmd_test.rst b/docs/userguide/cmd_test.rst index 7c74361d..e34ea0c0 100644 --- a/docs/userguide/cmd_test.rst +++ b/docs/userguide/cmd_test.rst @@ -76,7 +76,7 @@ For example, ``platformio test --ignore "mytest*" -i "test[13]"`` --upload-port Upload port of embedded board. To print all available ports use -:ref:`cmd_serialports` command. +:ref:`cmd_device` command. If upload port is not specified, PlatformIO will try to detect it automatically. diff --git a/docs/userguide/index.rst b/docs/userguide/index.rst index d6a49049..2a3b0f2a 100644 --- a/docs/userguide/index.rst +++ b/docs/userguide/index.rst @@ -60,10 +60,10 @@ Commands cmd_boards cmd_ci + cmd_device cmd_init platformio platform cmd_run - cmd_serialports cmd_settings cmd_test cmd_update diff --git a/platformio/__main__.py b/platformio/__main__.py index 08679523..5ee08cb9 100644 --- a/platformio/__main__.py +++ b/platformio/__main__.py @@ -52,8 +52,11 @@ class PlatformioCLI(click.MultiCommand): # pylint: disable=R0904 @staticmethod def _handle_obsolate_command(name): if name == "platforms": - from platformio.commands import platform - return platform.cli + from platformio.commands.platform import cli + return cli + elif name == "serialports": + from platformio.commands.device import cli + return cli raise AttributeError() diff --git a/platformio/commands/serialports.py b/platformio/commands/device.py similarity index 95% rename from platformio/commands/serialports.py rename to platformio/commands/device.py index a42e59f6..e423f273 100644 --- a/platformio/commands/serialports.py +++ b/platformio/commands/device.py @@ -24,14 +24,14 @@ from platformio.exception import MinitermException from platformio.util import get_serialports -@click.group(short_help="List or Monitor Serial ports") +@click.group(short_help="Monitor device or list existing") def cli(): pass -@cli.command("list", short_help="List Serial ports") +@cli.command("list", short_help="List devices") @click.option("--json-output", is_flag=True) -def serialports_list(json_output): +def device_list(json_output): if json_output: click.echo(json.dumps(get_serialports())) @@ -47,7 +47,7 @@ def serialports_list(json_output): if int(PYSERIAL_VERSION[0]) == 3: - @cli.command("monitor", short_help="Monitor Serial port") + @cli.command("monitor", short_help="Monitor device (Serial)") @click.option("--port", "-p", help="Port, a number or a device name") @click.option( "--baud", @@ -112,7 +112,7 @@ if int(PYSERIAL_VERSION[0]) == 3: "--quiet", is_flag=True, help="Diagnostics: suppress non-error messages, default=Off") - def serialports_monitor(**kwargs): + def device_monitor(**kwargs): if not kwargs['port']: for item in get_serialports(): if "VID:PID" in item['hwid']: @@ -143,7 +143,7 @@ if int(PYSERIAL_VERSION[0]) == 3: raise MinitermException(e) else: - @cli.command("monitor", short_help="Monitor Serial port") + @cli.command("monitor", short_help="Monitor device (Serial)") @click.option("--port", "-p", help="Port, a number or a device name") @click.option( "--baud", @@ -210,7 +210,7 @@ else: "--quiet", is_flag=True, help="Diagnostics: suppress non-error messages, default=Off") - def serialports_monitor(**kwargs): + def device_monitor(**kwargs): sys.argv = app.get_session_var("command_ctx").args[1:] if not kwargs['port']: diff --git a/platformio/commands/init.py b/platformio/commands/init.py index 2f6482b2..943cd9cb 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -42,7 +42,8 @@ def validate_boards(ctx, param, value): # pylint: disable=W0613 ", ".join(unknown_boards)) -@click.command("init", short_help="Initialize new PlatformIO based project") +@click.command( + "init", short_help="Initialize PlatformIO project or update existing") @click.option( "--project-dir", "-d", diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 23ff4483..533ce50c 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -27,6 +27,7 @@ from platformio.downloader import FileDownloader from platformio.unpacker import FileUnpacker from platformio.vcsclient import VCSClientFactory + # pylint: disable=too-many-arguments diff --git a/tests/conftest.py b/tests/conftest.py index a6cf052d..f5277a3e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -15,8 +15,11 @@ import os import pytest +import requests from click.testing import CliRunner +requests.packages.urllib3.disable_warnings() + @pytest.fixture(scope="session") def platformio_setup(request): @@ -40,10 +43,12 @@ def clirunner(): @pytest.fixture(scope="session") def validate_cliresult(): + def decorator(result): assert result.exit_code == 0 assert not result.exception assert "error" not in result.output.lower() + return decorator From 054790d1610f2a10741c2b7dce69b69068e659d0 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 26 Aug 2016 14:39:23 +0300 Subject: [PATCH 212/284] Use stderr stream to write errors instead env.Exi() --- platformio/builder/tools/piolib.py | 2 +- platformio/builder/tools/piomisc.py | 7 ++++-- platformio/builder/tools/pioplatform.py | 4 +++- platformio/builder/tools/piotest.py | 14 +++++++---- platformio/builder/tools/pioupload.py | 32 +++++++++++++++---------- platformio/builder/tools/platformio.py | 20 +++++++++++----- 6 files changed, 51 insertions(+), 28 deletions(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 1e820327..be761225 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -203,7 +203,7 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes sys.stderr.write( "Error: Could not find `%s` dependency for `%s` " "library\n" % (item['name'], self.name)) - self.env.Exit(2) + self.env.Exit(1) def _validate_search_paths(self, search_paths=None): if not search_paths: diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 14e99810..a4f3a343 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -16,6 +16,7 @@ from __future__ import absolute_import import atexit import re +import sys from glob import glob from os import environ, remove from os.path import isfile, join @@ -250,8 +251,10 @@ def GetActualLDScript(env): return path if script: - env.Exit("Error: Could not find '%s' LD script in LDPATH '%s'" % - (script, env.subst("$LIBPATH"))) + sys.stderr.write( + "Error: Could not find '%s' LD script in LDPATH '%s'\n" % + (script, env.subst("$LIBPATH"))) + env.Exit(1) return None diff --git a/platformio/builder/tools/pioplatform.py b/platformio/builder/tools/pioplatform.py index 2cec0992..42ad2ef4 100644 --- a/platformio/builder/tools/pioplatform.py +++ b/platformio/builder/tools/pioplatform.py @@ -14,6 +14,7 @@ from __future__ import absolute_import +import sys from os.path import isdir, isfile, join from SCons.Script import COMMAND_LINE_TARGETS @@ -43,7 +44,8 @@ def BoardConfig(env, board=None): try: config = p.board_config(board if board else env['BOARD']) except exception.UnknownBoard as e: - env.Exit("Error: %s" % str(e)) + sys.stderr.write("Error: %s\n" % str(e)) + env.Exit(1) return config diff --git a/platformio/builder/tools/piotest.py b/platformio/builder/tools/piotest.py index 3b72f7ce..4ed542ae 100644 --- a/platformio/builder/tools/piotest.py +++ b/platformio/builder/tools/piotest.py @@ -15,6 +15,7 @@ from __future__ import absolute_import import atexit +import sys from os import remove from os.path import isdir, isfile, join, sep from string import Template @@ -82,9 +83,10 @@ def ProcessTest(env): def GenerateOutputReplacement(env, destination_dir): if not isdir(env.subst(destination_dir)): - env.Exit( - "Error: Test folder doesn't exist. Please put your test suite " - 'to \"test\" folder in project\'s root directory.') + sys.stderr.write( + "Error: Test folder does not exist. Please put your test suite " + "to \"test\" folder in project's root directory.\n") + env.Exit(1) TEMPLATECPP = """ # include <$framework> @@ -127,8 +129,10 @@ void output_complete(void) else: framework = env.subst("$PIOFRAMEWORK").lower() if framework not in FRAMEWORK_PARAMETERS: - env.Exit("Error: %s framework doesn't support testing feature!" % - framework) + sys.stderr.write( + "Error: %s framework doesn't support testing feature!\n" % + framework) + env.Exit(1) else: data = Template(TEMPLATECPP).substitute(FRAMEWORK_PARAMETERS[ framework]) diff --git a/platformio/builder/tools/pioupload.py b/platformio/builder/tools/pioupload.py index 728e8883..00f14697 100644 --- a/platformio/builder/tools/pioupload.py +++ b/platformio/builder/tools/pioupload.py @@ -14,6 +14,7 @@ from __future__ import absolute_import +import sys from os import environ from os.path import isfile, join from platform import system @@ -71,10 +72,11 @@ def WaitForNewSerialPort(env, before): break if not new_port: - env.Exit("Error: Couldn't find a board on the selected port. " - "Check that you have the correct port selected. " - "If it is correct, try pressing the board's reset " - "button after initiating the upload.") + sys.stderr.write("Error: Couldn't find a board on the selected port. " + "Check that you have the correct port selected. " + "If it is correct, try pressing the board's reset " + "button after initiating the upload.\n") + env.Exit(1) return new_port @@ -116,7 +118,7 @@ def AutodetectUploadPort(*args, **kwargs): # pylint: disable=unused-argument else: if (system() == "Linux" and not isfile("/etc/udev/99-platformio-udev.rules")): - print( + 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" @@ -126,10 +128,12 @@ def AutodetectUploadPort(*args, **kwargs): # pylint: disable=unused-argument if env.subst("$UPLOAD_PORT"): print env.subst("Auto-detected: $UPLOAD_PORT") else: - env.Exit("Error: Please specify `upload_port` for environment or use " - "global `--upload-port` option.\n" - "For some development platforms this can be a USB flash " - "drive (i.e. /media//)\n") + sys.stderr.write( + "Error: Please specify `upload_port` for environment or use " + "global `--upload-port` option.\n" + "For some development platforms this can be a USB flash " + "drive (i.e. /media//)\n") + env.Exit(1) def UploadToDisk(_, target, source, env): # pylint: disable=W0613,W0621 @@ -141,8 +145,8 @@ 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 @@ -166,8 +170,10 @@ def CheckUploadSize(_, target, source, env): # pylint: disable=W0613,W0621 used_size = int(values[0]) + int(values[1]) if used_size > max_size: - env.Exit("Error: The program size (%d bytes) is greater " - "than maximum allowed (%s bytes)" % (used_size, max_size)) + sys.stderr.write("Error: The program size (%d bytes) is greater " + "than maximum allowed (%s bytes)\n" % + (used_size, max_size)) + env.Exit(1) def exists(_): diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 0db54cfd..e8a3c8d2 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -15,6 +15,7 @@ from __future__ import absolute_import import re +import sys from glob import glob from os import sep, walk from os.path import basename, dirname, isdir, join, realpath @@ -87,8 +88,10 @@ def BuildProgram(env): env.Append(PIOBUILDFILES=env.ProcessTest()) if not env['PIOBUILDFILES'] and not COMMAND_LINE_TARGETS: - env.Exit("Error: Nothing to build. Please put your source code files " - "to '%s' folder" % env.subst("$PROJECTSRC_DIR")) + 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']) @@ -230,15 +233,18 @@ def BuildFrameworks(env, frameworks): return if "BOARD" not in env: - env.Exit("Please specify `board` in `platformio.ini` to use " - "with '%s' framework" % ", ".join(frameworks)) + sys.stderr.write("Please specify `board` in `platformio.ini` to use " + "with '%s' framework\n" % ", ".join(frameworks)) + env.Exit(1) board_frameworks = env.BoardConfig().get("frameworks", []) if frameworks == ["platformio"]: if board_frameworks: frameworks.insert(0, board_frameworks[0]) else: - env.Exit("Error: Please specify `board` in `platformio.ini`") + sys.stderr.write( + "Error: Please specify `board` in `platformio.ini`\n") + env.Exit(1) for f in frameworks: if f in ("arduino", "energia"): @@ -247,7 +253,9 @@ def BuildFrameworks(env, frameworks): if f in board_frameworks: SConscript(env.GetFrameworkScript(f)) else: - env.Exit("Error: This board doesn't support %s framework!" % f) + sys.stderr.write( + "Error: This board doesn't support %s framework!\n" % f) + env.Exit(1) def BuildLibrary(env, variant_dir, src_dir, src_filter=None): From 8d8bfd5587dd89fb8911841a1a35d7b7363955a6 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 26 Aug 2016 14:44:45 +0300 Subject: [PATCH 213/284] Document `version` option for `dependencies` field in library.json --- docs/librarymanager/config.rst | 15 +++++++++++++++ platformio/__main__.py | 8 ++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index c7680c03..0d74243d 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -401,6 +401,21 @@ Allowed requirements for dependent library: * ``frameworks`` | Type: ``String`` or ``Array`` * ``platforms`` | Type: ``String`` or ``Array`` +The ``version`` supports `Semantic Versioning `_ ( +``..``) and can take any of the following forms: + +* ``0.1.2`` - an exact version number. Use only this exact version +* ``^0.1.2`` - any compatible version (exact version for ``0.x.x`` versions +* ``~0.1.2`` - any version with the same major and minor versions, and an + equal or greater patch version +* ``>0.1.2`` - any version greater than ``0.1.2``. ``>=``, ``<``, and ``<=`` + are also possible +* ``>0.1.0,!=0.2.0,<0.3.0`` - any version greater than ``0.1.0``, not equal to + ``0.2.0`` and less than ``0.3.0`` + +The rest possible values including VCS repository URLs are documented in +:ref:`cmd_lib_install` command. + Example: .. code-block:: javascript diff --git a/platformio/__main__.py b/platformio/__main__.py index 5ee08cb9..ae9fb061 100644 --- a/platformio/__main__.py +++ b/platformio/__main__.py @@ -52,11 +52,11 @@ class PlatformioCLI(click.MultiCommand): # pylint: disable=R0904 @staticmethod def _handle_obsolate_command(name): if name == "platforms": - from platformio.commands.platform import cli - return cli + from platformio.commands import platform + return platform.cli elif name == "serialports": - from platformio.commands.device import cli - return cli + from platformio.commands import device + return device.cli raise AttributeError() From 3e403ef9ee3165016fb34af91fe0ba0ae503fa65 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 26 Aug 2016 14:57:21 +0300 Subject: [PATCH 214/284] Add example with Library Manager --- examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples b/examples index a32b1662..67f0e894 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit a32b166297015fd9cb942c4711801e03e3ee9b94 +Subproject commit 67f0e8946a680b17e2a49a8994713fe099306ae8 From 37dff70cd6366893a206c40881d28c0d67087fac Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 26 Aug 2016 16:09:52 +0300 Subject: [PATCH 215/284] Replace TYPE for board/platform with ID // Resolve #459 --- docs/ci/appveyor.rst | 2 +- docs/ci/circleci.rst | 12 ++++++------ docs/ci/drone.rst | 2 +- docs/ci/shippable.rst | 2 +- docs/ci/travis.rst | 6 +++--- docs/ide/clion.rst | 4 ++-- docs/ide/codeblocks.rst | 4 ++-- docs/ide/eclipse.rst | 4 ++-- docs/ide/emacs.rst | 4 ++-- docs/ide/netbeans.rst | 4 ++-- docs/ide/qtcreator.rst | 4 ++-- docs/ide/sublimetext.rst | 4 ++-- docs/ide/visualstudio.rst | 4 ++-- docs/userguide/cmd_init.rst | 2 +- examples | 2 +- platformio/commands/platform.py | 5 ++--- platformio/managers/platform.py | 7 +------ 17 files changed, 33 insertions(+), 39 deletions(-) diff --git a/docs/ci/appveyor.rst b/docs/ci/appveyor.rst index af246a86..2341c0e3 100644 --- a/docs/ci/appveyor.rst +++ b/docs/ci/appveyor.rst @@ -56,7 +56,7 @@ Put ``appveyor.yml`` to the root directory of the GitHub repository. - cmd: pip install -U platformio test_script: - - cmd: platformio ci --board=TYPE_1 --board=TYPE_2 --board=TYPE_N + - cmd: platformio ci --board=ID_1 --board=ID_2 --board=ID_N For more details as for PlatformIO build process please look into :ref:`cmd_ci` diff --git a/docs/ci/circleci.rst b/docs/ci/circleci.rst index c159a4ef..d3e09fa9 100644 --- a/docs/ci/circleci.rst +++ b/docs/ci/circleci.rst @@ -49,9 +49,9 @@ guide first. test: override: - - platformio ci path/to/test/file.c --board=TYPE_1 --board=TYPE_2 --board=TYPE_N - - platformio ci examples/file.ino --board=TYPE_1 --board=TYPE_2 --board=TYPE_N - - platformio ci path/to/test/directory --board=TYPE_1 --board=TYPE_2 --board=TYPE_N + - platformio ci path/to/test/file.c --board=ID_1 --board=ID_2 --board=ID_N + - platformio ci examples/file.ino --board=ID_1 --board=ID_2 --board=ID_N + - platformio ci path/to/test/directory --board=ID_1 --board=ID_2 --board=ID_N For more details as for PlatformIO build process please look into :ref:`cmd_ci`. @@ -65,7 +65,7 @@ it), please use ``--lib="."`` option for :ref:`cmd_ci` command .. code-block:: yaml script: - - platformio ci --lib="." --board=TYPE_1 --board=TYPE_2 --board=TYPE_N + - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N Library dependecies ~~~~~~~~~~~~~~~~~~~ @@ -87,7 +87,7 @@ Install dependent library using :ref:`librarymanager` test: override: - - platformio ci path/to/test/file.c --board=TYPE_1 --board=TYPE_2 --board=TYPE_N + - platformio ci path/to/test/file.c --board=ID_1 --board=ID_2 --board=ID_N Manually download dependent library and include in build process via ``--lib`` option ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ Manually download dependent library and include in build process via ``--lib`` o test: override: - - platformio ci path/to/test/file.c --lib="/tmp/OneWire-master" --board=TYPE_1 --board=TYPE_2 --board=TYPE_N + - platformio ci path/to/test/file.c --lib="/tmp/OneWire-master" --board=ID_1 --board=ID_2 --board=ID_N Custom Build Flags ~~~~~~~~~~~~~~~~~~ diff --git a/docs/ci/drone.rst b/docs/ci/drone.rst index 8156a449..ec9d1118 100644 --- a/docs/ci/drone.rst +++ b/docs/ci/drone.rst @@ -51,7 +51,7 @@ Please fill all fields for your project in the Drone control panel: .. code-block:: bash pip install -U platformio - platformio ci --board=TYPE_1 --board=TYPE_2 --board=TYPE_N + platformio ci --board=ID_1 --board=ID_2 --board=ID_N .. image:: ../_static/droneci-platformio-integration-1.png diff --git a/docs/ci/shippable.rst b/docs/ci/shippable.rst index aafc2d07..4a71e7a7 100644 --- a/docs/ci/shippable.rst +++ b/docs/ci/shippable.rst @@ -58,7 +58,7 @@ GitHub repository. - pip install -U platformio script: - - platformio ci --board=TYPE_1 --board=TYPE_2 --board=TYPE_N + - platformio ci --board=ID_1 --board=ID_2 --board=ID_N For more details as for PlatformIO build process please look into :ref:`cmd_ci` diff --git a/docs/ci/travis.rst b/docs/ci/travis.rst index 53ff0f06..df48556a 100644 --- a/docs/ci/travis.rst +++ b/docs/ci/travis.rst @@ -72,7 +72,7 @@ PlatformIO is written in Python and is recommended to be run within - pip install -U platformio script: - - platformio ci --board=TYPE_1 --board=TYPE_2 --board=TYPE_N + - platformio ci --board=ID_1 --board=ID_2 --board=ID_N Then perform steps 1, 2 and 4 from http://docs.travis-ci.com/user/getting-started/ @@ -87,7 +87,7 @@ it), please use ``--lib="."`` option for :ref:`cmd_ci` command .. code-block:: yaml script: - - platformio ci --lib="." --board=TYPE_1 --board=TYPE_2 --board=TYPE_N + - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N Library dependecies ~~~~~~~~~~~~~~~~~~~ @@ -121,7 +121,7 @@ Manually download dependent library and include in build process via ``--lib`` o - unzip /tmp/onewire_source.zip -d /tmp/ script: - - platformio ci --lib="/tmp/OneWire-master" --board=TYPE_1 --board=TYPE_2 --board=TYPE_N + - platformio ci --lib="/tmp/OneWire-master" --board=ID_1 --board=ID_2 --board=ID_N Custom Build Flags ~~~~~~~~~~~~~~~~~~ diff --git a/docs/ide/clion.rst b/docs/ide/clion.rst index 01600f2e..2d04fbbd 100644 --- a/docs/ide/clion.rst +++ b/docs/ide/clion.rst @@ -31,12 +31,12 @@ page for more detailed information. Integration ----------- -Choose board ``type`` using :ref:`cmd_boards` or `Embedded Boards Explorer `_ +Choose board ``ID`` using :ref:`cmd_boards` or `Embedded Boards Explorer `_ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide clion --board %TYPE% + platformio init --ide clion --board %ID% # For example, generate project for Arduino UNO platformio init --ide clion --board uno diff --git a/docs/ide/codeblocks.rst b/docs/ide/codeblocks.rst index dd1857dd..7ac5b3c6 100644 --- a/docs/ide/codeblocks.rst +++ b/docs/ide/codeblocks.rst @@ -30,12 +30,12 @@ CodeBlocks IDE can be downloaded from `here `_ +Choose board ``ID`` using :ref:`cmd_boards` or `Embedded Boards Explorer `_ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide codeblocks --board %TYPE% + platformio init --ide codeblocks --board %ID% # For example, generate project for Arduino UNO platformio init --ide codeblocks --board uno diff --git a/docs/ide/eclipse.rst b/docs/ide/eclipse.rst index 558117c8..418cdec7 100644 --- a/docs/ide/eclipse.rst +++ b/docs/ide/eclipse.rst @@ -35,12 +35,12 @@ page for more detailed information. Integration ----------- -Choose board ``type`` using :ref:`cmd_boards` or `Embedded Boards Explorer `_ +Choose board ``ID`` using :ref:`cmd_boards` or `Embedded Boards Explorer `_ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide eclipse --board %TYPE% + platformio init --ide eclipse --board %ID% # For example, generate project for Arduino UNO platformio init --ide eclipse --board uno diff --git a/docs/ide/emacs.rst b/docs/ide/emacs.rst index 769a64ce..768c6333 100644 --- a/docs/ide/emacs.rst +++ b/docs/ide/emacs.rst @@ -45,12 +45,12 @@ Code completion can optionally be provided by installing `irony-mode `_ +Choose board ``ID`` using :ref:`cmd_boards` or `Embedded Boards Explorer `_ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide emacs --board %TYPE% + platformio init --ide emacs --board %ID% There are 6 predefined targets for building. diff --git a/docs/ide/netbeans.rst b/docs/ide/netbeans.rst index d4a95e98..dfe96f35 100644 --- a/docs/ide/netbeans.rst +++ b/docs/ide/netbeans.rst @@ -33,12 +33,12 @@ install the C/C++ development plugins). Integration ----------- -Choose board ``type`` using :ref:`cmd_boards` or `Embedded Boards Explorer `_ +Choose board ``ID`` using :ref:`cmd_boards` or `Embedded Boards Explorer `_ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide netbeans --board %TYPE% + platformio init --ide netbeans --board %ID% # For example, generate project for Arduino UNO platformio init --ide netbeans --board uno diff --git a/docs/ide/qtcreator.rst b/docs/ide/qtcreator.rst index a40f910a..2cacc2c8 100644 --- a/docs/ide/qtcreator.rst +++ b/docs/ide/qtcreator.rst @@ -35,12 +35,12 @@ Integration Project Generator ^^^^^^^^^^^^^^^^^ -Choose board ``type`` using :ref:`cmd_boards` or `Embedded Boards Explorer `_ +Choose board ``ID`` using :ref:`cmd_boards` or `Embedded Boards Explorer `_ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide qtcreator --board %TYPE% + platformio init --ide qtcreator --board %ID% # For example, generate project for Arduino UNO platformio init --ide qtcreator --board uno diff --git a/docs/ide/sublimetext.rst b/docs/ide/sublimetext.rst index 3342f5d4..150c7a96 100644 --- a/docs/ide/sublimetext.rst +++ b/docs/ide/sublimetext.rst @@ -42,12 +42,12 @@ steps and documentation. Project Generator ^^^^^^^^^^^^^^^^^ -Choose board ``type`` using :ref:`cmd_boards` or `Embedded Boards Explorer `_ +Choose board ``ID`` using :ref:`cmd_boards` or `Embedded Boards Explorer `_ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide sublimetext --board %TYPE% + platformio init --ide sublimetext --board %ID% # For example, generate project for Arduino UNO platformio init --ide sublimetext --board uno diff --git a/docs/ide/visualstudio.rst b/docs/ide/visualstudio.rst index ae58d2f5..ddcd2d54 100644 --- a/docs/ide/visualstudio.rst +++ b/docs/ide/visualstudio.rst @@ -35,12 +35,12 @@ Integration Project Generator ^^^^^^^^^^^^^^^^^ -Choose board ``type`` using :ref:`cmd_boards` or `Embedded Boards Explorer `_ +Choose board ``ID`` using :ref:`cmd_boards` or `Embedded Boards Explorer `_ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide sublimetext --board %TYPE% + platformio init --ide sublimetext --board %ID% # For example, generate project for Arduino UNO platformio init --ide visualstudio --board uno diff --git a/docs/userguide/cmd_init.rst b/docs/userguide/cmd_init.rst index 6605d9a0..eb001fdd 100644 --- a/docs/userguide/cmd_init.rst +++ b/docs/userguide/cmd_init.rst @@ -52,7 +52,7 @@ A path to the directory where *PlatformIO* will initialize new project. .. option:: -b, --board -If you specify board ``type`` (you can pass multiple ``--board`` options), then +If you specify board ``ID`` (you can pass multiple ``--board`` options), then *PlatformIO* will automatically generate environment for :ref:`projectconf` and pre-fill these data: diff --git a/examples b/examples index 67f0e894..8c4de49a 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 67f0e8946a680b17e2a49a8994713fe099306ae8 +Subproject commit 8c4de49a532ad1903a845b4b34d8fd4b244cb063 diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index c69c8ceb..7934ebe9 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -56,10 +56,9 @@ def platform_search(query, json_output): if query and query.lower() not in search_data.lower(): continue - # @TODO update API with NAME/TITLE platforms.append({ - "name": platform['type'], - "title": platform['name'], + "name": platform['name'], + "title": platform['title'], "description": platform['description'], "packages": platform['packages'] }) diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index fcfe3038..c4642365 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -117,12 +117,7 @@ class PlatformManager(BasePkgManager): @staticmethod @util.memoized def get_registered_boards(): - boards = util.get_api_result("/boards") - for item in boards: - # @TODO remove type from API - item['id'] = item['type'] - del item['type'] - return boards + return util.get_api_result("/boards") class PlatformFactory(object): From 8e09d637e7bfa59c35fe6bf4234bd65fa9a4ddb0 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 26 Aug 2016 18:52:44 +0300 Subject: [PATCH 216/284] Improve compatibility with Arduino 1.0 library format --- platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index f002cab1..740e93b3 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0a11") +VERSION = (3, 0, "0a12") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index be761225..e88ea9aa 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -346,21 +346,22 @@ class ArduinoLibBuilder(LibBuilderBase): def get_inc_dirs(self, use_build_dir=False): inc_dirs = LibBuilderBase.get_inc_dirs(self, use_build_dir) - if not isdir(join(self.src_dir, "utility")): + if not isdir(join(self.path, "utility")): return inc_dirs inc_dirs.append( - join(self.build_dir if use_build_dir else self.src_dir, "utility")) + join(self.build_dir if use_build_dir else self.path, "utility")) return inc_dirs @property def src_filter(self): if isdir(join(self.path, "src")): return LibBuilderBase.src_filter.fget(self) - src_filter = [ - "+<*.%s>" % ext - for ext in piotool.SRC_BUILD_EXT + piotool.SRC_HEADER_EXT - ] - src_filter.append("+" % sep) + src_filter = [] + is_utility = isdir(join(self.path, "utility")) + for ext in piotool.SRC_BUILD_EXT + piotool.SRC_HEADER_EXT: + src_filter.append("+<*.%s>" % ext) + if is_utility: + src_filter.append("+" % (sep, ext)) return src_filter def is_framework_compatible(self, framework): From 84abc5764ddab831c80040abbc0d0c0171e6d216 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 26 Aug 2016 19:11:35 +0300 Subject: [PATCH 217/284] Improve docs for library.json `build` field --- docs/librarymanager/config.rst | 72 +++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index 0d74243d..3f96814a 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -284,8 +284,8 @@ reduce size of the final archive. Possible options: -* ``include`` -* ``exclude`` +.. contents:: + :local: ``include`` ~~~~~~~~~~~ @@ -483,39 +483,55 @@ A list of example patterns. This field is predefined with default value: .. _libjson_build: ``build`` ------------- +--------- *Optional* | Type: ``Object`` Specify advanced settings, options and flags for the build system. Possible options: -.. list-table:: - :header-rows: 1 +.. contents:: + :local: - * - Option - - Type - - Description - * - ``flags`` - - ``String`` or ``Array`` - - Extra flags to control preprocessing, compilation, assembly and - linking processes. More details :ref:`projectconf_build_flags` - * - ``unflags`` - - ``String`` or ``Array`` - - Remove base/initial flags which were set by development - platform. More details :ref:`projectconf_build_unflags` - * - ``srcFilter`` - - ``String`` or ``Array`` - - Specify which source files should be included/excluded - from build process. More details :ref:`projectconf_src_filter` - * - ``extraScript`` - - ``String`` - - Launch extra script before build process. - More details :ref:`projectconf_extra_script` - * - ``libArchive`` - - ``Boolean`` - - Archive object files to Static Library. This is default behavior of - PlatformIO Build System (``"libArchive": true``). +``flags`` +~~~~~~~~~ + +*Optional* | Type: ``String`` or ``Array`` + +Extra flags to control preprocessing, compilation, assembly and linking +processes. More details :ref:`projectconf_build_flags`. + +``unflags`` +~~~~~~~~~~~ + +*Optional* | Type: ``String`` or ``Array`` + +Remove base/initial flags which were set by development platform. More +details :ref:`projectconf_build_unflags`. + +``srcFilter`` +~~~~~~~~~~~~~ + +*Optional* | Type: ``String`` or ``Array`` + +Specify which source files should be included/excluded from build process. +More details :ref:`projectconf_src_filter`. + +``extraScript`` +~~~~~~~~~~~~~~~ + +*Optional* | Type: ``String`` + +Launch extra script before build process. +More details :ref:`projectconf_extra_script`. + +``libArchive`` +~~~~~~~~~~~~~~ + +*Optional* | Type: ``Boolean`` + +Archive object files to Static Library. This is default behavior of PlatformIO +Build System (``"libArchive": true``). **Examples** From 99dfc23d96aad6f0c0e26b7f7449906288add140 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 26 Aug 2016 20:22:32 +0300 Subject: [PATCH 218/284] Update supported manifests for Library Registry --- docs/userguide/lib/cmd_register.rst | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/userguide/lib/cmd_register.rst b/docs/userguide/lib/cmd_register.rst index 08911f64..d34b857c 100644 --- a/docs/userguide/lib/cmd_register.rst +++ b/docs/userguide/lib/cmd_register.rst @@ -21,17 +21,25 @@ Usage .. code-block:: bash - platformio lib register [HTTP_URL_TO_LIBRARY.JSON] + platformio lib register [MANIFEST_URL] Description ----------- -Register new library and allow others to install it. +Register new library in `PlatformIO Library Registry `_. + +PlatformIO Library Registry supports the next library manifests: + +* PlatformIO :ref:`library_config` +* Arduino `library.properties `_ +* ARM mbed yotta `module.json `_. Examples -------- .. code:: - platformio lib register http://my.example.com/raw-library.json + platformio lib register https://raw.githubusercontent.com/bblanchon/ArduinoJson/master/library.json + platformio lib register https://raw.githubusercontent.com/adafruit/DHT-sensor-library/master/library.properties + platformio lib register https://raw.githubusercontent.com/ARMmbed/ble/master/module.json From 4ba36259875ef98fe9359a646b405afd3f041916 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 27 Aug 2016 12:14:43 +0300 Subject: [PATCH 219/284] Update comment header for platformio.ini --- examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples b/examples index 8c4de49a..e614de50 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 8c4de49a532ad1903a845b4b34d8fd4b244cb063 +Subproject commit e614de50bfefe7c0aea1731bebd8afa9e91293e2 From e2328103254ce270f3666f143f6ca97378f981ef Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 27 Aug 2016 19:30:38 +0300 Subject: [PATCH 220/284] Improve output in non verbose mode --- platformio/__init__.py | 2 +- platformio/builder/main.py | 18 +++++++++++------- platformio/builder/tools/piolib.py | 6 ++++-- platformio/builder/tools/piomisc.py | 17 +++++++++-------- platformio/builder/tools/pioupload.py | 8 +++----- platformio/builder/tools/platformio.py | 4 +++- platformio/managers/package.py | 1 - platformio/managers/platform.py | 3 +-- 8 files changed, 32 insertions(+), 27 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 740e93b3..7ee7955e 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0a12") +VERSION = (3, 0, "0a13") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 67df1f5c..356b862a 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -19,8 +19,8 @@ from os import environ from os.path import join, normpath from time import time -from SCons.Script import (COMMAND_LINE_TARGETS, AllowSubstExceptions, - DefaultEnvironment, Progress, Variables) +from SCons.Script import (ARGUMENTS, COMMAND_LINE_TARGETS, + AllowSubstExceptions, DefaultEnvironment, Variables) from platformio import util @@ -65,7 +65,7 @@ commonvars.AddVariables( ("UPLOAD_RESETMETHOD",) ) # yapf: disable -DefaultEnvironment( +DEFAULT_ENV_OPTIONS = dict( tools=[ "ar", "as", "gcc", "g++", "gnulink", "platformio", "pioplatform", "piowinhooks", @@ -93,11 +93,15 @@ DefaultEnvironment( ], PYTHONEXE=normpath(sys.executable)) -env = DefaultEnvironment() - -if env.GetOption("silent"): +if not int(ARGUMENTS.get("PIOVERBOSE", 0)): print "Verbose mode can be enabled via `-v, --verbose` option" - Progress(env.ProgressHandler) + DEFAULT_ENV_OPTIONS['ARCOMSTR'] = "Archiving $TARGET" + DEFAULT_ENV_OPTIONS['LINKCOMSTR'] = "Linking $TARGET" + DEFAULT_ENV_OPTIONS['RANLIBCOMSTR'] = "Indexing $TARGET" + for k in ("ASPPCOMSTR", "CCCOMSTR", "CXXCOMSTR"): + DEFAULT_ENV_OPTIONS[k] = "Compiling $TARGET" + +env = DefaultEnvironment(**DEFAULT_ENV_OPTIONS) # decode common variables for k in commonvars.keys(): diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index e88ea9aa..04b2d40c 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -22,6 +22,7 @@ from os.path import basename, commonprefix, isdir, isfile, join, realpath, sep from platform import system import SCons.Scanner +from SCons.Script import ARGUMENTS from platformio import util from platformio.builder.tools import platformio as piotool @@ -465,7 +466,8 @@ def GetLibBuilders(env): f.lower().strip() for f in env.get("PIOFRAMEWORK", "").split(",") ] compat_mode = int(env.get("LIB_COMPAT_MODE", 1)) - verbose = not (env.GetOption("silent") or env.GetOption('clean')) + verbose = (int(ARGUMENTS.get("PIOVERBOSE", 0)) and + not env.GetOption('clean')) def _check_lib_builder(lb): if lb.name in env.get("LIB_IGNORE", []): @@ -528,7 +530,7 @@ def BuildDependentLibraries(env, src_dir): title = "<%s>" % lb.name if lb.version: title += " v%s" % lb.version - if not env.GetOption("silent"): + if int(ARGUMENTS.get("PIOVERBOSE", 0)): title += " (%s)" % lb.path print "%s|-- %s" % (margin, title) if lb.depbuilders: diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index a4f3a343..efc21679 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -21,6 +21,9 @@ from glob import glob from os import environ, remove from os.path import isfile, join +from SCons.Action import Action +from SCons.Script import ARGUMENTS + from platformio import util @@ -259,13 +262,11 @@ def GetActualLDScript(env): return None -def ProgressHandler(env, node): - item = str(node) - if "toolchain-" in item or "tool-" in item or \ - item.endswith((".o", ".h", ".hpp", ".ipp")): - return - item = item.replace(env['PIOHOME_DIR'], ".platformio") - print "Processing %s" % item +def VerboseAction(env, act, actstr): + if int(ARGUMENTS.get("PIOVERBOSE", 0)): + return act + else: + return Action(act, actstr) def exists(_): @@ -277,5 +278,5 @@ def generate(env): env.AddMethod(DumpIDEData) env.AddMethod(GetCompilerType) env.AddMethod(GetActualLDScript) - env.AddMethod(ProgressHandler) + env.AddMethod(VerboseAction) return env diff --git a/platformio/builder/tools/pioupload.py b/platformio/builder/tools/pioupload.py index 00f14697..9d2b1a6e 100644 --- a/platformio/builder/tools/pioupload.py +++ b/platformio/builder/tools/pioupload.py @@ -83,7 +83,6 @@ def WaitForNewSerialPort(env, before): def AutodetectUploadPort(*args, **kwargs): # pylint: disable=unused-argument env = args[0] - print "Looking for upload port/disk..." def _look_for_mbed_disk(): msdlabels = ("mbed", "nucleo", "frdm", "microbit") @@ -110,7 +109,7 @@ def AutodetectUploadPort(*args, **kwargs): # pylint: disable=unused-argument return port if "UPLOAD_PORT" in env: - print env.subst("Manually specified: $UPLOAD_PORT") + print env.subst("Use manually specified: $UPLOAD_PORT") return if env.subst("$PIOFRAMEWORK") == "mbed": @@ -131,13 +130,13 @@ def AutodetectUploadPort(*args, **kwargs): # pylint: disable=unused-argument sys.stderr.write( "Error: Please specify `upload_port` for environment or use " "global `--upload-port` option.\n" - "For some development platforms this can be a USB flash " + "For some development platforms it can be a USB flash " "drive (i.e. /media//)\n") env.Exit(1) def UploadToDisk(_, target, source, env): # pylint: disable=W0613,W0621 - env.AutodetectUploadPort() + assert "UPLOAD_PORT" in env progname = env.subst("$PROGNAME") for ext in ("bin", "hex"): fpath = join(env.subst("$BUILD_DIR"), "%s.%s" % (progname, ext)) @@ -156,7 +155,6 @@ def CheckUploadSize(_, target, source, env): # pylint: disable=W0613,W0621 if max_size == 0 or "SIZETOOL" not in env: return - print "Check program size..." sysenv = environ.copy() sysenv['PATH'] = str(env['ENV']['PATH']) cmd = [env.subst("$SIZETOOL"), "-B", str(target[0])] diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index e8a3c8d2..9634ef1e 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -20,6 +20,7 @@ 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, DefaultEnvironment, SConscript from SCons.Util import case_sensitive_suffixes @@ -97,7 +98,8 @@ def BuildProgram(env): join("$BUILD_DIR", env.subst("$PROGNAME")), env['PIOBUILDFILES']) if set(["upload", "uploadlazy", "program"]) & set(COMMAND_LINE_TARGETS): - env.AddPostAction(program, env.CheckUploadSize) + env.AddPostAction(program, Action(env.CheckUploadSize, + "Checking program size $TARGET")) return program diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 533ce50c..23ff4483 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -27,7 +27,6 @@ from platformio.downloader import FileDownloader from platformio.unpacker import FileUnpacker from platformio.vcsclient import VCSClientFactory - # pylint: disable=too-many-arguments diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index c4642365..4372bb0c 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -276,8 +276,7 @@ class PlatformRunMixin(object): "-j %d" % self.get_job_nums(), "--warn=no-no-parallel-support", "-f", join(util.get_source_dir(), "builder", "main.py") ] - if not self.verbose and "-c" not in targets: - cmd.append("--silent") + cmd.append("PIOVERBOSE=%d" % (1 if self.verbose else 0)) cmd += targets # encode and append variables From 7b474c69ab6fb36b68fbe3abbaf3b1a99fb7fbbd Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 27 Aug 2016 19:30:53 +0300 Subject: [PATCH 221/284] PyLint fix --- platformio/builder/tools/piomisc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index efc21679..78ca1e26 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -262,7 +262,7 @@ def GetActualLDScript(env): return None -def VerboseAction(env, act, actstr): +def VerboseAction(_, act, actstr): if int(ARGUMENTS.get("PIOVERBOSE", 0)): return act else: From 6894d2c5d2d10efc3efaf1a8baf1a3f8c0189c83 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 27 Aug 2016 20:32:21 +0300 Subject: [PATCH 222/284] Allow to pass project file path to run command instead project dir --- platformio/commands/run.py | 9 ++++++++- platformio/util.py | 10 ++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 825d09ac..0f8c7402 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -38,7 +38,7 @@ from platformio.managers.platform import PlatformFactory default=getcwd, type=click.Path( exists=True, - file_okay=False, + file_okay=True, dir_okay=True, writable=True, resolve_path=True)) @@ -54,6 +54,13 @@ def cli(ctx, # pylint: disable=R0913,R0914 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: diff --git a/platformio/util.py b/platformio/util.py index dcbf298a..4dbf530e 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -194,6 +194,16 @@ def get_project_dir(): return os.getcwd() +def find_project_dir_above(path): + if isfile(path): + path = dirname(path) + if is_platformio_project(path): + return path + if isdir(dirname(path)): + return find_project_dir_above(dirname(path)) + return None + + def is_platformio_project(project_dir=None): if not project_dir: project_dir = get_project_dir() From d28f0b259a5a51315e0d6ff326f64693abf4a296 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 27 Aug 2016 23:15:32 +0300 Subject: [PATCH 223/284] Generate better UID --- platformio/__main__.py | 2 -- platformio/app.py | 16 ++++++++++++++++ platformio/telemetry.py | 12 +----------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/platformio/__main__.py b/platformio/__main__.py index ae9fb061..05486bf0 100644 --- a/platformio/__main__.py +++ b/platformio/__main__.py @@ -72,8 +72,6 @@ class PlatformioCLI(click.MultiCommand): # pylint: disable=R0904 @click.option("--caller", "-c", help="Caller ID (service).") @click.pass_context def cli(ctx, force, caller): - if not caller and getenv("PLATFORMIO_CALLER"): - caller = getenv("PLATFORMIO_CALLER") maintenance.on_platformio_start(ctx, force, caller) diff --git a/platformio/app.py b/platformio/app.py index 42c8ee8d..cfd6b164 100644 --- a/platformio/app.py +++ b/platformio/app.py @@ -13,6 +13,7 @@ # limitations under the License. import json +import uuid from copy import deepcopy from os import environ, getenv from os.path import getmtime, isfile, join @@ -164,6 +165,11 @@ def reset_settings(): def get_session_var(name, default=None): + if name == "caller_id" and not SESSION_VARS[name]: + if getenv("PLATFORMIO_CALLER"): + return getenv("PLATFORMIO_CALLER") + elif getenv("C9_UID"): + return "C9" return SESSION_VARS.get(name, default) @@ -175,3 +181,13 @@ def set_session_var(name, value): def is_disabled_progressbar(): return any([get_session_var("force_option"), util.is_ci(), getenv("PLATFORMIO_DISABLE_PROGRESSBAR") == "true"]) + + +def get_cid(): + cid = get_state_item("cid") + if not cid: + cid = str( + uuid.uuid5(uuid.NAMESPACE_OID, str( + getenv("C9_UID") if getenv("C9_UID") else uuid.getnode()))) + set_state_item("cid", cid) + return cid diff --git a/platformio/telemetry.py b/platformio/telemetry.py index 08a8302d..68a1e517 100644 --- a/platformio/telemetry.py +++ b/platformio/telemetry.py @@ -17,7 +17,6 @@ import platform import Queue import sys import threading -import uuid from collections import deque from os import getenv from time import sleep, time @@ -31,8 +30,6 @@ from platformio import __version__, app, exception, util class TelemetryBase(object): - MACHINE_ID = str(uuid.uuid5(uuid.NAMESPACE_OID, str(uuid.getnode()))) - def __init__(self): self._params = {} @@ -46,13 +43,6 @@ class TelemetryBase(object): if name in self._params: del self._params[name] - def get_cid(self): - cid = app.get_state_item("cid") - if not cid: - cid = self.MACHINE_ID - app.set_state_item("cid", cid) - return cid - def send(self, hittype): raise NotImplementedError() @@ -72,7 +62,7 @@ class MeasurementProtocol(TelemetryBase): TelemetryBase.__init__(self) self['v'] = 1 self['tid'] = self.TID - self['cid'] = self.get_cid() + self['cid'] = app.get_cid() self['sr'] = "%dx%d" % click.get_terminal_size() self._prefill_screen_name() From 6765a60ec3ff60481cf2ff2506e94e84fe836db2 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 28 Aug 2016 00:03:54 +0300 Subject: [PATCH 224/284] Minor improvements --- platformio/app.py | 11 ++++------- platformio/commands/run.py | 10 +++------- platformio/maintenance.py | 6 ++++++ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/platformio/app.py b/platformio/app.py index cfd6b164..54ddf9be 100644 --- a/platformio/app.py +++ b/platformio/app.py @@ -14,6 +14,7 @@ import json import uuid +import hashlib from copy import deepcopy from os import environ, getenv from os.path import getmtime, isfile, join @@ -165,11 +166,6 @@ def reset_settings(): def get_session_var(name, default=None): - if name == "caller_id" and not SESSION_VARS[name]: - if getenv("PLATFORMIO_CALLER"): - return getenv("PLATFORMIO_CALLER") - elif getenv("C9_UID"): - return "C9" return SESSION_VARS.get(name, default) @@ -187,7 +183,8 @@ def get_cid(): cid = get_state_item("cid") if not cid: cid = str( - uuid.uuid5(uuid.NAMESPACE_OID, str( - getenv("C9_UID") if getenv("C9_UID") else uuid.getnode()))) + uuid.UUID(bytes=hashlib.md5( + str(getenv("C9_UID") + if getenv("C9_UID") else uuid.getnode())).digest())) set_state_item("cid", cid) return cid diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 0f8c7402..ffa837f7 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -27,6 +27,8 @@ from platformio.commands.platform import \ 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) @@ -46,13 +48,7 @@ from platformio.managers.platform import PlatformFactory @click.option("-v", "--verbose", is_flag=True) @click.option("--disable-auto-clean", is_flag=True) @click.pass_context -def cli(ctx, # pylint: disable=R0913,R0914 - environment, - target, - upload_port, - project_dir, - silent, - verbose, +def cli(ctx, environment, target, upload_port, project_dir, silent, verbose, disable_auto_clean): # find project directory on upper level if isfile(project_dir): diff --git a/platformio/maintenance.py b/platformio/maintenance.py index 0d6ac489..ee3ba4fc 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -38,6 +38,12 @@ def in_silence(ctx): def on_platformio_start(ctx, force, caller): + if not caller: + if getenv("PLATFORMIO_CALLER"): + caller = getenv("PLATFORMIO_CALLER") + elif getenv("C9_UID"): + caller = "C9" + app.set_session_var("command_ctx", ctx) app.set_session_var("force_option", force) app.set_session_var("caller_id", caller) From 22bb1c39b1b9441dd5d2661d674100987e937067 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 29 Aug 2016 13:35:35 +0300 Subject: [PATCH 225/284] Handle EOL when update VCS ignore file --- examples | 2 +- platformio/commands/init.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/examples b/examples index e614de50..5cafb1f7 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit e614de50bfefe7c0aea1731bebd8afa9e91293e2 +Subproject commit 5cafb1f792a240d719036a9b36fb21e6fd746d05 diff --git a/platformio/commands/init.py b/platformio/commands/init.py index 943cd9cb..f04c7088 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -278,6 +278,8 @@ def init_cvs_ignore(project_dir): 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: current.append(d) From 0f8f9c94cd0082ecdd808535e933c6212cb8c97d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 29 Aug 2016 14:10:09 +0300 Subject: [PATCH 226/284] Make less verbose AS command --- platformio/builder/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 356b862a..15a248b2 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -98,7 +98,7 @@ if not int(ARGUMENTS.get("PIOVERBOSE", 0)): DEFAULT_ENV_OPTIONS['ARCOMSTR'] = "Archiving $TARGET" DEFAULT_ENV_OPTIONS['LINKCOMSTR'] = "Linking $TARGET" DEFAULT_ENV_OPTIONS['RANLIBCOMSTR'] = "Indexing $TARGET" - for k in ("ASPPCOMSTR", "CCCOMSTR", "CXXCOMSTR"): + for k in ("ASCOMSTR", "ASPPCOMSTR", "CCCOMSTR", "CXXCOMSTR"): DEFAULT_ENV_OPTIONS[k] = "Compiling $TARGET" env = DefaultEnvironment(**DEFAULT_ENV_OPTIONS) From 023e2978bad0c3db2d088ca45783bc00a6ba8850 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 29 Aug 2016 14:56:55 +0300 Subject: [PATCH 227/284] Disable platforms patching (while PIO3 is not released) --- platformio/maintenance.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platformio/maintenance.py b/platformio/maintenance.py index ee3ba4fc..0095beaa 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -133,10 +133,12 @@ def after_upgrade(ctx): if u.run(ctx): app.set_state_item("last_version", __version__) - # patch development platforms + # update development platforms pm = PlatformManager() for manifest in pm.get_installed(): - pm.update(manifest['name'], "^" + manifest['version']) + # @TODO Uncomment line below after first PIO3 release + # pm.update(manifest['name'], "^" + manifest['version']) + pm.update(manifest['name']) click.secho( "PlatformIO has been successfully upgraded to %s!\n" % From f8e70c9362416559869a04ce693f6debcbf3ff35 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 29 Aug 2016 20:20:12 +0300 Subject: [PATCH 228/284] Improve detecting of Python EXE Path --- platformio/app.py | 2 +- platformio/builder/main.py | 5 ++--- platformio/commands/upgrade.py | 4 +--- platformio/ide/projectgenerator.py | 6 ++---- platformio/managers/platform.py | 14 ++------------ platformio/util.py | 16 +++++++++++++++- 6 files changed, 23 insertions(+), 24 deletions(-) diff --git a/platformio/app.py b/platformio/app.py index 54ddf9be..25ec8ce7 100644 --- a/platformio/app.py +++ b/platformio/app.py @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import hashlib import json import uuid -import hashlib from copy import deepcopy from os import environ, getenv from os.path import getmtime, isfile, join diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 15a248b2..2b5ea8d3 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -14,9 +14,8 @@ import base64 import json -import sys from os import environ -from os.path import join, normpath +from os.path import join from time import time from SCons.Script import (ARGUMENTS, COMMAND_LINE_TARGETS, @@ -91,7 +90,7 @@ DEFAULT_ENV_OPTIONS = dict( util.get_projectlib_dir(), util.get_projectlibdeps_dir(), join("$PIOHOME_DIR", "lib") ], - PYTHONEXE=normpath(sys.executable)) + PYTHONEXE=util.get_pythonexe_path()) if not int(ARGUMENTS.get("PIOVERBOSE", 0)): print "Verbose mode can be enabled via `-v, --verbose` option" diff --git a/platformio/commands/upgrade.py b/platformio/commands/upgrade.py index 5f81807d..ef613fc8 100644 --- a/platformio/commands/upgrade.py +++ b/platformio/commands/upgrade.py @@ -12,9 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os import re -import sys import click import requests @@ -43,7 +41,7 @@ def cli(): r = None try: for cmd in cmds: - cmd = [os.path.normpath(sys.executable), "-m"] + cmd + cmd = [util.get_pythonexe_path(), "-m"] + cmd r = None r = util.exec_command(cmd) diff --git a/platformio/ide/projectgenerator.py b/platformio/ide/projectgenerator.py index ecd2f868..03df1840 100644 --- a/platformio/ide/projectgenerator.py +++ b/platformio/ide/projectgenerator.py @@ -15,9 +15,7 @@ import json import os import re -import sys -from os.path import (abspath, basename, expanduser, isdir, isfile, join, - normpath, relpath) +from os.path import abspath, basename, expanduser, isdir, isfile, join, relpath import bottle @@ -63,7 +61,7 @@ class ProjectGenerator(object): envdata = self.get_project_env() if "env_name" not in envdata: return data - cmd = [normpath(sys.executable), "-m", "platformio", "-f"] + cmd = [util.get_pythonexe_path(), "-m", "platformio", "-f"] if app.get_session_var("caller_id"): cmd.extend(["-c", app.get_session_var("caller_id")]) cmd.extend(["run", "-t", "idedata", "-e", envdata['env_name']]) diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 4372bb0c..05a303b7 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -15,7 +15,6 @@ import base64 import os import re -import sys from imp import load_source from multiprocessing import cpu_count from os.path import basename, dirname, isdir, isfile, join @@ -260,18 +259,8 @@ class PlatformRunMixin(object): return result def _run_scons(self, variables, targets): - # pass current PYTHONPATH to SCons - if "PYTHONPATH" in os.environ: - _PYTHONPATH = os.environ.get("PYTHONPATH").split(os.pathsep) - else: - _PYTHONPATH = [] - for p in os.sys.path: - if p not in _PYTHONPATH: - _PYTHONPATH.append(p) - os.environ['PYTHONPATH'] = os.pathsep.join(_PYTHONPATH) - cmd = [ - os.path.normpath(sys.executable), + util.get_pythonexe_path(), join(self.get_package_dir("tool-scons"), "script", "scons"), "-Q", "-j %d" % self.get_job_nums(), "--warn=no-no-parallel-support", "-f", join(util.get_source_dir(), "builder", "main.py") @@ -283,6 +272,7 @@ class PlatformRunMixin(object): for key, value in variables.items(): cmd.append("%s=%s" % (key.upper(), base64.b64encode(value))) + util.copy_pythonpath_to_osenv() result = util.exec_command( cmd, stdout=util.AsyncPipe(self.on_run_out), diff --git a/platformio/util.py b/platformio/util.py index 4dbf530e..0a55725a 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -22,7 +22,7 @@ import subprocess import sys from glob import glob from os.path import (abspath, basename, dirname, expanduser, isdir, isfile, - join, splitdrive) + join, normpath, splitdrive) from platform import system, uname from shutil import rmtree from threading import Thread @@ -299,6 +299,16 @@ def exec_command(*args, **kwargs): return result +def copy_pythonpath_to_osenv(): + _PYTHONPATH = [] + if "PYTHONPATH" in os.environ: + _PYTHONPATH = os.environ.get("PYTHONPATH").split(os.pathsep) + for p in os.sys.path: + if p not in _PYTHONPATH: + _PYTHONPATH.append(p) + os.environ['PYTHONPATH'] = os.pathsep.join(_PYTHONPATH) + + def get_serialports(): try: from serial.tools.list_ports import comports @@ -446,6 +456,10 @@ def get_frameworks(type_=None): return frameworks +def get_pythonexe_path(): + return os.environ.get("PYTHONEXEPATH", normpath(sys.executable)) + + def where_is_program(program, envpath=None): env = os.environ if envpath: From 5d2f42a5a82b0df8056e97d17ae8cb345687edb0 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 29 Aug 2016 22:06:37 +0300 Subject: [PATCH 229/284] Cleanup PackageManager --- platformio/commands/lib.py | 6 ++-- platformio/managers/lib.py | 8 ++--- platformio/managers/package.py | 52 ++++++++++++++++-------------- platformio/managers/platform.py | 56 +++++++++++---------------------- 4 files changed, 53 insertions(+), 69 deletions(-) diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index ba179b63..5d67c933 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -252,14 +252,14 @@ def lib_list(lm, json_output): @click.argument("library", metavar="[LIBRARY]") def lib_show(lm, library): # pylint: disable=too-many-branches name, requirements, url = lm.parse_pkg_name(library) - installed_dir = lm.get_installed_dir(name, requirements, url) - if not installed_dir: + package_dir = lm.get_package_dir(name, requirements, url) + if not package_dir: click.secho( "%s @ %s is not installed" % (name, requirements or "*"), fg="yellow") return - manifest = lm.load_manifest(installed_dir) + manifest = lm.load_manifest(package_dir) click.secho(manifest['name'], fg="cyan") click.echo("=" * len(manifest['name'])) diff --git a/platformio/managers/lib.py b/platformio/managers/lib.py index 379b6d22..2ebb7c07 100644 --- a/platformio/managers/lib.py +++ b/platformio/managers/lib.py @@ -114,9 +114,9 @@ class LibraryManager(BasePkgManager): if name.startswith("id="): return int(name[3:]) # try to find ID from installed packages - installed_dir = self.get_installed_dir(name, requirements) - if installed_dir: - manifest = self.load_manifest(installed_dir) + package_dir = self.get_package_dir(name, requirements) + if package_dir: + manifest = self.load_manifest(package_dir) if "id" in manifest: return int(manifest['id']) return int( @@ -151,7 +151,7 @@ class LibraryManager(BasePkgManager): if not _url: _name = "id=%d" % self._get_pkg_id_by_name( _name, _requirements, silent=silent, interactive=interactive) - already_installed = self.get_installed_dir(_name, _requirements, _url) + already_installed = self.get_package(_name, _requirements, _url) pkg_dir = BasePkgManager.install(self, _name if not _url else name, _requirements, silent, trigger_event) diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 23ff4483..87fd662b 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -370,7 +370,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): BasePkgManager._INSTALLED_CACHE[self.package_dir] = items return items - def get_installed_dir(self, name, requirements=None, url=None): + def get_package(self, name, requirements=None, url=None): pkg_id = int(name[3:]) if name.startswith("id=") else 0 best = None reqspec = None @@ -406,19 +406,23 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): # check that URL is the same in installed package (VCS) if url and best.get("url") != url: return None - return best.get("__pkg_dir") + return best return None + def get_package_dir(self, name, requirements=None, url=None): + package = self.get_package(name, requirements, url) + return package.get("__pkg_dir") if package else None + def is_outdated(self, name, requirements=None): - installed_dir = self.get_installed_dir(name, requirements) - if not installed_dir: + package_dir = self.get_package_dir(name, requirements) + if not package_dir: click.secho( "%s @ %s is not installed" % (name, requirements or "*"), fg="yellow") return - if self.get_vcs_manifest_path(installed_dir): + if self.get_vcs_manifest_path(package_dir): return False - manifest = self.load_manifest(installed_dir) + manifest = self.load_manifest(package_dir) return manifest['version'] != self.get_latest_repo_version( name, requirements) @@ -429,20 +433,20 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): trigger_event=True, interactive=False): # pylint: disable=unused-argument name, requirements, url = self.parse_pkg_name(name, requirements) - installed_dir = self.get_installed_dir(name, requirements, url) + package_dir = self.get_package_dir(name, requirements, url) - if not installed_dir or not silent: + if not package_dir or not silent: msg = "Installing " + click.style(name, fg="cyan") if requirements: msg += " @ " + requirements self.print_message(msg) - if installed_dir: + if package_dir: if not silent: click.secho( "{name} @ {version} is already installed".format( - **self.load_manifest(installed_dir)), + **self.load_manifest(package_dir)), fg="yellow") - return installed_dir + return package_dir if url: pkg_dir = self._install_from_url(name, url, requirements) @@ -470,24 +474,24 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): def uninstall(self, name, requirements=None, trigger_event=True): name, requirements, url = self.parse_pkg_name(name, requirements) - installed_dir = self.get_installed_dir(name, requirements, url) - if not installed_dir: + package_dir = self.get_package_dir(name, requirements, url) + if not package_dir: click.secho( "%s @ %s is not installed" % (name, requirements or "*"), fg="yellow") return - manifest = self.load_manifest(installed_dir) + manifest = self.load_manifest(package_dir) click.echo( "Uninstalling %s @ %s: \t" % (click.style( manifest['name'], fg="cyan"), manifest['version']), nl=False) - if isdir(installed_dir): - if islink(installed_dir): - os.unlink(installed_dir) + if isdir(package_dir): + if islink(package_dir): + os.unlink(package_dir) else: - util.rmtree_(installed_dir) + util.rmtree_(package_dir) click.echo("[%s]" % click.style("OK", fg="green")) @@ -501,19 +505,19 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): def update(self, name, requirements=None, only_check=False): name, requirements, url = self.parse_pkg_name(name, requirements) - installed_dir = self.get_installed_dir(name, requirements, url) - if not installed_dir: + package_dir = self.get_package_dir(name, requirements, url) + if not package_dir: click.secho( "%s @ %s is not installed" % (name, requirements or "*"), fg="yellow") return is_vcs_pkg = False - if self.get_vcs_manifest_path(installed_dir): + if self.get_vcs_manifest_path(package_dir): is_vcs_pkg = True - manifest_path = self.get_vcs_manifest_path(installed_dir) + manifest_path = self.get_vcs_manifest_path(package_dir) else: - manifest_path = self.get_manifest_path(installed_dir) + manifest_path = self.get_manifest_path(package_dir) manifest = self.load_manifest(manifest_path) click.echo( @@ -527,7 +531,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): click.echo("[%s]" % (click.style("Skip", fg="yellow"))) return click.echo("[%s]" % (click.style("VCS", fg="yellow"))) - vcs = VCSClientFactory.newClient(installed_dir, manifest['url']) + vcs = VCSClientFactory.newClient(package_dir, manifest['url']) if not vcs.can_be_updated: click.secho( "Skip update because repository is fixed " diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 05a303b7..c7f3f14a 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -144,8 +144,8 @@ class PlatformFactory(object): else: if not requirements and "@" in name: name, requirements = name.rsplit("@", 1) - platform_dir = PlatformManager().get_installed_dir(name, - requirements) + platform_dir = PlatformManager().get_package_dir(name, + requirements) if not platform_dir: raise exception.UnknownPlatform(name if not requirements else @@ -167,30 +167,6 @@ class PlatformFactory(object): class PlatformPackagesMixin(object): - def get_installed_packages(self): - items = {} - installed = self.pm.get_installed() - for name, opts in self.packages.items(): - manifest = None - reqspec = None - try: - reqspec = semantic_version.Spec(opts['version']) - except ValueError: - pass - - for p in installed: - if p['name'] != name: - continue - if reqspec and not reqspec.match( - semantic_version.Version(p['version'])): - continue - elif (not manifest or semantic_version.compare( - p['version'], manifest['version']) == 1): - manifest = p - if manifest: - items[name] = manifest - return items - def install_packages(self, with_packages=None, without_packages=None, @@ -217,6 +193,14 @@ class PlatformPackagesMixin(object): return True + def get_installed_packages(self): + items = {} + for name, opts in self.packages.items(): + package = self.pm.get_package(name, opts['version']) + if package: + items[name] = package + return items + def update_packages(self, only_check=False): for name in self.get_installed_packages(): self.pm.update(name, self.packages[name]['version'], only_check) @@ -228,6 +212,14 @@ class PlatformPackagesMixin(object): return True return False + def get_package_dir(self, name): + return self.pm.get_package_dir(name, + self.packages[name].get("version")) + + def get_package_version(self, name): + package = self.pm.get_package(name, self.packages[name].get("version")) + return package['version'] if package else None + class PlatformRunMixin(object): @@ -417,18 +409,6 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): def board_config(self, id_): return self.get_boards(id_) - def get_package_dir(self, name): - packages = self.get_installed_packages() - if name not in packages: - return None - return packages[name]['__pkg_dir'] - - def get_package_version(self, name): - packages = self.get_installed_packages() - if name not in packages: - return None - return packages[name]['version'] - def get_package_type(self, name): return self.packages[name].get("type") From d516d31b3058751b945e67dcbc34c346a1183238 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 29 Aug 2016 22:07:21 +0300 Subject: [PATCH 230/284] Remove unused import --- platformio/managers/platform.py | 1 - 1 file changed, 1 deletion(-) diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index c7f3f14a..e95cdc01 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -20,7 +20,6 @@ from multiprocessing import cpu_count from os.path import basename, dirname, isdir, isfile, join import click -import semantic_version from platformio import app, exception, util from platformio.managers.package import BasePkgManager, PackageManager From 64520130f6d0014aac7166d2fb2189c3a099c211 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 29 Aug 2016 22:19:56 +0300 Subject: [PATCH 231/284] Add development packages --- tox.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tox.ini b/tox.ini index 172bb4c5..d2fffe23 100644 --- a/tox.ini +++ b/tox.ini @@ -21,6 +21,9 @@ usedevelop = True deps = isort flake8 + yapf + pylint + pytest commands = python --version [testenv:docs] From dec5529a6487d93b1e608e41520904dcee2ac682 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 29 Aug 2016 22:25:38 +0300 Subject: [PATCH 232/284] Cleanup not used packages after update --- platformio/managers/platform.py | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index e95cdc01..2896ceae 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -72,6 +72,7 @@ class PlatformManager(BasePkgManager): BasePkgManager.update(self, name, requirements, only_check) p = PlatformFactory.newPlatform(name, requirements) p.update_packages(only_check) + self.cleanup_packages(p.packages.keys()) return True def is_outdated(self, name, requirements=None): From d0d139511ced2fa8d66aa01bb65f81ad4e974026 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 30 Aug 2016 20:38:00 +0300 Subject: [PATCH 233/284] Skip unknown packages while updating --- platformio/managers/package.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 87fd662b..649b747f 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -27,6 +27,7 @@ from platformio.downloader import FileDownloader from platformio.unpacker import FileUnpacker from platformio.vcsclient import VCSClientFactory + # pylint: disable=too-many-arguments @@ -544,6 +545,9 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): json.dump(manifest, fp) else: latest_version = self.get_latest_repo_version(name, requirements) + if not latest_version: + click.echo("[%s]" % (click.style("Unknown", fg="yellow"))) + return if manifest['version'] == latest_version: click.echo("[%s]" % (click.style("Up-to-date", fg="green"))) return From 34a860cfa6cc8353a7b6a2da517c991d0624cf80 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 30 Aug 2016 23:09:53 +0300 Subject: [PATCH 234/284] Limit max sources length for Win to 6000 chars --- platformio/builder/tools/piowinhooks.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platformio/builder/tools/piowinhooks.py b/platformio/builder/tools/piowinhooks.py index 2b2dcf3e..c1b0895a 100644 --- a/platformio/builder/tools/piowinhooks.py +++ b/platformio/builder/tools/piowinhooks.py @@ -17,7 +17,9 @@ from os import makedirs from os.path import isdir, isfile, join from platform import system -MAX_SOURCES_LENGTH = 8000 # Windows CLI has limit with command length to 8192 +# Windows CLI has limit with command length to 8192 +# Leave 2000 chars for flags and other options +MAX_SOURCES_LENGTH = 6000 def long_sources_hook(env, sources): @@ -38,7 +40,7 @@ def long_sources_hook(env, sources): def long_incflags_hook(env, incflags): _incflags = env.subst(incflags).replace("\\", "/") - if len(_incflags) < MAX_SOURCES_LENGTH - 2000: + if len(_incflags) < MAX_SOURCES_LENGTH: return incflags # fix space in paths From 8a379d2db26ff0deb37be83e82d1abe72e5439f8 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 31 Aug 2016 00:16:23 +0300 Subject: [PATCH 235/284] Refactor INO to CPP converter --- HISTORY.rst | 1 + docs/platforms/creating_platform.rst | 5 +- platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 30 +++-- platformio/builder/tools/piomisc.py | 156 +++++++++++++------------ platformio/builder/tools/platformio.py | 8 +- platformio/commands/platform.py | 2 +- platformio/managers/package.py | 6 +- tests/ino2cpp/basic/basic.ino | 18 +++ tests/ino2cpp/multifiles/bar.ino | 3 + tests/ino2cpp/multifiles/foo.pde | 13 +++ tests/test_ino2cpp.py | 41 +++++++ 12 files changed, 179 insertions(+), 106 deletions(-) create mode 100644 tests/ino2cpp/basic/basic.ino create mode 100644 tests/ino2cpp/multifiles/bar.ino create mode 100644 tests/ino2cpp/multifiles/foo.pde create mode 100644 tests/test_ino2cpp.py diff --git a/HISTORY.rst b/HISTORY.rst index 6be89824..901c1ba9 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -73,6 +73,7 @@ PlatformIO 3.0 * Print human-readable information when processing environments without ``-v, --verbose`` option (`issue #721 `_) +* Improved INO to CPP converter * Added ``license`` field to `library.json `__ (`issue #522 `_) * Warn about unknown options in project configuration file ``platformio.ini`` diff --git a/docs/platforms/creating_platform.rst b/docs/platforms/creating_platform.rst index 90f14517..29ceec6f 100644 --- a/docs/platforms/creating_platform.rst +++ b/docs/platforms/creating_platform.rst @@ -198,10 +198,7 @@ Manifest File ``platform.json`` "description": "My custom development platform", "url": "http://example.com", "homepage": "http://platformio.org/platforms/myplatform", - "license": { - "type": "Apache-2.0", - "url": "http://opensource.org/licenses/apache2.0.php" - }, + "license": "Apache-2.0", "engines": { "platformio": "~3.0.0", "scons": ">=2.3.0,<2.6.0" diff --git a/platformio/__init__.py b/platformio/__init__.py index 7ee7955e..29a27397 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0a13") +VERSION = (3, 0, "0b1") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 04b2d40c..47f0351c 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -134,8 +134,8 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes def build_dir(self): return join("$BUILD_DIR", "lib", basename(self.path)) - def get_inc_dirs(self, use_build_dir=False): - return [self.build_dir if use_build_dir else self.src_dir] + def get_inc_dirs(self): + return [self.src_dir] @property def build_flags(self): @@ -290,8 +290,7 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes self.env.AppendUnique(**{key: lb.env.get(key)}) if not self._built_node: - self.env.AppendUnique(CPPPATH=self.get_inc_dirs( - use_build_dir=True)) + self.env.AppendUnique(CPPPATH=self.get_inc_dirs()) if self.lib_archive: self._built_node = self.env.BuildLibrary( self.build_dir, self.src_dir, self.src_filter) @@ -345,12 +344,11 @@ class ArduinoLibBuilder(LibBuilderBase): manifest[key.strip()] = value.strip() return manifest - def get_inc_dirs(self, use_build_dir=False): - inc_dirs = LibBuilderBase.get_inc_dirs(self, use_build_dir) + def get_inc_dirs(self): + inc_dirs = LibBuilderBase.get_inc_dirs(self) if not isdir(join(self.path, "utility")): return inc_dirs - inc_dirs.append( - join(self.build_dir if use_build_dir else self.path, "utility")) + inc_dirs.append(join(self.path, "utility")) return inc_dirs @property @@ -382,8 +380,8 @@ class MbedLibBuilder(LibBuilderBase): return join(self.path, "source") return LibBuilderBase.src_dir.fget(self) - def get_inc_dirs(self, use_build_dir=False): - inc_dirs = LibBuilderBase.get_inc_dirs(self, use_build_dir) + def get_inc_dirs(self): + inc_dirs = LibBuilderBase.get_inc_dirs(self) if self.path not in inc_dirs: inc_dirs.append(self.path) for p in self._manifest.get("extraIncludes", []): @@ -451,12 +449,11 @@ class PlatformIOLibBuilder(LibBuilderBase): ilist = [i.strip() for i in ilist.split(",")] return item.lower() in [i.lower() for i in ilist] - def get_inc_dirs(self, use_build_dir=False): - inc_dirs = LibBuilderBase.get_inc_dirs(self, use_build_dir) + def get_inc_dirs(self): + inc_dirs = LibBuilderBase.get_inc_dirs(self) for path in self.env['CPPPATH']: if path not in self.envorigin['CPPPATH']: - inc_dirs.append( - path if use_build_dir else self.env.subst(path)) + inc_dirs.append(self.env.subst(path)) return inc_dirs @@ -499,8 +496,9 @@ def GetLibBuilders(env): try: lb = LibBuilderFactory.new(env, join(libs_dir, item)) except ValueError: - sys.stderr.write("Skip library with broken manifest: %s\n" % - join(libs_dir, item)) + if verbose: + sys.stderr.write("Skip library with broken manifest: %s\n" + % join(libs_dir, item)) continue if _check_lib_builder(lb): items += (lb, ) diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 78ca1e26..e5b73741 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -19,7 +19,8 @@ import re import sys from glob import glob from os import environ, remove -from os.path import isfile, join +from os.path import basename, isfile, join +from tempfile import mkstemp from SCons.Action import Action from SCons.Script import ARGUMENTS @@ -38,106 +39,118 @@ class InoToCPPConverter(object): DETECTMAIN_RE = re.compile(r"void\s+(setup|loop)\s*\(", re.M | re.I) PROTOPTRS_TPLRE = r"\([^&\(]*&(%s)[^\)]*\)" - def __init__(self, nodes): - self.nodes = nodes + def __init__(self, env): + self.env = env + self._main_ino = None def is_main_node(self, contents): return self.DETECTMAIN_RE.search(contents) - def _parse_prototypes(self, file_path, contents): + def convert(self, nodes): + contents = self.merge(nodes) + if not contents: + return + return self.process(contents) + + def merge(self, nodes): + lines = [] + for node in nodes: + contents = node.get_text_contents() + _lines = [ + '# 1 "%s"' % node.get_path().replace("\\", "/"), contents + ] + if self.is_main_node(contents): + lines = _lines + lines + self._main_ino = node.get_path() + else: + lines.extend(_lines) + + return "\n".join(["#include "] + lines) if lines else None + + 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() + with open(out_file, "w") as fp: + fp.write(self.append_prototypes(contents)) + return out_file + + def _gcc_preprocess(self, contents, out_file): + tmp_path = mkstemp()[1] + with open(tmp_path, "w") as fp: + fp.write(contents) + fp.close() + 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]))) + remove(tmp_path) + return isfile(out_file) + + def _parse_prototypes(self, contents): prototypes = [] reserved_keywords = set(["if", "else", "while"]) for match in self.PROTOTYPE_RE.finditer(contents): if (set([match.group(2).strip(), match.group(3).strip()]) & reserved_keywords): continue - prototypes.append({"path": file_path, "match": match}) + prototypes.append(match) return prototypes - def append_prototypes(self, file_path, contents, prototypes): - result = [] + @staticmethod + def _get_total_lines(contents): + total = 0 + for line in contents.split("\n")[::-1]: + if line.startswith("#"): + tokens = line.split(" ", 3) + if len(tokens) > 2 and tokens[1].isdigit(): + return int(tokens[1]) + total + total += 1 + return total + + def append_prototypes(self, contents): + prototypes = self._parse_prototypes(contents) if not prototypes: - return result - - prototype_names = set( - [p['match'].group(3).strip() for p in prototypes]) - split_pos = prototypes[0]['match'].start() - for item in prototypes: - if item['path'] == file_path: - split_pos = item['match'].start() - break + return contents + 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) if match_ptrs: split_pos = contents.rfind("\n", 0, match_ptrs.start()) + result = [] result.append(contents[:split_pos].strip()) - result.append("%s;" % - ";\n".join([p['match'].group(1) for p in prototypes])) + result.append("%s;" % ";\n".join([m.group(1) for m in prototypes])) result.append('#line %d "%s"' % - (contents.count("\n", 0, split_pos) + 2, - file_path.replace("\\", "/"))) + (self._get_total_lines(contents[:split_pos]), + self._main_ino.replace("\\", "/"))) result.append(contents[split_pos:].strip()) - - return result - - def convert(self): - prototypes = [] - data = [] - for node in self.nodes: - ino_contents = node.get_text_contents() - prototypes += self._parse_prototypes(node.get_path(), ino_contents) - - item = (node.get_path(), ino_contents) - if self.is_main_node(ino_contents): - data = [item] + data - else: - data.append(item) - - if not data: - return None - - result = ["#include "] - is_first = True - for file_path, contents in data: - result.append('#line 1 "%s"' % file_path.replace("\\", "/")) - - if is_first and prototypes: - result += self.append_prototypes(file_path, contents, - prototypes) - else: - result.append(contents) - is_first = False - return "\n".join(result) def ConvertInoToCpp(env): - def delete_tmpcpp_file(file_): + def _delete_file(path): try: - remove(file_) + if isfile(path): + remove(path) except: # pylint: disable=bare-except - if isfile(file_): - print("Warning: Could not remove temporary file '%s'. " - "Please remove it manually." % file_) + if path and isfile(path): + sys.stderr.write( + "Warning: Could not remove temporary file '%s'. " + "Please remove it manually.\n" % path) ino_nodes = (env.Glob(join("$PROJECTSRC_DIR", "*.ino")) + env.Glob(join("$PROJECTSRC_DIR", "*.pde"))) + c = InoToCPPConverter(env) + out_file = c.convert(ino_nodes) - c = InoToCPPConverter(ino_nodes) - data = c.convert() - - if not data: - return - - tmpcpp_file = join(env.subst("$PROJECTSRC_DIR"), "tmp_ino_to.cpp") - with open(tmpcpp_file, "w") as f: - f.write(data) - - atexit.register(delete_tmpcpp_file, tmpcpp_file) + atexit.register(_delete_file, out_file) def DumpIDEData(env): @@ -146,14 +159,7 @@ def DumpIDEData(env): includes = [] for item in env_.get("CPPPATH", []): - invardir = False - for vardiritem in env_.get("VARIANT_DIRS", []): - if item == vardiritem[0]: - includes.append(env_.subst(vardiritem[1])) - invardir = True - break - if not invardir: - includes.append(env_.subst(item)) + includes.append(env_.subst(item)) # installed libs for lb in env.GetLibBuilders(): diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 9634ef1e..3f56eebd 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -198,11 +198,6 @@ def MatchSourceFiles(env, src_dir, src_filter=None): return sorted(list(matches)) -def VariantDirWrap(env, variant_dir, src_dir, duplicate=False): - DefaultEnvironment().Append(VARIANT_DIRS=[(variant_dir, src_dir)]) - env.VariantDir(variant_dir, src_dir, duplicate) - - def CollectBuildFiles(env, variant_dir, src_dir, @@ -222,7 +217,7 @@ def CollectBuildFiles(env, if _var_dir not in variants: variants.append(_var_dir) - env.VariantDirWrap(_var_dir, _src_dir, duplicate) + env.VariantDir(_var_dir, _src_dir, duplicate) if env.IsFileWithExt(item, SRC_BUILD_EXT): sources.append(env.File(join(_var_dir, basename(item)))) @@ -283,7 +278,6 @@ def generate(env): env.AddMethod(ProcessUnFlags) env.AddMethod(IsFileWithExt) env.AddMethod(MatchSourceFiles) - env.AddMethod(VariantDirWrap) env.AddMethod(CollectBuildFiles) env.AddMethod(BuildFrameworks) env.AddMethod(BuildLibrary) diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index 7934ebe9..7f98b257 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -165,7 +165,7 @@ def platform_show(platform): if p.homepage: click.echo("Home: %s" % p.homepage) if p.license: - click.echo("License: %s" % p.license.get("type")) + click.echo("License: %s" % p.license) if p.frameworks: click.echo("Frameworks: %s" % ", ".join(p.frameworks.keys())) diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 649b747f..39626f76 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -27,7 +27,6 @@ from platformio.downloader import FileDownloader from platformio.unpacker import FileUnpacker from platformio.vcsclient import VCSClientFactory - # pylint: disable=too-many-arguments @@ -504,7 +503,10 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): label=manifest['name']) return True - def update(self, name, requirements=None, only_check=False): + def update(self, # pylint: disable=too-many-return-statements + name, + requirements=None, + only_check=False): name, requirements, url = self.parse_pkg_name(name, requirements) package_dir = self.get_package_dir(name, requirements, url) if not package_dir: diff --git a/tests/ino2cpp/basic/basic.ino b/tests/ino2cpp/basic/basic.ino new file mode 100644 index 00000000..47b48694 --- /dev/null +++ b/tests/ino2cpp/basic/basic.ino @@ -0,0 +1,18 @@ + +struct MyItem { + byte foo[50]; + int bar; +}; + +void setup() { + struct MyItem item1; + myFunction(&item1); +} + +void loop() { + +} + +void myFunction(struct MyItem *item) { + +} diff --git a/tests/ino2cpp/multifiles/bar.ino b/tests/ino2cpp/multifiles/bar.ino new file mode 100644 index 00000000..5eac56d9 --- /dev/null +++ b/tests/ino2cpp/multifiles/bar.ino @@ -0,0 +1,3 @@ +void barFunc () { // my comment + +} \ No newline at end of file diff --git a/tests/ino2cpp/multifiles/foo.pde b/tests/ino2cpp/multifiles/foo.pde new file mode 100644 index 00000000..4abeeffc --- /dev/null +++ b/tests/ino2cpp/multifiles/foo.pde @@ -0,0 +1,13 @@ + +void setup() { + barFunc(); + fooFunc(); +} + +void loop() { + +} + +char* fooFunc() { + +} \ No newline at end of file diff --git a/tests/test_ino2cpp.py b/tests/test_ino2cpp.py new file mode 100644 index 00000000..0a6efc77 --- /dev/null +++ b/tests/test_ino2cpp.py @@ -0,0 +1,41 @@ +# Copyright 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from os import listdir +from os.path import dirname, isdir, join, normpath + +import pytest + +from platformio import util + + +def pytest_generate_tests(metafunc): + if "piotest_dir" not in metafunc.fixturenames: + return + test_dir = normpath(join(dirname(__file__), "ino2cpp")) + test_dirs = [] + for name in listdir(test_dir): + if isdir(join(test_dir, name)): + test_dirs.append(join(test_dir, name)) + test_dirs.sort() + metafunc.parametrize("piotest_dir", test_dirs) + + +@pytest.mark.examples +def test_ci(platformio_setup, piotest_dir): + result = util.exec_command( + ["platformio", "--force", "ci", piotest_dir, "-b", "uno"] + ) + if result['returncode'] != 0: + pytest.fail(result) From a94aa898a6b975c289201e5794073f5ea2c99584 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 31 Aug 2016 00:34:23 +0300 Subject: [PATCH 236/284] Remove temporary INO/CPP file at process exit --- platformio/builder/tools/piomisc.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index e5b73741..2dd9c013 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -86,7 +86,7 @@ class InoToCPPConverter(object): '$CXX -o "{0}" -x c++ -fpreprocessed -dD -E "{1}"'.format( out_file, tmp_path), "Converting " + basename( out_file[:-4]))) - remove(tmp_path) + atexit.register(_delete_file, tmp_path) return isfile(out_file) def _parse_prototypes(self, contents): @@ -134,17 +134,6 @@ class InoToCPPConverter(object): def ConvertInoToCpp(env): - - def _delete_file(path): - try: - if isfile(path): - remove(path) - except: # pylint: disable=bare-except - if path and isfile(path): - sys.stderr.write( - "Warning: Could not remove temporary file '%s'. " - "Please remove it manually.\n" % path) - ino_nodes = (env.Glob(join("$PROJECTSRC_DIR", "*.ino")) + env.Glob(join("$PROJECTSRC_DIR", "*.pde"))) c = InoToCPPConverter(env) @@ -153,6 +142,16 @@ def ConvertInoToCpp(env): atexit.register(_delete_file, out_file) +def _delete_file(path): + try: + if isfile(path): + remove(path) + except: # pylint: disable=bare-except + if path and isfile(path): + sys.stderr.write("Warning: Could not remove temporary file '%s'. " + "Please remove it manually.\n" % path) + + def DumpIDEData(env): def get_includes(env_): From c33a745862f760fbb596019db2341ff7d7a2f1de Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 31 Aug 2016 01:03:13 +0300 Subject: [PATCH 237/284] Fix wrong line number for INO file when ``#warning`` directive is used // Resolve #742 --- HISTORY.rst | 4 ++++ tests/commands/test_boards.py | 6 +++--- tests/commands/test_update.py | 2 +- tests/conftest.py | 15 --------------- tests/ino2cpp/basic/basic.ino | 5 ++++- tests/ino2cpp/multifiles/foo.pde | 1 - tests/test_examples.py | 11 ++++------- tests/test_ino2cpp.py | 29 ++++++++++++++++------------- 8 files changed, 32 insertions(+), 41 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 901c1ba9..2fc14056 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -78,8 +78,12 @@ PlatformIO 3.0 (`issue #522 `_) * Warn about unknown options in project configuration file ``platformio.ini`` (`issue #740 `_) +* Fixed wrong line number for INO file when ``#warning`` directive is used + (`issue #742 `_) * Stopped supporting Python 2.6 +------ + * Development platform `Atmel SAM `__ + Fixed missing analog ports for Adafruit Feather M0 Bluefruit diff --git a/tests/commands/test_boards.py b/tests/commands/test_boards.py index 71f4ebd8..6b216146 100644 --- a/tests/commands/test_boards.py +++ b/tests/commands/test_boards.py @@ -18,7 +18,7 @@ from platformio.commands.boards import cli as cmd_boards from platformio.commands.platform import platform_search as cmd_platform_search -def test_board_json_output(platformio_setup, clirunner, validate_cliresult): +def test_board_json_output(clirunner, validate_cliresult): result = clirunner.invoke(cmd_boards, ["mbed", "--json-output"]) validate_cliresult(result) boards = json.loads(result.output) @@ -26,13 +26,13 @@ def test_board_json_output(platformio_setup, clirunner, validate_cliresult): assert any(["mbed" in b['frameworks'] for b in boards]) -def test_board_raw_output(platformio_setup, clirunner, validate_cliresult): +def test_board_raw_output(clirunner, validate_cliresult): result = clirunner.invoke(cmd_boards, ["energia"]) validate_cliresult(result) assert "titiva" in result.output -def test_board_options(platformio_setup, clirunner, validate_cliresult): +def test_board_options(clirunner, validate_cliresult): required_opts = set( ["fcpu", "frameworks", "id", "mcu", "name", "platform"]) diff --git a/tests/commands/test_update.py b/tests/commands/test_update.py index 27eb8c9d..f17f5bbd 100644 --- a/tests/commands/test_update.py +++ b/tests/commands/test_update.py @@ -15,7 +15,7 @@ from platformio.commands.update import cli as cmd_update -def test_update(platformio_setup, clirunner, validate_cliresult): +def test_update(clirunner, validate_cliresult): matches = ( "Platform Manager", "Up-to-date", diff --git a/tests/conftest.py b/tests/conftest.py index f5277a3e..9af9b6f7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -21,21 +21,6 @@ from click.testing import CliRunner requests.packages.urllib3.disable_warnings() -@pytest.fixture(scope="session") -def platformio_setup(request): - pioenvvars = ("ENABLE_TELEMETRY", ) - for v in pioenvvars: - os.environ["PLATFORMIO_SETTING_%s" % v] = "No" - - def platformio_teardown(): - for v in pioenvvars: - _name = "PLATFORMIO_SETTING_%s" % v - if _name in os.environ: - del os.environ[_name] - - request.addfinalizer(platformio_teardown) - - @pytest.fixture(scope="module") def clirunner(): return CliRunner() diff --git a/tests/ino2cpp/basic/basic.ino b/tests/ino2cpp/basic/basic.ino index 47b48694..461399de 100644 --- a/tests/ino2cpp/basic/basic.ino +++ b/tests/ino2cpp/basic/basic.ino @@ -1,4 +1,3 @@ - struct MyItem { byte foo[50]; int bar; @@ -7,8 +6,12 @@ struct MyItem { void setup() { struct MyItem item1; myFunction(&item1); + + } +#warning "Line number is 13" + void loop() { } diff --git a/tests/ino2cpp/multifiles/foo.pde b/tests/ino2cpp/multifiles/foo.pde index 4abeeffc..991bacbd 100644 --- a/tests/ino2cpp/multifiles/foo.pde +++ b/tests/ino2cpp/multifiles/foo.pde @@ -1,4 +1,3 @@ - void setup() { barFunc(); fooFunc(); diff --git a/tests/test_examples.py b/tests/test_examples.py index bfe428d9..75278d9c 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -19,6 +19,7 @@ from os.path import dirname, getsize, isdir, isfile, join, normpath import pytest from platformio import util +from platformio.commands.run import cli as cmd_run def pytest_generate_tests(metafunc): @@ -34,16 +35,12 @@ def pytest_generate_tests(metafunc): metafunc.parametrize("pioproject_dir", project_dirs) -@pytest.mark.examples -def test_run(platformio_setup, pioproject_dir): +def test_run(clirunner, validate_cliresult, pioproject_dir): if isdir(join(pioproject_dir, ".pioenvs")): util.rmtree_(join(pioproject_dir, ".pioenvs")) - result = util.exec_command( - ["platformio", "--force", "run", "--project-dir", pioproject_dir] - ) - if result['returncode'] != 0: - pytest.fail(result) + result = clirunner.invoke(cmd_run, ["-d", pioproject_dir]) + validate_cliresult(result) # check .elf file pioenvs_dir = join(pioproject_dir, ".pioenvs") diff --git a/tests/test_ino2cpp.py b/tests/test_ino2cpp.py index 0a6efc77..12fde08a 100644 --- a/tests/test_ino2cpp.py +++ b/tests/test_ino2cpp.py @@ -15,27 +15,30 @@ from os import listdir from os.path import dirname, isdir, join, normpath -import pytest +from platformio.commands.ci import cli as cmd_ci -from platformio import util +INOTEST_DIR = normpath(join(dirname(__file__), "ino2cpp")) def pytest_generate_tests(metafunc): if "piotest_dir" not in metafunc.fixturenames: return - test_dir = normpath(join(dirname(__file__), "ino2cpp")) test_dirs = [] - for name in listdir(test_dir): - if isdir(join(test_dir, name)): - test_dirs.append(join(test_dir, name)) + for name in listdir(INOTEST_DIR): + if isdir(join(INOTEST_DIR, name)): + test_dirs.append(join(INOTEST_DIR, name)) test_dirs.sort() metafunc.parametrize("piotest_dir", test_dirs) -@pytest.mark.examples -def test_ci(platformio_setup, piotest_dir): - result = util.exec_command( - ["platformio", "--force", "ci", piotest_dir, "-b", "uno"] - ) - if result['returncode'] != 0: - pytest.fail(result) +def test_example(clirunner, validate_cliresult, piotest_dir): + result = clirunner.invoke(cmd_ci, [piotest_dir, "-b", "uno"]) + validate_cliresult(result) + + +def test_warning_line(clirunner, validate_cliresult): + result = clirunner.invoke(cmd_ci, + [join(INOTEST_DIR, "basic"), "-b", "uno"]) + validate_cliresult(result) + assert ('basic.ino:13:2: warning: #warning "Line number is 13"' in + result.output) From e703054716d49c4fce7dcbfb92882649fa4a97c8 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 31 Aug 2016 01:26:08 +0300 Subject: [PATCH 238/284] Update INO2CPP examples --- tests/ino2cpp/basic/basic.ino | 29 +++++++++++++++++++++++------ tests/ino2cpp/multifiles/foo.pde | 5 +++-- tests/test_ino2cpp.py | 2 +- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/tests/ino2cpp/basic/basic.ino b/tests/ino2cpp/basic/basic.ino index 461399de..c44340aa 100644 --- a/tests/ino2cpp/basic/basic.ino +++ b/tests/ino2cpp/basic/basic.ino @@ -1,21 +1,38 @@ -struct MyItem { +typedef struct Item item; +struct Item { byte foo[50]; int bar; + void (*noob)(item*); }; +// test callback +class Foo { + + public: + Foo(void (*function)()) { + #warning "Line number is 13" + } + +}; + +Foo foo(&fooCallback); + +// + void setup() { - struct MyItem item1; + struct Item item1; myFunction(&item1); - - } -#warning "Line number is 13" void loop() { } -void myFunction(struct MyItem *item) { +void myFunction(struct Item *item) { + +} + +void fooCallback(){ } diff --git a/tests/ino2cpp/multifiles/foo.pde b/tests/ino2cpp/multifiles/foo.pde index 991bacbd..785166cd 100644 --- a/tests/ino2cpp/multifiles/foo.pde +++ b/tests/ino2cpp/multifiles/foo.pde @@ -1,5 +1,6 @@ +char buf[5]; + void setup() { - barFunc(); fooFunc(); } @@ -8,5 +9,5 @@ void loop() { } char* fooFunc() { - + return buf; } \ No newline at end of file diff --git a/tests/test_ino2cpp.py b/tests/test_ino2cpp.py index 12fde08a..c414ebc6 100644 --- a/tests/test_ino2cpp.py +++ b/tests/test_ino2cpp.py @@ -40,5 +40,5 @@ def test_warning_line(clirunner, validate_cliresult): result = clirunner.invoke(cmd_ci, [join(INOTEST_DIR, "basic"), "-b", "uno"]) validate_cliresult(result) - assert ('basic.ino:13:2: warning: #warning "Line number is 13"' in + assert ('basic.ino:13:4: warning: #warning "Line number is 13"' in result.output) From 7a88778f5e0e7037a123561fcf6d5ae11b3efef5 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 31 Aug 2016 01:47:57 +0300 Subject: [PATCH 239/284] Improve INO to CPP converter // Resolve #659 --- HISTORY.rst | 1 + platformio/builder/tools/piomisc.py | 2 +- tests/ino2cpp/basic/basic.ino | 10 +++++++--- tests/test_ino2cpp.py | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 2fc14056..052b63b2 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -74,6 +74,7 @@ PlatformIO 3.0 ``-v, --verbose`` option (`issue #721 `_) * Improved INO to CPP converter + (`issue #659 `_) * Added ``license`` field to `library.json `__ (`issue #522 `_) * Warn about unknown options in project configuration file ``platformio.ini`` diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 2dd9c013..33d9b2cb 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -31,7 +31,7 @@ from platformio import util class InoToCPPConverter(object): PROTOTYPE_RE = re.compile(r"""^( - (\s*[a-z_\d]+\*?){1,2} # return type + ([a-z_\d]+\*?){1,2} # return type (\s+[a-z_\d]+\s*) # name of prototype \([a-z_,\.\*\&\[\]\s\d]*\) # arguments )\s*\{ # must end with { diff --git a/tests/ino2cpp/basic/basic.ino b/tests/ino2cpp/basic/basic.ino index c44340aa..80b3be86 100644 --- a/tests/ino2cpp/basic/basic.ino +++ b/tests/ino2cpp/basic/basic.ino @@ -9,9 +9,13 @@ struct Item { class Foo { public: - Foo(void (*function)()) { - #warning "Line number is 13" - } + Foo(void (*function)()) { + #warning "Line number is 13" + } + + bool childFunc() { + + } }; diff --git a/tests/test_ino2cpp.py b/tests/test_ino2cpp.py index c414ebc6..0bb6b143 100644 --- a/tests/test_ino2cpp.py +++ b/tests/test_ino2cpp.py @@ -40,5 +40,5 @@ def test_warning_line(clirunner, validate_cliresult): result = clirunner.invoke(cmd_ci, [join(INOTEST_DIR, "basic"), "-b", "uno"]) validate_cliresult(result) - assert ('basic.ino:13:4: warning: #warning "Line number is 13"' in + assert ('basic.ino:13:14: warning: #warning "Line number is 13"' in result.output) From 1b32091d7d5d901fb76329346980ab944308f11c Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 31 Aug 2016 02:06:43 +0300 Subject: [PATCH 240/284] Fix broken Unit Testing --- platformio/__init__.py | 2 +- platformio/builder/main.py | 7 +++++-- platformio/commands/test.py | 4 +++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 29a27397..723890c0 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0b1") +VERSION = (3, 0, "0b2") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 2b5ea8d3..f78c4942 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -18,8 +18,9 @@ from os import environ from os.path import join from time import time -from SCons.Script import (ARGUMENTS, COMMAND_LINE_TARGETS, - AllowSubstExceptions, DefaultEnvironment, Variables) +from SCons.Script import (ARGUMENTS, COMMAND_LINE_TARGETS, DEFAULT_TARGETS, + AllowSubstExceptions, AlwaysBuild, + DefaultEnvironment, Variables) from platformio import util @@ -127,6 +128,8 @@ env.SConscriptChdir(0) env.SConsignFile(join("$PROJECTPIOENVS_DIR", ".sconsign.dblite")) env.SConscript("$BUILD_SCRIPT") +AlwaysBuild(env.Alias("test", DEFAULT_TARGETS + ["size"])) + if "UPLOAD_FLAGS" in env: env.Append(UPLOADERFLAGS=["$UPLOAD_FLAGS"]) diff --git a/platformio/commands/test.py b/platformio/commands/test.py index 6820fa31..db35db45 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -16,7 +16,7 @@ from fnmatch import fnmatch from os import getcwd, listdir -from os.path import isdir, join +from os.path import isdir, isfile, join from time import sleep, time import click @@ -173,6 +173,8 @@ class LocalTestProcessor(TestProcessorBase): def run(self): with util.cd(self.options['project_dir']): pioenvs_dir = util.get_projectpioenvs_dir() + program_path = join(pioenvs_dir, self.env_name, "program") + assert isfile(program_path) result = util.exec_command( [join(pioenvs_dir, self.env_name, "program")], stdout=util.AsyncPipe(self.on_run_out), From 3a7b0d2c9d5935ee25b7097e89118838d472062f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 31 Aug 2016 12:49:10 +0300 Subject: [PATCH 241/284] Fix INO to CPP converting when 2-tokens type is used --- platformio/__init__.py | 2 +- platformio/builder/tools/piomisc.py | 4 ++-- tests/conftest.py | 1 - tests/ino2cpp/multifiles/bar.ino | 5 +++-- tests/ino2cpp/multifiles/foo.pde | 4 ++-- tests/test_examples.py | 11 +++++++---- 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 723890c0..7c94ebc9 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0b2") +VERSION = (3, 0, "0b3") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 33d9b2cb..75f748a5 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -31,8 +31,8 @@ from platformio import util class InoToCPPConverter(object): PROTOTYPE_RE = re.compile(r"""^( - ([a-z_\d]+\*?){1,2} # return type - (\s+[a-z_\d]+\s*) # name of prototype + ([a-z_\d]+\*?\s+){1,2} # return type + ([a-z_\d]+\s*) # name of prototype \([a-z_,\.\*\&\[\]\s\d]*\) # arguments )\s*\{ # must end with { """, re.X | re.M | re.I) diff --git a/tests/conftest.py b/tests/conftest.py index 9af9b6f7..46670a44 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -32,7 +32,6 @@ def validate_cliresult(): def decorator(result): assert result.exit_code == 0 assert not result.exception - assert "error" not in result.output.lower() return decorator diff --git a/tests/ino2cpp/multifiles/bar.ino b/tests/ino2cpp/multifiles/bar.ino index 5eac56d9..6040586a 100644 --- a/tests/ino2cpp/multifiles/bar.ino +++ b/tests/ino2cpp/multifiles/bar.ino @@ -1,3 +1,4 @@ -void barFunc () { // my comment - +unsigned int barFunc () // my comment +{ + return 0; } \ No newline at end of file diff --git a/tests/ino2cpp/multifiles/foo.pde b/tests/ino2cpp/multifiles/foo.pde index 785166cd..9b2913cb 100644 --- a/tests/ino2cpp/multifiles/foo.pde +++ b/tests/ino2cpp/multifiles/foo.pde @@ -9,5 +9,5 @@ void loop() { } char* fooFunc() { - return buf; -} \ No newline at end of file + return buf; +} diff --git a/tests/test_examples.py b/tests/test_examples.py index 75278d9c..42ff2b5e 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -19,7 +19,6 @@ from os.path import dirname, getsize, isdir, isfile, join, normpath import pytest from platformio import util -from platformio.commands.run import cli as cmd_run def pytest_generate_tests(metafunc): @@ -35,12 +34,16 @@ def pytest_generate_tests(metafunc): metafunc.parametrize("pioproject_dir", project_dirs) -def test_run(clirunner, validate_cliresult, pioproject_dir): +@pytest.mark.examples +def test_run(pioproject_dir): if isdir(join(pioproject_dir, ".pioenvs")): util.rmtree_(join(pioproject_dir, ".pioenvs")) - result = clirunner.invoke(cmd_run, ["-d", pioproject_dir]) - validate_cliresult(result) + result = util.exec_command( + ["platformio", "--force", "run", "--project-dir", pioproject_dir] + ) + if result['returncode'] != 0: + pytest.fail(result) # check .elf file pioenvs_dir = join(pioproject_dir, ".pioenvs") From c3004c6a6cd22249ef1c593b9a61d6019a15fce7 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 31 Aug 2016 13:15:40 +0300 Subject: [PATCH 242/284] Disable HG testing --- tests/commands/{test__lib.py => test_lib.py} | 21 +++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) rename tests/commands/{test__lib.py => test_lib.py} (89%) diff --git a/tests/commands/test__lib.py b/tests/commands/test_lib.py similarity index 89% rename from tests/commands/test__lib.py rename to tests/commands/test_lib.py index 1aafde58..af9d60da 100644 --- a/tests/commands/test__lib.py +++ b/tests/commands/test_lib.py @@ -48,13 +48,16 @@ def test_global_install_registry(clirunner, validate_cliresult, def test_global_install_repository(clirunner, validate_cliresult, isolated_pio_home): result = clirunner.invoke( - cmd_lib, ["-g", "install", "https://github.com/gioblu/PJON.git#3.0", - "https://developer.mbed.org/users/simon/code/TextLCD/", - "http://dl.platformio.org/libraries/archives/3/3756.tar.gz", - "knolleary/pubsubclient"]) + cmd_lib, + ["-g", + "install", + "https://github.com/gioblu/PJON.git#3.0", + # "https://developer.mbed.org/users/simon/code/TextLCD/", + "http://dl.platformio.org/libraries/archives/3/3756.tar.gz", + "knolleary/pubsubclient"]) validate_cliresult(result) items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] - items2 = ["PJON", "TextLCD", "ESPAsyncTCP", "PubSubClient"] + items2 = ["PJON", "ESPAsyncTCP", "PubSubClient"] assert set(items2) & set(items1) @@ -66,11 +69,10 @@ def test_global_lib_list(clirunner, validate_cliresult, isolated_pio_home): result = clirunner.invoke(cmd_lib, ["-g", "list", "--json-output"]) assert all( [n in result.output - for n in ("PJON", - "https://developer.mbed.org/users/simon/code/TextLCD/")]) + for n in ("PJON", "git+https://github.com/knolleary/pubsubclient")]) items1 = [i['name'] for i in json.loads(result.output)] items2 = ["OneWire", "DHT22", "PJON", "ESPAsyncTCP", "Json", "ArduinoJson", - "TextLCD", "pubsubclient"] + "pubsubclient"] assert set(items1) == set(items2) @@ -82,7 +84,8 @@ def test_global_lib_show(clirunner, validate_cliresult, isolated_pio_home): result = clirunner.invoke(cmd_lib, ["-g", "show", "ArduinoJson@>5.4.0"]) validate_cliresult(result) - assert all([s in result.output for s in ("ArduinoJson", "arduino", "atmelavr")]) + assert all( + [s in result.output for s in ("ArduinoJson", "arduino", "atmelavr")]) assert "5.4.0" not in result.output result = clirunner.invoke(cmd_lib, ["-g", "show", "1"]) From 86794d2cf1b48c79e3d5d330157a734e430b46a5 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 31 Aug 2016 14:13:09 +0300 Subject: [PATCH 243/284] Don't check program path --- platformio/commands/test.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/platformio/commands/test.py b/platformio/commands/test.py index db35db45..6820fa31 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -16,7 +16,7 @@ from fnmatch import fnmatch from os import getcwd, listdir -from os.path import isdir, isfile, join +from os.path import isdir, join from time import sleep, time import click @@ -173,8 +173,6 @@ class LocalTestProcessor(TestProcessorBase): def run(self): with util.cd(self.options['project_dir']): pioenvs_dir = util.get_projectpioenvs_dir() - program_path = join(pioenvs_dir, self.env_name, "program") - assert isfile(program_path) result = util.exec_command( [join(pioenvs_dir, self.env_name, "program")], stdout=util.AsyncPipe(self.on_run_out), From 3be35f998792d57579977e91eb08a9e3954544cd Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 31 Aug 2016 16:07:35 +0300 Subject: [PATCH 244/284] Introduce PlatformIO Plus --- platformio/builder/tools/piotest.py | 113 +------------- platformio/commands/test.py | 233 +--------------------------- platformio/commands/update.py | 2 + platformio/maintenance.py | 4 + platformio/pioplus.py | 53 +++++++ tests/commands/test_test.py | 2 +- tox.ini | 9 +- 7 files changed, 73 insertions(+), 343 deletions(-) create mode 100644 platformio/pioplus.py diff --git a/platformio/builder/tools/piotest.py b/platformio/builder/tools/piotest.py index 4ed542ae..e79584a3 100644 --- a/platformio/builder/tools/piotest.py +++ b/platformio/builder/tools/piotest.py @@ -14,46 +14,7 @@ from __future__ import absolute_import -import atexit -import sys -from os import remove -from os.path import isdir, isfile, join, sep -from string import Template - -FRAMEWORK_PARAMETERS = { - "arduino": { - "framework": "Arduino.h", - "serial_obj": "", - "serial_putc": "Serial.write(a)", - "serial_flush": "Serial.flush()", - "serial_begin": "Serial.begin(9600)", - "serial_end": "Serial.end()" - }, - "mbed": { - "framework": "mbed.h", - "serial_obj": "Serial pc(USBTX, USBRX);", - "serial_putc": "pc.putc(a)", - "serial_flush": "", - "serial_begin": "pc.baud(9600)", - "serial_end": "" - }, - "energia": { - "framework": "Energia.h", - "serial_obj": "", - "serial_putc": "Serial.write(a)", - "serial_flush": "Serial.flush()", - "serial_begin": "Serial.begin(9600)", - "serial_end": "Serial.end()" - }, - "native": { - "framework": "stdio.h", - "serial_obj": "", - "serial_putc": "putchar(a)", - "serial_flush": "fflush(stdout)", - "serial_begin": "", - "serial_end": "" - } -} +from os.path import join, sep def ProcessTest(env): @@ -69,79 +30,16 @@ def ProcessTest(env): env.PioPlatform().get_package_dir("tool-unity")) env.Prepend(LIBS=[unitylib]) - test_dir = env.subst("$PROJECTTEST_DIR") - env.GenerateOutputReplacement(test_dir) src_filter = None if "PIOTEST" in env: src_filter = "+" src_filter += " +<%s%s>" % (env['PIOTEST'], sep) return env.CollectBuildFiles( - "$BUILDTEST_DIR", test_dir, src_filter=src_filter, duplicate=False) - - -def GenerateOutputReplacement(env, destination_dir): - - if not isdir(env.subst(destination_dir)): - sys.stderr.write( - "Error: Test folder does not exist. Please put your test suite " - "to \"test\" folder in project's root directory.\n") - env.Exit(1) - - TEMPLATECPP = """ -# include <$framework> -# include - -$serial_obj - -void output_char(int a) -{ - $serial_putc; -} - -void output_flush(void) -{ - $serial_flush; -} - -void output_start(unsigned int baudrate) -{ - $serial_begin; -} - -void output_complete(void) -{ - $serial_end; -} - -""" - - def delete_tmptest_file(file_): - try: - remove(file_) - except: # pylint: disable=bare-except - if isfile(file_): - print("Warning: Could not remove temporary file '%s'. " - "Please remove it manually." % file_) - - if env['PIOPLATFORM'] == "native": - framework = "native" - else: - framework = env.subst("$PIOFRAMEWORK").lower() - if framework not in FRAMEWORK_PARAMETERS: - sys.stderr.write( - "Error: %s framework doesn't support testing feature!\n" % - framework) - env.Exit(1) - else: - data = Template(TEMPLATECPP).substitute(FRAMEWORK_PARAMETERS[ - framework]) - - tmp_file = join(destination_dir, "output_export.cpp") - with open(tmp_file, "w") as f: - f.write(data) - - atexit.register(delete_tmptest_file, tmp_file) + "$BUILDTEST_DIR", + "$PROJECTTEST_DIR", + src_filter=src_filter, + duplicate=False) def exists(_): @@ -150,5 +48,4 @@ def exists(_): def generate(env): env.AddMethod(ProcessTest) - env.AddMethod(GenerateOutputReplacement) return env diff --git a/platformio/commands/test.py b/platformio/commands/test.py index 6820fa31..420c7082 100644 --- a/platformio/commands/test.py +++ b/platformio/commands/test.py @@ -12,20 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=R0913,R0914 - -from fnmatch import fnmatch -from os import getcwd, listdir -from os.path import isdir, join -from time import sleep, time +import sys +from os import getcwd import click -import serial -from platformio import exception, util -from platformio.commands.run import cli as cmd_run -from platformio.commands.run import check_project_envs, print_header -from platformio.managers.platform import PlatformFactory +from platformio.pioplus import pioplus_call @click.command("test", short_help="Unit Testing") @@ -43,220 +35,5 @@ from platformio.managers.platform import PlatformFactory writable=True, resolve_path=True)) @click.option("--verbose", "-v", is_flag=True) -@click.pass_context -def cli(ctx, environment, ignore, upload_port, project_dir, verbose): - with util.cd(project_dir): - test_dir = util.get_projecttest_dir() - if not isdir(test_dir): - raise exception.TestDirEmpty(test_dir) - test_names = get_test_names(test_dir) - projectconf = util.load_project_config() - assert check_project_envs(projectconf, environment) - - click.echo("Verbose mode can be enabled via `-v, --verbose` option") - click.echo("Collected %d items" % len(test_names)) - - start_time = time() - results = [] - for testname in test_names: - for section in projectconf.sections(): - if not section.startswith("env:"): - continue - - envname = section[4:] - if environment and envname not in environment: - continue - - # check ignore patterns - _ignore = list(ignore) - if projectconf.has_option(section, "test_ignore"): - _ignore.extend([ - p.strip() - for p in projectconf.get(section, "test_ignore").split(",") - if p.strip() - ]) - if testname != "*" and \ - any([fnmatch(testname, p) for p in _ignore]): - results.append((None, testname, envname)) - continue - - cls = (LocalTestProcessor - if projectconf.get(section, "platform") == "native" else - EmbeddedTestProcessor) - tp = cls(ctx, testname, envname, { - "project_config": projectconf, - "project_dir": project_dir, - "upload_port": upload_port, - "verbose": verbose - }) - results.append((tp.process(), testname, envname)) - - click.echo() - print_header("[%s]" % click.style("TEST SUMMARY")) - - passed = True - for result in results: - status, testname, envname = result - status_str = click.style("PASSED", fg="green") - if status is False: - passed = False - status_str = click.style("FAILED", fg="red") - elif status is None: - status_str = click.style("IGNORED", fg="yellow") - - click.echo( - "test:%s/env:%s\t[%s]" % (click.style( - testname, fg="yellow"), click.style( - envname, fg="cyan"), status_str), - err=status is False) - - print_header( - "[%s] Took %.2f seconds" % ((click.style( - "PASSED", fg="green", bold=True) if passed else click.style( - "FAILED", fg="red", bold=True)), time() - start_time), - is_error=not passed) - - if not passed: - raise exception.ReturnErrorCode() - - -class TestProcessorBase(object): - - def __init__(self, cmd_ctx, testname, envname, options): - self.cmd_ctx = cmd_ctx - self.cmd_ctx.meta['piotest_processor'] = True - self.test_name = testname - self.env_name = envname - self.options = options - self._run_failed = False - - def print_progress(self, text, is_error=False): - click.echo() - print_header( - "[test::%s] %s" % (click.style( - self.test_name, fg="yellow", bold=True), text), - is_error=is_error) - - def build_or_upload(self, target): - if self.test_name != "*": - self.cmd_ctx.meta['piotest'] = self.test_name - 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], - target=target) - - def run(self): - raise NotImplementedError - - def on_run_out(self, line): - 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) - - -class LocalTestProcessor(TestProcessorBase): - - def process(self): - self.print_progress("Building... (1/2)") - self.build_or_upload(["test"]) - self.print_progress("Testing... (2/2)") - return self.run() - - def run(self): - with util.cd(self.options['project_dir']): - pioenvs_dir = util.get_projectpioenvs_dir() - result = util.exec_command( - [join(pioenvs_dir, self.env_name, "program")], - stdout=util.AsyncPipe(self.on_run_out), - stderr=util.AsyncPipe(self.on_run_out)) - assert "returncode" in result - return result['returncode'] == 0 and not self._run_failed - - -class EmbeddedTestProcessor(TestProcessorBase): - - SERIAL_TIMEOUT = 600 - SERIAL_BAUDRATE = 9600 - - def process(self): - self.print_progress("Building... (1/3)") - self.build_or_upload(["test"]) - self.print_progress("Uploading... (2/3)") - self.build_or_upload(["test", "upload"]) - self.print_progress("Testing... (3/3)") - sleep(1.0) # wait while board is starting... - 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() - ser = serial.Serial( - self.get_serial_port(), - self.SERIAL_BAUDRATE, - timeout=self.SERIAL_TIMEOUT) - while True: - line = ser.readline().strip() - - # fix non-ascii output from device - for i, c in enumerate(line[::-1]): - if ord(c) > 127: - line = line[-i:] - break - - if not line: - continue - 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_serial_port(self): - config = self.options['project_config'] - envdata = {} - for k, v in config.items("env:" + self.env_name): - envdata[k] = v - - # if upload port is specified manually - if self.options.get("upload_port", envdata.get("upload_port")): - return self.options.get("upload_port", envdata.get("upload_port")) - - p = PlatformFactory.newPlatform(envdata['platform']) - bconfig = p.board_config(envdata['board']) - - port = None - board_hwids = [] - if "build.hwids" in bconfig: - board_hwids = bconfig.get("build.hwids") - for item in util.get_serialports(): - if "VID:PID" not in item['hwid']: - continue - 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 - if not port: - raise exception.PlatformioException( - "Please specify `upload_port` for environment or use " - "global `--upload-port` option.") - return port - - -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 cli(*args, **kwargs): # pylint: disable=unused-argument + pioplus_call(sys.argv[1:]) diff --git a/platformio/commands/update.py b/platformio/commands/update.py index 422ac3d9..2d32ef48 100644 --- a/platformio/commands/update.py +++ b/platformio/commands/update.py @@ -17,6 +17,7 @@ import click 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.lib import LibraryManager +from platformio.pioplus import pioplus_update @click.command( @@ -31,6 +32,7 @@ def cli(ctx, only_check): click.echo("Platform Manager") click.echo("================") ctx.invoke(cmd_platform_update, only_check=only_check) + pioplus_update() click.echo() click.echo("Library Manager") diff --git a/platformio/maintenance.py b/platformio/maintenance.py index 0095beaa..2d2605c4 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -29,6 +29,7 @@ from platformio.commands.platform import platform_update as cmd_platform_update from platformio.commands.upgrade import get_latest_version from platformio.managers.lib import LibraryManager from platformio.managers.platform import PlatformManager +from platformio.pioplus import pioplus_update def in_silence(ctx): @@ -140,6 +141,9 @@ def after_upgrade(ctx): # pm.update(manifest['name'], "^" + manifest['version']) pm.update(manifest['name']) + # update PlatformIO Plus tool if installed + pioplus_update() + click.secho( "PlatformIO has been successfully upgraded to %s!\n" % __version__, diff --git a/platformio/pioplus.py b/platformio/pioplus.py new file mode 100644 index 00000000..aae5c646 --- /dev/null +++ b/platformio/pioplus.py @@ -0,0 +1,53 @@ +# Copyright 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import subprocess +from os.path import join + +from platformio import util +from platformio.managers.package import PackageManager + +PACKAGE_PIOPLUS_NAME = "tool-pioplus" + + +class PioPlusPackageManager(PackageManager): + + def __init__(self): + PackageManager.__init__( + self, join(util.get_home_dir(), "packages"), + ["https://dl.bintray.com/platformio/dl-packages/manifest.json", + "https://dl.platformio.org/packages/manifest.json"]) + + +def get_pioplusexe_path(): + pm = PioPlusPackageManager() + package_dir = pm.get_package_dir(PACKAGE_PIOPLUS_NAME) + if not package_dir: + pm.install(PACKAGE_PIOPLUS_NAME) + package_dir = pm.get_package_dir(PACKAGE_PIOPLUS_NAME) + assert package_dir + return join(package_dir, "pioplus") + + +def pioplus_update(): + pm = PioPlusPackageManager() + if pm.get_package_dir(PACKAGE_PIOPLUS_NAME): + pm.update(PACKAGE_PIOPLUS_NAME) + + +def pioplus_call(args, **kwargs): + os.environ['PYTHONEXEPATH'] = util.get_pythonexe_path() + util.copy_pythonpath_to_osenv() + subprocess.call([get_pioplusexe_path()] + args, **kwargs) diff --git a/tests/commands/test_test.py b/tests/commands/test_test.py index 482f20f4..1ecaac39 100644 --- a/tests/commands/test_test.py +++ b/tests/commands/test_test.py @@ -21,6 +21,6 @@ def test_local_env(clirunner, validate_cliresult): result = clirunner.invoke( cli_test, ["-d", join("examples", "unit-testing", "calculator"), "-e", "local"]) - result.exit_code == -1 + validate_cliresult(result) assert all( [s in result.output for s in ("[PASSED]", "[IGNORED]", "[FAILED]")]) diff --git a/tox.ini b/tox.ini index d2fffe23..13c4e891 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,7 @@ # limitations under the License. [tox] -envlist = py26, py27, docs, lint +envlist = py27, docs, lint [testenv:develop] basepython = python2.7 @@ -53,10 +53,7 @@ commands = pylint --rcfile=./.pylintrc ./platformio [testenv] -basepython = - py26: python2.6 - py27: python2.7 -usedevelop = True +basepython = python2.7 passenv = * deps = pytest @@ -65,8 +62,8 @@ commands = py.test -v --basetemp="{envtmpdir}" tests [testenv:coverage] -passenv = * basepython = python2.7 +passenv = * deps = pytest pytest-cov From 013c675bc4ee89b1a436c54b16444c6b97ff8803 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 31 Aug 2016 18:52:27 +0300 Subject: [PATCH 245/284] Allow to control library dependency finder mode from library.json; set ldf_mode to 1 by default --- docs/librarymanager/config.rst | 7 +++++ docs/librarymanager/ldf.rst | 8 +++--- docs/projectconf.rst | 9 ++---- platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 46 ++++++++++++++++++++++++------ 5 files changed, 51 insertions(+), 21 deletions(-) diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index 3f96814a..67a5e6bb 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -533,6 +533,13 @@ More details :ref:`projectconf_extra_script`. Archive object files to Static Library. This is default behavior of PlatformIO Build System (``"libArchive": true``). +``libLDFMode`` +~~~~~~~~~~~~~~ + +*Optional* | Type: ``Integer`` + +Specify Library Dependency Finder Mode. See :ref:`ldf_mode` for details. + **Examples** 1. Custom macros/defines diff --git a/docs/librarymanager/ldf.rst b/docs/librarymanager/ldf.rst index bd5889ff..269b1e6a 100644 --- a/docs/librarymanager/ldf.rst +++ b/docs/librarymanager/ldf.rst @@ -65,10 +65,10 @@ project (:ref:`projectconf_pio_src_dir`) and can work in the next modes: * ``0`` - "manual mode", does not process source files of a project and dependencies. Builds only the libraries that are specified in manifests (:ref:`library_config`, ``module.json``) or in the :ref:`projectconf`. -* ``1`` - parses ALL C/C++ source code of the project and follows only by - nested includes/chain (``#include ...``) from the libraries. -* ``2`` - **default** - parses ALL C/C++ source code of the project and parses - ALL C/C++ source code of the each dependency (recursively). +* ``1`` - **default** - parses ALL C/C++ source code of the project and follows + only by nested includes (``#include ...``, chain...) from the libraries. +* ``2`` - parses ALL C/C++ source code of the project and parses + ALL C/C++ source code of the each found dependency (recursively). This mode can be changed using :ref:`projectconf_lib_ldf_mode` option in :ref:`projectconf`. diff --git a/docs/projectconf.rst b/docs/projectconf.rst index dd2c2c0a..357473f2 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -812,13 +812,8 @@ Example: .. seealso:: Please make sure to read :ref:`ldf` guide first. -Library Dependency Finder starts work from analyzing source files of the -project (:ref:`projectconf_pio_src_dir`) and can work in the different modes -(see :ref:`ldf_mode`). - -By default, this value is set to ``lib_ldf_mode = 2`` and means that LDF -will parse ALL C/C++ source code of the project and will parse ALL C/C++ -source code of the each dependent library (recursively). +This option specifies how does Library Dependency Finder should analyze +dependencies (``#include`` directives). See :ref:`ldf_mode` for details. .. _projectconf_lib_compat_mode: diff --git a/platformio/__init__.py b/platformio/__init__.py index 7c94ebc9..d6a8a6dc 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0b3") +VERSION = (3, 0, "0b4") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 47f0351c..74748609 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -34,9 +34,7 @@ class LibBuilderFactory(object): @staticmethod def new(env, path): clsname = "UnknownLibBuilder" - if isfile(join(path, "library.properties")): - clsname = "ArduinoLibBuilder" - elif isfile(join(path, "library.json")): + if isfile(join(path, "library.json")): clsname = "PlatformIOLibBuilder" else: env_frameworks = [ @@ -76,8 +74,10 @@ class LibBuilderFactory(object): return ["mbed"] return [] +# pylint: disable=too-many-instance-attributes, too-many-public-methods -class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes + +class LibBuilderBase(object): INC_SCANNER = SCons.Scanner.C.CScanner() @@ -153,6 +153,10 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes def lib_archive(self): return True + @property + def lib_ldf_mode(self): + return int(self.env.get("LIB_LDF_MODE", 1)) + @property def depbuilders(self): return self._depbuilders @@ -210,7 +214,7 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes if not search_paths: search_paths = tuple() assert isinstance(search_paths, tuple) - deep_search = int(self.env.get("LIB_LDF_MODE", 2)) == 2 + deep_search = self.lib_ldf_mode == 2 if not self._scanned_paths and ( isinstance(self, ProjectAsLibBuilder) or deep_search): @@ -265,8 +269,7 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes self._process_dependencies(lib_builders) # when LDF is disabled - if "LIB_LDF_MODE" in self.env and \ - int(self.env.get("LIB_LDF_MODE")) == 0: + if self.lib_ldf_mode == 0: return lib_inc_map = {} @@ -346,9 +349,10 @@ class ArduinoLibBuilder(LibBuilderBase): def get_inc_dirs(self): inc_dirs = LibBuilderBase.get_inc_dirs(self) - if not isdir(join(self.path, "utility")): + if isdir(join(self.path, "src")): return inc_dirs - inc_dirs.append(join(self.path, "utility")) + if isdir(join(self.path, "utility")): + inc_dirs.append(join(self.path, "utility")) return inc_dirs @property @@ -391,6 +395,12 @@ class MbedLibBuilder(LibBuilderBase): def is_framework_compatible(self, framework): return framework.lower() == "mbed" + @property + def lib_ldf_mode(self): + if "dependencies" in self._manifest: + return 2 + return LibBuilderBase.lib_ldf_mode.fget(self) + class PlatformIOLibBuilder(LibBuilderBase): @@ -400,10 +410,15 @@ class PlatformIOLibBuilder(LibBuilderBase): assert "name" in manifest return manifest + def _is_arduino_manifest(self): + return isfile(join(self.path, "library.properties")) + @property def src_filter(self): if "srcFilter" in self._manifest.get("build", {}): return self._manifest.get("build").get("srcFilter") + elif self._is_arduino_manifest(): + return ArduinoLibBuilder.src_filter.fget(self) return LibBuilderBase.src_filter.fget(self) @property @@ -430,6 +445,12 @@ class PlatformIOLibBuilder(LibBuilderBase): return self._manifest.get("build").get("libArchive") return LibBuilderBase.lib_archive.fget(self) + @property + def lib_ldf_mode(self): + if "libLDFMode" in self._manifest.get("build", {}): + return int(self._manifest.get("build").get("libLDFMode")) + return LibBuilderBase.lib_ldf_mode.fget(self) + def is_platform_compatible(self, platform): items = self._manifest.get("platforms") if not items: @@ -451,6 +472,13 @@ class PlatformIOLibBuilder(LibBuilderBase): def get_inc_dirs(self): inc_dirs = LibBuilderBase.get_inc_dirs(self) + + # backwards compatibility with PlatformIO 2.0 + if ("build" not in self._manifest and self._is_arduino_manifest() and + not isdir(join(self.path, "src")) and + isdir(join(self.path, "utility"))): + inc_dirs.append(join(self.path, "utility")) + for path in self.env['CPPPATH']: if path not in self.envorigin['CPPPATH']: inc_dirs.append(self.env.subst(path)) From 86aa7ad69298f7ea6034d9985c0c908886438abf Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 31 Aug 2016 20:28:26 +0300 Subject: [PATCH 246/284] Temporary enable LDF_MODE=2 before refactoring --- platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index d6a8a6dc..410c33f6 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0b4") +VERSION = (3, 0, "0b5") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 74748609..1e1c2be1 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -155,7 +155,7 @@ class LibBuilderBase(object): @property def lib_ldf_mode(self): - return int(self.env.get("LIB_LDF_MODE", 1)) + return int(self.env.get("LIB_LDF_MODE", 2)) @property def depbuilders(self): From 0e464b011f964e1c29239301a145b0191031fd93 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 1 Sep 2016 00:06:34 +0300 Subject: [PATCH 247/284] Improve Library Dependency Finder in mode=1 --- platformio/__init__.py | 2 +- platformio/builder/tools/piolib.py | 111 +++++++++++++++++------------ 2 files changed, 66 insertions(+), 47 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 410c33f6..adf9961b 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0b5") +VERSION = (3, 0, "0b6") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 1e1c2be1..1439433d 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -80,6 +80,7 @@ class LibBuilderFactory(object): class LibBuilderBase(object): INC_SCANNER = SCons.Scanner.C.CScanner() + INC_DIRS_CACHE = None def __init__(self, env, path, manifest=None): self.env = env.Clone() @@ -87,8 +88,8 @@ class LibBuilderBase(object): self.path = realpath(env.subst(path)) self._manifest = manifest if manifest else self.load_manifest() self._is_dependent = False - self._depbuilders = tuple() - self._scanned_paths = tuple() + self._depbuilders = list() + self._scanned_paths = list() self._built_node = None # process extra options and append to build environment @@ -155,7 +156,7 @@ class LibBuilderBase(object): @property def lib_ldf_mode(self): - return int(self.env.get("LIB_LDF_MODE", 2)) + return int(self.env.get("LIB_LDF_MODE", 1)) @property def depbuilders(self): @@ -174,6 +175,13 @@ class LibBuilderBase(object): def load_manifest(self): return {} + def get_src_files(self): + return [ + join(self.src_dir, item) + for item in self.env.MatchSourceFiles(self.src_dir, + self.src_filter) + ] + def process_extra_options(self): with util.cd(self.path): self.env.ProcessUnFlags(self.build_unflags) @@ -212,44 +220,40 @@ class LibBuilderBase(object): def _validate_search_paths(self, search_paths=None): if not search_paths: - search_paths = tuple() - assert isinstance(search_paths, tuple) - deep_search = self.lib_ldf_mode == 2 + search_paths = [] + assert isinstance(search_paths, list) - if not self._scanned_paths and ( - isinstance(self, ProjectAsLibBuilder) or deep_search): - for item in self.env.MatchSourceFiles(self.src_dir, - self.src_filter): - path = join(self.src_dir, item) - if (path not in self._scanned_paths and - path not in search_paths): - search_paths += (path, ) - - _search_paths = tuple() + _search_paths = [] for path in search_paths: if path not in self._scanned_paths: - _search_paths += (path, ) - self._scanned_paths += (path, ) + _search_paths.append(path) + self._scanned_paths.append(path) return _search_paths def _get_found_includes(self, lib_builders, search_paths=None): - inc_dirs = tuple() - used_inc_dirs = tuple() - for lb in (self, ) + lib_builders: - items = tuple(self.env.Dir(d) for d in lb.get_inc_dirs()) - if lb.dependent: - used_inc_dirs += items - else: - inc_dirs += items - inc_dirs = used_inc_dirs + inc_dirs + # all include directories + if not LibBuilderBase.INC_DIRS_CACHE: + inc_dirs = [] + used_inc_dirs = [] + for lb in lib_builders: + items = [self.env.Dir(d) for d in lb.get_inc_dirs()] + if lb.dependent: + used_inc_dirs.extend(items) + else: + inc_dirs.extend(items) + LibBuilderBase.INC_DIRS_CACHE = used_inc_dirs + inc_dirs - result = tuple() + # append self include directories + inc_dirs = [self.env.Dir(d) for d in self.get_inc_dirs()] + inc_dirs.extend(LibBuilderBase.INC_DIRS_CACHE) + + result = [] for path in self._validate_search_paths(search_paths): for inc in self.env.File(path).get_found_includes( - self.env, LibBuilderBase.INC_SCANNER, inc_dirs): + self.env, LibBuilderBase.INC_SCANNER, tuple(inc_dirs)): if inc not in result: - result += (inc, ) + result.append(inc) return result def depend_recursive(self, lb, lib_builders, search_paths=None): @@ -260,13 +264,17 @@ class LibBuilderBase(object): "between `%s` and `%s`\n" % (self.path, lb.path)) elif lb not in self._depbuilders: - self._depbuilders += (lb, ) + self._depbuilders.append(lb) + LibBuilderBase.INC_DIRS_CACHE = None lb.search_deps_recursive(lib_builders, search_paths) def search_deps_recursive(self, lib_builders, search_paths=None): - self._is_dependent = True + if not self._is_dependent: + self._is_dependent = True + self._process_dependencies(lib_builders) - self._process_dependencies(lib_builders) + if self.lib_ldf_mode == 2: + search_paths = self.get_src_files() # when LDF is disabled if self.lib_ldf_mode == 0: @@ -277,12 +285,12 @@ class LibBuilderBase(object): for lb in lib_builders: if inc.get_abspath() in lb: if lb not in lib_inc_map: - lib_inc_map[lb] = tuple() - lib_inc_map[lb] += (inc.get_abspath(), ) + lib_inc_map[lb] = [] + lib_inc_map[lb].append(inc.get_abspath()) break - for lb, lb_src_files in lib_inc_map.items(): - self.depend_recursive(lb, lib_builders, lb_src_files) + for lb, lb_search_paths in lib_inc_map.items(): + self.depend_recursive(lb, lib_builders, lb_search_paths) def build(self): libs = [] @@ -309,6 +317,10 @@ class UnknownLibBuilder(LibBuilderBase): class ProjectAsLibBuilder(LibBuilderBase): + @property + def lib_ldf_mode(self): + return 2 # parse all project files + @property def src_filter(self): return self.env.get("SRC_FILTER", LibBuilderBase.src_filter.fget(self)) @@ -395,12 +407,6 @@ class MbedLibBuilder(LibBuilderBase): def is_framework_compatible(self, framework): return framework.lower() == "mbed" - @property - def lib_ldf_mode(self): - if "dependencies" in self._manifest: - return 2 - return LibBuilderBase.lib_ldf_mode.fget(self) - class PlatformIOLibBuilder(LibBuilderBase): @@ -486,7 +492,7 @@ class PlatformIOLibBuilder(LibBuilderBase): def GetLibBuilders(env): - items = tuple() + items = [] env_frameworks = [ f.lower().strip() for f in env.get("PIOFRAMEWORK", "").split(",") ] @@ -529,13 +535,13 @@ def GetLibBuilders(env): % join(libs_dir, item)) continue if _check_lib_builder(lb): - items += (lb, ) + items.append(lb) else: found_incompat = True for lb in env.get("EXTRA_LIB_BUILDERS", []): if _check_lib_builder(lb): - items += (lb, ) + items.append(lb) else: found_incompat = True @@ -550,6 +556,16 @@ def GetLibBuilders(env): def BuildDependentLibraries(env, src_dir): + def correct_found_libs(lib_builders): + # build full dependency graph + found_lbs = [lb for lb in lib_builders if lb.dependent] + for lb in lib_builders: + lb.search_deps_recursive(lib_builders, lb.get_src_files()) + for lb in lib_builders: + for deplb in lb.depbuilders[:]: + if deplb not in found_lbs: + lb.depbuilders.remove(deplb) + def print_deps_tree(root, level=0): margin = "| " * (level) for lb in root.depbuilders: @@ -571,6 +587,9 @@ def BuildDependentLibraries(env, src_dir): project.env = env project.search_deps_recursive(lib_builders) + if int(env.get("LIB_LDF_MODE", 1)) == 1 and project.depbuilders: + correct_found_libs(lib_builders) + if project.depbuilders: print "Library Dependency Graph" print_deps_tree(project) From c51ac0489fd9b47be5f53d37991209a6f288563a Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 1 Sep 2016 01:30:14 +0300 Subject: [PATCH 248/284] Use global library storage for CI --- docs/ci/circleci.rst | 4 ++-- docs/ci/travis.rst | 6 +++--- platformio/commands/lib.py | 7 +++++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/docs/ci/circleci.rst b/docs/ci/circleci.rst index d3e09fa9..ebc9c7ac 100644 --- a/docs/ci/circleci.rst +++ b/docs/ci/circleci.rst @@ -83,7 +83,7 @@ Install dependent library using :ref:`librarymanager` - sudo pip install -U platformio # OneWire Library with ID=1 http://platformio.org/lib/show/1/OneWire - - platformio lib install 1 + - platformio lib -g install 1 test: override: @@ -159,7 +159,7 @@ Examples # # http://platformio.org/lib/show/416/TinyGPS # http://platformio.org/lib/show/417/SPI4Teensy3 - - platformio lib install 416 417 + - platformio lib -g install 416 417 test: override: diff --git a/docs/ci/travis.rst b/docs/ci/travis.rst index df48556a..03a08b9d 100644 --- a/docs/ci/travis.rst +++ b/docs/ci/travis.rst @@ -106,7 +106,7 @@ Install dependent library using :ref:`librarymanager` # Libraries from PlatformIO Library Registry: # # http://platformio.org/lib/show/1/OneWire - - platformio lib install 1 + - platformio lib -g install 1 Manually download dependent library and include in build process via ``--lib`` option ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,7 +189,7 @@ Examples # # http://platformio.org/lib/show/416/TinyGPS # http://platformio.org/lib/show/417/SPI4Teensy3 - - platformio lib install 416 417 + - platformio lib -g install 416 417 script: - platformio ci --board=uno --board=teensy31 --board=due --lib="." @@ -260,7 +260,7 @@ Examples # Libraries from PlatformIO Library Registry: # # http://platformio.org/lib/show/416/TinyGPS - - platformio lib install 416 421 422 + - platformio lib -g install 416 421 422 script: - platformio ci --lib="." --board=uno --board=teensy20pp $PLATFORMIO_CI_EXTRA_ARGS diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index 5d67c933..5b72b57d 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -53,6 +53,13 @@ def cli(ctx, **options): 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") + 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(), From 838063b1b7fd0036c47db2f08edbb68bb0271ca7 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 1 Sep 2016 15:14:38 +0300 Subject: [PATCH 249/284] Allow passing custom project configuration options to ``platformio ci`` and ``platformio init`` commands using ``-O, --project-option``. --- HISTORY.rst | 2 ++ docs/userguide/cmd_ci.rst | 30 +++++++++++++++--------------- docs/userguide/cmd_init.rst | 14 +++++--------- platformio/commands/ci.py | 9 ++++++++- platformio/commands/init.py | 14 +++++++------- 5 files changed, 37 insertions(+), 32 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 052b63b2..481b1970 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -70,6 +70,8 @@ PlatformIO 3.0 * Renamed ``platformio serialports`` command to ``platformio device`` * Build System: Attach custom Before/Pre and After/Post actions for targets (`issue #542 `_) +* Allowed passing custom project configuration options to ``platformio ci`` + and ``platformio init`` commands using ``-O, --project-option``. * Print human-readable information when processing environments without ``-v, --verbose`` option (`issue #721 `_) diff --git a/docs/userguide/cmd_ci.rst b/docs/userguide/cmd_ci.rst index 72d647c2..708996e2 100644 --- a/docs/userguide/cmd_ci.rst +++ b/docs/userguide/cmd_ci.rst @@ -49,20 +49,11 @@ Systems please follow to :ref:`ci` page. .. note:: :ref:`cmd_ci` command is useful for library developers. It allows to build different examples without creating own project per them. Also, is possible - to upload firmware to the target device. In this case, need to create - :ref:`projectconf` where specify "upload" :ref:`projectconf_targets`. Custom - upload port can be overridden with :ref:`projectconf_upload_port` option. - Then need to specify the path to this :ref:`projectconf` to - :option:`platformio ci --project-conf`. For example, - - .. code-block:: ini - - [env:uno] - platform = atmelavr - framework = arduino - targets = upload - ; custom upload port - ; upload_port = ... + to upload firmware to the target device. In this case, you need to pass + additional option ``--project-option="targets=upload"``. What is more, + you can specify custom upload port using + ``--project-option="upload_port="`` option. + See :option:`platformio ci --project-option` for details. Options ------- @@ -120,10 +111,19 @@ temporary directory within your operation system. Don't remove :option:`platformio ci --build-dir` after build process. .. option:: - --project-conf + -P, --project-conf Buid project using pre-configured :ref:`projectconf`. +.. option:: + -O, --project-option + +Pass additional options from :ref:`projectconf` to +:option:`platformio init --project-option` command. For example, +automatically install dependent libraries +``platformio ci --project-option="lib_deps=ArduinoJSON"`` or ignore specific +library ``platformio ci --project-option="lib_ignore=SomeLib"``. + .. option:: -v, --verbose diff --git a/docs/userguide/cmd_init.rst b/docs/userguide/cmd_init.rst index eb001fdd..a9dcb194 100644 --- a/docs/userguide/cmd_init.rst +++ b/docs/userguide/cmd_init.rst @@ -65,18 +65,17 @@ The full list with pre-configured boards is available here :ref:`platforms`. .. option:: --ide -Initialise PlatformIO project for the specified IDE which can be imported later +Initialize PlatformIO project for the specified IDE which can be imported later via "Import Project" functionality. A list with supported IDE is available within ``platformio init --help`` command. Also, please take a look at :ref:`ide` page. .. option:: - --enable-auto-uploading + -O, --project-option -If you initialise project with the specified -:option:`platformio init --board`, then *PlatformIO* -will create environment with enabled firmware auto-uploading. +Initialize project with additional options from :ref:`projectconf`. For example, +``platformio init --project-option="lib_deps=ArduinoJSON"``. .. option:: --env-prefix @@ -104,7 +103,6 @@ Examples platformio.ini - Project Configuration File. |-> PLEASE EDIT ME <-| src - Put your source files here lib - Put here project specific (private) libraries - Do you want to continue? [y/N]: y Project has been successfully initialized! Useful commands: `platformio run` - process/build project from the current directory @@ -122,14 +120,13 @@ Examples platformio.ini - Project Configuration File. |-> PLEASE EDIT ME <-| src - Put your source files here lib - Put here project specific (private) libraries - Do you want to continue? [y/N]: y Project has been successfully initialized! Useful commands: `platformio run` - process/build project from the current directory `platformio run --target upload` or `platformio run -t upload` - upload firmware to embedded board `platformio run --target clean` - clean project (remove compiled files) -3. Initialise project for Arduino Uno +3. Initialize project for Arduino Uno .. code-block:: bash @@ -143,7 +140,6 @@ Examples platformio.ini - Project Configuration File. |-> PLEASE EDIT ME <-| src - Put your source files here lib - Put here project specific (private) libraries - Do you want to continue? [y/N]: y Project has been successfully initialized! Useful commands: `platformio run` - process/build project from the current directory diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index 5303932a..cdfc004c 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -68,6 +68,7 @@ def validate_path(ctx, param, value): # pylint: disable=unused-argument resolve_path=True)) @click.option("--keep-build-dir", is_flag=True) @click.option( + "-C", "--project-conf", type=click.Path( exists=True, @@ -75,6 +76,7 @@ def validate_path(ctx, param, value): # pylint: disable=unused-argument 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(ctx, # pylint: disable=R0913 @@ -85,6 +87,7 @@ def cli(ctx, # pylint: disable=R0913 build_dir, keep_build_dir, project_conf, + project_option, verbose): if not src and getenv("PLATFORMIO_CI_SRC"): @@ -113,7 +116,11 @@ def cli(ctx, # pylint: disable=R0913 _exclude_contents(build_dir, exclude) # initialise project - ctx.invoke(cmd_init, project_dir=build_dir, board=board) + 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) diff --git a/platformio/commands/init.py b/platformio/commands/init.py index f04c7088..d7eee985 100644 --- a/platformio/commands/init.py +++ b/platformio/commands/init.py @@ -58,14 +58,14 @@ def validate_boards(ctx, param, value): # pylint: disable=W0613 "-b", "--board", multiple=True, metavar="ID", callback=validate_boards) @click.option( "--ide", type=click.Choice(ProjectGenerator.get_supported_ides())) -@click.option("--enable-auto-uploading", is_flag=True) +@click.option("-O", "--project-option", multiple=True) @click.option("--env-prefix", default="") @click.pass_context def cli(ctx, # pylint: disable=R0913 project_dir, board, ide, - enable_auto_uploading, + project_option, env_prefix): if project_dir == getcwd(): @@ -92,8 +92,8 @@ def cli(ctx, # pylint: disable=R0913 init_base_project(project_dir) if board: - fill_project_envs(ctx, project_dir, board, enable_auto_uploading, - env_prefix, ide is not None) + fill_project_envs(ctx, project_dir, board, project_option, env_prefix, + ide is not None) if ide: if not board: @@ -288,7 +288,7 @@ def init_cvs_ignore(project_dir): def fill_project_envs( # pylint: disable=too-many-arguments,too-many-locals - ctx, project_dir, board_ids, enable_auto_uploading, env_prefix, + ctx, project_dir, board_ids, project_option, env_prefix, force_download): installed_boards = PlatformManager().get_installed_boards() content = [] @@ -327,8 +327,8 @@ def fill_project_envs( # pylint: disable=too-many-arguments,too-many-locals content.append("framework = %s" % frameworks[0]) content.append("board = %s" % id_) - if enable_auto_uploading: - content.append("targets = upload") + if project_option: + content.extend(project_option) if force_download and used_platforms: _install_dependent_platforms(ctx, used_platforms) From ac4c054d1f5588e1a40c70962aa70065ba192fc1 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 1 Sep 2016 16:05:02 +0300 Subject: [PATCH 250/284] Implement retrying mechanism for get results from PlatformIO API --- docs/ci/travis.rst | 4 ++-- platformio/__init__.py | 3 +-- platformio/util.py | 46 +++++++++++++++++++++++-------------- tests/commands/test_init.py | 4 ++-- 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/docs/ci/travis.rst b/docs/ci/travis.rst index 03a08b9d..e4dd6ef5 100644 --- a/docs/ci/travis.rst +++ b/docs/ci/travis.rst @@ -89,8 +89,8 @@ it), please use ``--lib="."`` option for :ref:`cmd_ci` command script: - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N -Library dependecies -~~~~~~~~~~~~~~~~~~~ +Library dependencies +~~~~~~~~~~~~~~~~~~~~ There 2 options to test source code with dependent libraries: diff --git a/platformio/__init__.py b/platformio/__init__.py index adf9961b..5c776f68 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0b6") +VERSION = (3, 0, "0b7") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" @@ -31,7 +31,6 @@ __license__ = "Apache Software License" __copyright__ = "Copyright 2014-present PlatformIO" __apiurl__ = "https://api.platformio.org" -__apiip__ = "198.7.57.247" if sys.version_info < (2, 7, 0) or sys.version_info >= (3, 0, 0): msg = ("PlatformIO version %s does not run under Python version %s.\n" diff --git a/platformio/util.py b/platformio/util.py index 0a55725a..88c5832f 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -26,8 +26,12 @@ from os.path import (abspath, basename, dirname, expanduser, isdir, isfile, from platform import system, uname from shutil import rmtree from threading import Thread +from time import sleep -from platformio import __apiip__, __apiurl__, __version__, exception +import click +import requests + +from platformio import __apiurl__, __version__, exception # pylint: disable=wrong-import-order try: @@ -357,20 +361,19 @@ def get_logicaldisks(): def get_request_defheaders(): - import requests data = (__version__, int(is_ci()), requests.utils.default_user_agent()) return {"User-Agent": "PlatformIO/%s CI/%d %s" % data} @memoized def _api_request_session(): - import requests return requests.Session() -def get_api_result(path, # pylint: disable=too-many-branches - params=None, data=None, skipdns=False): - import requests +def _get_api_result( + path, # pylint: disable=too-many-branches + params=None, + data=None): from platformio.app import get_setting result = None @@ -378,9 +381,6 @@ def get_api_result(path, # pylint: disable=too-many-branches headers = get_request_defheaders() url = __apiurl__ - if skipdns: - url = "https://%s" % __apiip__ - headers['host'] = __apiurl__[__apiurl__.index("://") + 3:] if get_setting("disable_ssl"): url = url.replace("https://", "http://") @@ -400,14 +400,6 @@ def get_api_result(path, # pylint: disable=too-many-branches raise exception.APIRequestError(result['errors'][0]['title']) else: raise exception.APIRequestError(e) - except (requests.exceptions.ConnectionError, - requests.exceptions.ConnectTimeout, - requests.exceptions.ReadTimeout): - if not skipdns: - return get_api_result(path, params, data, skipdns=True) - raise exception.APIRequestError( - "Could not connect to PlatformIO Registry Service. " - "Please try later.") except ValueError: raise exception.APIRequestError("Invalid response: %s" % r.text.encode("utf-8")) @@ -417,6 +409,26 @@ def get_api_result(path, # pylint: disable=too-many-branches return result +def get_api_result(path, params=None, data=None): + max_retries = 5 + total = 0 + while total < max_retries: + try: + return _get_api_result(path, params, data) + except (requests.exceptions.ConnectionError, + requests.exceptions.Timeout) as e: + total += 1 + click.secho( + "[API] ConnectionError: {0} (incremented retry: max={1}, " + "total={2})".format(e, max_retries, total), + fg="yellow") + sleep(2 * total) + + raise exception.APIRequestError( + "Could not connect to PlatformIO Registry Service. " + "Please try later.") + + @memoized def _lookup_frameworks(): frameworks = {} diff --git a/tests/commands/test_init.py b/tests/commands/test_init.py index 6064fd49..5f08c336 100644 --- a/tests/commands/test_init.py +++ b/tests/commands/test_init.py @@ -117,8 +117,8 @@ def test_init_special_board(clirunner, validate_cliresult): def test_init_enable_auto_uploading(clirunner, validate_cliresult): with clirunner.isolated_filesystem(): - result = clirunner.invoke(cmd_init, - ["-b", "uno", "--enable-auto-uploading"]) + result = clirunner.invoke( + cmd_init, ["-b", "uno", "--project-option", "targets=upload"]) validate_cliresult(result) validate_pioproject(getcwd()) config = util.load_project_config() From bb62444f15ff6dabbd7e8f270005460c499e4fcd Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 1 Sep 2016 19:08:32 +0300 Subject: [PATCH 251/284] Handle C multiline strings when converting INO to CPP // Resolve #765 --- HISTORY.rst | 3 +- platformio/__init__.py | 2 +- platformio/builder/tools/piomisc.py | 50 +++++++++++++++--- tests/ino2cpp/strmultilines/main.ino | 79 ++++++++++++++++++++++++++++ tests/test_ino2cpp.py | 4 ++ 5 files changed, 130 insertions(+), 8 deletions(-) create mode 100644 tests/ino2cpp/strmultilines/main.ino diff --git a/HISTORY.rst b/HISTORY.rst index 481b1970..3241cca9 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -76,7 +76,8 @@ PlatformIO 3.0 ``-v, --verbose`` option (`issue #721 `_) * Improved INO to CPP converter - (`issue #659 `_) + (`issue #659 `_, + `issue #765 `_) * Added ``license`` field to `library.json `__ (`issue #522 `_) * Warn about unknown options in project configuration file ``platformio.ini`` diff --git a/platformio/__init__.py b/platformio/__init__.py index 5c776f68..a813278b 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0b7") +VERSION = (3, 0, "0b8") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 75f748a5..1a6d83c9 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -72,6 +72,7 @@ class InoToCPPConverter(object): assert self._gcc_preprocess(contents, out_file) with open(out_file) as fp: contents = fp.read() + contents = self._join_multiline_strings(contents) with open(out_file, "w") as fp: fp.write(self.append_prototypes(contents)) return out_file @@ -89,6 +90,45 @@ class InoToCPPConverter(object): atexit.register(_delete_file, tmp_path) return isfile(out_file) + def _join_multiline_strings(self, contents): + if "\\" not in contents: + return contents + newlines = [] + linenum = 0 + stropen = False + for line in contents.split("\n"): + _linenum = self._parse_preproc_line_num(line) + if _linenum is not None: + linenum = _linenum + continue + else: + linenum += 1 + + if line.endswith("\\"): + if line.startswith('"'): + newlines.append(line[:-1]) + stropen = True + elif stropen: + newlines[len(newlines) - 1] += line[:-1] + elif stropen and line.endswith('";'): + newlines[len(newlines) - 1] += line + stropen = False + newlines.append('#line %d "%s"' % + (linenum, self._main_ino.replace("\\", "/"))) + else: + newlines.append(line) + + return "\n".join(newlines) + + @staticmethod + def _parse_preproc_line_num(line): + if not line.startswith("#"): + return None + tokens = line.split(" ", 3) + if len(tokens) > 2 and tokens[1].isdigit(): + return int(tokens[1]) + return None + def _parse_prototypes(self, contents): prototypes = [] reserved_keywords = set(["if", "else", "while"]) @@ -99,14 +139,12 @@ class InoToCPPConverter(object): prototypes.append(match) return prototypes - @staticmethod - def _get_total_lines(contents): + def _get_total_lines(self, contents): total = 0 for line in contents.split("\n")[::-1]: - if line.startswith("#"): - tokens = line.split(" ", 3) - if len(tokens) > 2 and tokens[1].isdigit(): - return int(tokens[1]) + total + linenum = self._parse_preproc_line_num(line) + if linenum is not None: + return total + linenum total += 1 return total diff --git a/tests/ino2cpp/strmultilines/main.ino b/tests/ino2cpp/strmultilines/main.ino new file mode 100644 index 00000000..c5df8f30 --- /dev/null +++ b/tests/ino2cpp/strmultilines/main.ino @@ -0,0 +1,79 @@ +const char headerEndP[] PROGMEM = +"\ +\ +\ +"; + +void setup() { + +} + +const char javaScriptPinControlP[] PROGMEM = +"
\ +
\ +"; + +#warning "Line 75" + +void loop() { + +} \ No newline at end of file diff --git a/tests/test_ino2cpp.py b/tests/test_ino2cpp.py index 0bb6b143..d4008628 100644 --- a/tests/test_ino2cpp.py +++ b/tests/test_ino2cpp.py @@ -42,3 +42,7 @@ def test_warning_line(clirunner, validate_cliresult): validate_cliresult(result) assert ('basic.ino:13:14: warning: #warning "Line number is 13"' in result.output) + result = clirunner.invoke( + cmd_ci, [join(INOTEST_DIR, "strmultilines"), "-b", "uno"]) + validate_cliresult(result) + assert ('main.ino:75:2: warning: #warning "Line 75"' in result.output) From b6269188fe809d80f22bad5141b0945cc81e2cc7 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 1 Sep 2016 20:02:12 +0300 Subject: [PATCH 252/284] Fix indention --- HISTORY.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index 3241cca9..0f41ac40 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -77,7 +77,7 @@ PlatformIO 3.0 (`issue #721 `_) * Improved INO to CPP converter (`issue #659 `_, - `issue #765 `_) + `issue #765 `_) * Added ``license`` field to `library.json `__ (`issue #522 `_) * Warn about unknown options in project configuration file ``platformio.ini`` From 85439dbff77a1c36f8dd8f7d2d787999b0913b25 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 1 Sep 2016 21:34:37 +0300 Subject: [PATCH 253/284] Allow to use dependencies separated with comma + space --- docs/projectconf.rst | 18 +++++++++++------- platformio/commands/run.py | 6 ++++-- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 357473f2..df09decb 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -194,7 +194,7 @@ if :option:`platformio run --environment` option is not specified. :ref:`projectconf_pio_env_default` allows to define environments which should be processed by default. -Multiple environments are allowed if they are separated with ``,`` (comma). +Multiple environments are allowed if they are separated with ``, `` (comma+space). For example. .. code-block:: ini @@ -286,7 +286,7 @@ Examples: :ref:`frameworks` name. -The multiple frameworks are allowed, split them with comma ``,`` separator. +The multiple frameworks are allowed, split them with comma+space ``, ``. .. _projectconf_env_board: @@ -701,13 +701,17 @@ Library options Specify project dependencies that should be installed automatically to :ref:`projectconf_pio_libdeps_dir` before environment processing. -Multiple dependencies are allowed (multi-lines). +Multiple dependencies are allowed (multi-lines or separated with comma+space +``, ``). **Valid forms** .. code-block:: ini [env:myenv] + lib_deps = LIBRARY_1, LIBRARY_2, LIBRARY_N + + [env:myenv2] lib_deps = LIBRARY_1 LIBRARY_2 @@ -744,7 +748,7 @@ processed in the first order. The correct value for this option is library name (not folder name). In the most cases, library name is pre-defined in manifest file (:ref:`library_config`, ``library.properties``, ``module.json``). The multiple -library names are allowed, split them with comma ``,`` separator. +library names are allowed, split them with comma+space ``, ``. Example: @@ -766,7 +770,7 @@ Specify libraries which should be ignored by Library Dependency Finder. The correct value for this option is library name (not folder name). In the most cases, library name is pre-defined in manifest file (:ref:`library_config`, ``library.properties``, ``module.json``). The multiple -library names are allowed, split them with comma ``,`` separator. +library names are allowed, split them with comma+space ``, ``. Example: @@ -786,7 +790,7 @@ Example: A list with extra directories/storages where Library Dependency Finder will look for dependencies. Multiple paths are allowed. Please separate them -using comma ``,`` symbol. +using comma+space ``, ``. This option can be set by global environment variable :envvar:`PLATFORMIO_LIB_EXTRA_DIRS`. @@ -847,7 +851,7 @@ Test options Please make sure to read :ref:`unit_testing` guide first. Ignore tests where the name matches specified patterns. Multiple names are -allowed. Please separate them using comma ``,`` symbol. Also, you can +allowed. Please separate them using comma+space ``, ``. Also, you can ignore some tests using :option:`platformio test --ignore` command. .. list-table:: diff --git a/platformio/commands/run.py b/platformio/commands/run.py index ffa837f7..2bac6643 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -153,7 +153,7 @@ class EnvironmentProcessor(object): process_opts = [] for k, v in self.options.items(): if "\n" in v: - process_opts.append((k, "; ".join( + process_opts.append((k, ", ".join( [s.strip() for s in v.split("\n") if s.strip()]))) else: process_opts.append((k, v)) @@ -237,7 +237,9 @@ class EnvironmentProcessor(object): ], self.verbose) if "lib_deps" in self.options: _autoinstall_libdeps(self.cmd_ctx, [ - d.strip() for d in self.options['lib_deps'].split("\n") + d.strip() + for d in self.options['lib_deps'].split( + "\n" if "\n" in self.options['lib_deps'] else ", ") if d.strip() ], self.verbose) From 6b63ae2e46eb1a8a4d55fa7bf586a140ddb54adb Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 1 Sep 2016 21:56:43 +0300 Subject: [PATCH 254/284] Ignore warning when can't delete temporary file --- platformio/builder/tools/piomisc.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 1a6d83c9..94bf6e81 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -81,7 +81,6 @@ class InoToCPPConverter(object): tmp_path = mkstemp()[1] with open(tmp_path, "w") as fp: fp.write(contents) - fp.close() self.env.Execute( self.env.VerboseAction( '$CXX -o "{0}" -x c++ -fpreprocessed -dD -E "{1}"'.format( @@ -185,9 +184,7 @@ def _delete_file(path): if isfile(path): remove(path) except: # pylint: disable=bare-except - if path and isfile(path): - sys.stderr.write("Warning: Could not remove temporary file '%s'. " - "Please remove it manually.\n" % path) + pass def DumpIDEData(env): From b8af2acce5e7b115812d1e9199f1599da6e09c74 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 1 Sep 2016 23:19:46 +0300 Subject: [PATCH 255/284] Fix issue with converting INO to CPP and missing line number --- docs/projectconf.rst | 4 ++-- platformio/builder/tools/piomisc.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/projectconf.rst b/docs/projectconf.rst index df09decb..82ad8443 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -194,8 +194,8 @@ if :option:`platformio run --environment` option is not specified. :ref:`projectconf_pio_env_default` allows to define environments which should be processed by default. -Multiple environments are allowed if they are separated with ``, `` (comma+space). -For example. +Multiple environments are allowed if they are separated with ``, `` +(comma+space). For example. .. code-block:: ini diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 94bf6e81..00d9e386 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -90,7 +90,7 @@ class InoToCPPConverter(object): return isfile(out_file) def _join_multiline_strings(self, contents): - if "\\" not in contents: + if "\\\n" not in contents: return contents newlines = [] linenum = 0 @@ -99,7 +99,6 @@ class InoToCPPConverter(object): _linenum = self._parse_preproc_line_num(line) if _linenum is not None: linenum = _linenum - continue else: linenum += 1 From bbe6550abe77bf34673effa05274fe42c90e0f0d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 2 Sep 2016 00:22:12 +0300 Subject: [PATCH 256/284] Fix Sphinx warnings --- docs/projectconf.rst | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 82ad8443..30f82968 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -194,7 +194,7 @@ if :option:`platformio run --environment` option is not specified. :ref:`projectconf_pio_env_default` allows to define environments which should be processed by default. -Multiple environments are allowed if they are separated with ``, `` +Multiple environments are allowed if they are separated with ", " (comma+space). For example. .. code-block:: ini @@ -286,7 +286,7 @@ Examples: :ref:`frameworks` name. -The multiple frameworks are allowed, split them with comma+space ``, ``. +The multiple frameworks are allowed, split them with comma+space ", ". .. _projectconf_env_board: @@ -701,8 +701,7 @@ Library options Specify project dependencies that should be installed automatically to :ref:`projectconf_pio_libdeps_dir` before environment processing. -Multiple dependencies are allowed (multi-lines or separated with comma+space -``, ``). +Multiple dependencies are allowed (multi-lines or separated with comma+space ", "). **Valid forms** @@ -748,7 +747,7 @@ processed in the first order. The correct value for this option is library name (not folder name). In the most cases, library name is pre-defined in manifest file (:ref:`library_config`, ``library.properties``, ``module.json``). The multiple -library names are allowed, split them with comma+space ``, ``. +library names are allowed, split them with comma+space ", ". Example: @@ -770,7 +769,7 @@ Specify libraries which should be ignored by Library Dependency Finder. The correct value for this option is library name (not folder name). In the most cases, library name is pre-defined in manifest file (:ref:`library_config`, ``library.properties``, ``module.json``). The multiple -library names are allowed, split them with comma+space ``, ``. +library names are allowed, split them with comma+space ", ". Example: @@ -790,7 +789,7 @@ Example: A list with extra directories/storages where Library Dependency Finder will look for dependencies. Multiple paths are allowed. Please separate them -using comma+space ``, ``. +using comma+space ", ". This option can be set by global environment variable :envvar:`PLATFORMIO_LIB_EXTRA_DIRS`. @@ -851,7 +850,7 @@ Test options Please make sure to read :ref:`unit_testing` guide first. Ignore tests where the name matches specified patterns. Multiple names are -allowed. Please separate them using comma+space ``, ``. Also, you can +allowed. Please separate them using comma+space ", ". Also, you can ignore some tests using :option:`platformio test --ignore` command. .. list-table:: From b06dc1e63f5c9c7bab3716fe54789f99ba7b81f1 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 2 Sep 2016 00:46:06 +0300 Subject: [PATCH 257/284] Bump new version --- platformio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index a813278b..7852e081 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0b8") +VERSION = (3, 0, "0b9") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" From 6442c86084e91c79ff8f84cc9bc58b648fc0f77e Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 2 Sep 2016 14:35:07 +0300 Subject: [PATCH 258/284] Fix INO to CPP converter when #define is used --- platformio/builder/tools/piomisc.py | 13 ++++++++++--- tests/ino2cpp/basic/basic.ino | 5 ++++- tests/test_ino2cpp.py | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 00d9e386..c3d5dd99 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -53,6 +53,7 @@ class InoToCPPConverter(object): return self.process(contents) def merge(self, nodes): + assert nodes lines = [] for node in nodes: contents = node.get_text_contents() @@ -65,6 +66,9 @@ class InoToCPPConverter(object): else: lines.extend(_lines) + if not self._main_ino: + self._main_ino = nodes[0].get_path() + return "\n".join(["#include "] + lines) if lines else None def process(self, contents): @@ -104,17 +108,20 @@ class InoToCPPConverter(object): if line.endswith("\\"): if line.startswith('"'): - newlines.append(line[:-1]) stropen = True + newlines.append(line[:-1]) + continue elif stropen: newlines[len(newlines) - 1] += line[:-1] + continue elif stropen and line.endswith('";'): newlines[len(newlines) - 1] += line stropen = False newlines.append('#line %d "%s"' % (linenum, self._main_ino.replace("\\", "/"))) - else: - newlines.append(line) + continue + + newlines.append(line) return "\n".join(newlines) diff --git a/tests/ino2cpp/basic/basic.ino b/tests/ino2cpp/basic/basic.ino index 80b3be86..6f764fed 100644 --- a/tests/ino2cpp/basic/basic.ino +++ b/tests/ino2cpp/basic/basic.ino @@ -1,3 +1,6 @@ +#define SQR(a) \ +( a * a ) + typedef struct Item item; struct Item { byte foo[50]; @@ -10,7 +13,7 @@ class Foo { public: Foo(void (*function)()) { - #warning "Line number is 13" + #warning "Line number is 16" } bool childFunc() { diff --git a/tests/test_ino2cpp.py b/tests/test_ino2cpp.py index d4008628..c8f411c0 100644 --- a/tests/test_ino2cpp.py +++ b/tests/test_ino2cpp.py @@ -40,7 +40,7 @@ def test_warning_line(clirunner, validate_cliresult): result = clirunner.invoke(cmd_ci, [join(INOTEST_DIR, "basic"), "-b", "uno"]) validate_cliresult(result) - assert ('basic.ino:13:14: warning: #warning "Line number is 13"' in + assert ('basic.ino:16:14: warning: #warning "Line number is 16"' in result.output) result = clirunner.invoke( cmd_ci, [join(INOTEST_DIR, "strmultilines"), "-b", "uno"]) From a48201f60f442c1e54a0255c10939a01982daa1d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 2 Sep 2016 15:19:54 +0300 Subject: [PATCH 259/284] Skip converting if INO nodes are not found --- platformio/builder/tools/piomisc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index c3d5dd99..46ba5ab4 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -179,6 +179,8 @@ class InoToCPPConverter(object): def ConvertInoToCpp(env): ino_nodes = (env.Glob(join("$PROJECTSRC_DIR", "*.ino")) + env.Glob(join("$PROJECTSRC_DIR", "*.pde"))) + if not ino_nodes: + return c = InoToCPPConverter(env) out_file = c.convert(ino_nodes) From 424d5e71a835bae2afebb9b1c4bdc26f2ca059b0 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 2 Sep 2016 16:45:08 +0300 Subject: [PATCH 260/284] Minor improvements to docs --- docs/ci/appveyor.rst | 2 +- docs/ci/circleci.rst | 12 ++++++------ docs/ci/drone.rst | 2 +- docs/ci/shippable.rst | 2 +- docs/ci/travis.rst | 6 +++--- docs/ide/clion.rst | 2 +- docs/ide/codeblocks.rst | 2 +- docs/ide/eclipse.rst | 2 +- docs/ide/emacs.rst | 2 +- docs/ide/netbeans.rst | 2 +- docs/ide/qtcreator.rst | 2 +- docs/ide/sublimetext.rst | 2 +- docs/ide/visualstudio.rst | 2 +- docs/userguide/cmd_ci.rst | 4 ++-- 14 files changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/ci/appveyor.rst b/docs/ci/appveyor.rst index 2341c0e3..5a018b29 100644 --- a/docs/ci/appveyor.rst +++ b/docs/ci/appveyor.rst @@ -56,7 +56,7 @@ Put ``appveyor.yml`` to the root directory of the GitHub repository. - cmd: pip install -U platformio test_script: - - cmd: platformio ci --board=ID_1 --board=ID_2 --board=ID_N + - cmd: platformio ci --board= --board= --board= For more details as for PlatformIO build process please look into :ref:`cmd_ci` diff --git a/docs/ci/circleci.rst b/docs/ci/circleci.rst index ebc9c7ac..da331230 100644 --- a/docs/ci/circleci.rst +++ b/docs/ci/circleci.rst @@ -49,9 +49,9 @@ guide first. test: override: - - platformio ci path/to/test/file.c --board=ID_1 --board=ID_2 --board=ID_N - - platformio ci examples/file.ino --board=ID_1 --board=ID_2 --board=ID_N - - platformio ci path/to/test/directory --board=ID_1 --board=ID_2 --board=ID_N + - platformio ci path/to/test/file.c --board= --board= --board= + - platformio ci examples/file.ino --board= --board= --board= + - platformio ci path/to/test/directory --board= --board= --board= For more details as for PlatformIO build process please look into :ref:`cmd_ci`. @@ -65,7 +65,7 @@ it), please use ``--lib="."`` option for :ref:`cmd_ci` command .. code-block:: yaml script: - - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N + - platformio ci --lib="." --board= --board= --board= Library dependecies ~~~~~~~~~~~~~~~~~~~ @@ -87,7 +87,7 @@ Install dependent library using :ref:`librarymanager` test: override: - - platformio ci path/to/test/file.c --board=ID_1 --board=ID_2 --board=ID_N + - platformio ci path/to/test/file.c --board= --board= --board= Manually download dependent library and include in build process via ``--lib`` option ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ Manually download dependent library and include in build process via ``--lib`` o test: override: - - platformio ci path/to/test/file.c --lib="/tmp/OneWire-master" --board=ID_1 --board=ID_2 --board=ID_N + - platformio ci path/to/test/file.c --lib="/tmp/OneWire-master" --board= --board= --board= Custom Build Flags ~~~~~~~~~~~~~~~~~~ diff --git a/docs/ci/drone.rst b/docs/ci/drone.rst index ec9d1118..c0537d8e 100644 --- a/docs/ci/drone.rst +++ b/docs/ci/drone.rst @@ -51,7 +51,7 @@ Please fill all fields for your project in the Drone control panel: .. code-block:: bash pip install -U platformio - platformio ci --board=ID_1 --board=ID_2 --board=ID_N + platformio ci --board= --board= --board= .. image:: ../_static/droneci-platformio-integration-1.png diff --git a/docs/ci/shippable.rst b/docs/ci/shippable.rst index 4a71e7a7..63daa960 100644 --- a/docs/ci/shippable.rst +++ b/docs/ci/shippable.rst @@ -58,7 +58,7 @@ GitHub repository. - pip install -U platformio script: - - platformio ci --board=ID_1 --board=ID_2 --board=ID_N + - platformio ci --board= --board= --board= For more details as for PlatformIO build process please look into :ref:`cmd_ci` diff --git a/docs/ci/travis.rst b/docs/ci/travis.rst index e4dd6ef5..a690e5a0 100644 --- a/docs/ci/travis.rst +++ b/docs/ci/travis.rst @@ -72,7 +72,7 @@ PlatformIO is written in Python and is recommended to be run within - pip install -U platformio script: - - platformio ci --board=ID_1 --board=ID_2 --board=ID_N + - platformio ci --board= --board= --board= Then perform steps 1, 2 and 4 from http://docs.travis-ci.com/user/getting-started/ @@ -87,7 +87,7 @@ it), please use ``--lib="."`` option for :ref:`cmd_ci` command .. code-block:: yaml script: - - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N + - platformio ci --lib="." --board= --board= --board= Library dependencies ~~~~~~~~~~~~~~~~~~~~ @@ -121,7 +121,7 @@ Manually download dependent library and include in build process via ``--lib`` o - unzip /tmp/onewire_source.zip -d /tmp/ script: - - platformio ci --lib="/tmp/OneWire-master" --board=ID_1 --board=ID_2 --board=ID_N + - platformio ci --lib="/tmp/OneWire-master" --board= --board= --board= Custom Build Flags ~~~~~~~~~~~~~~~~~~ diff --git a/docs/ide/clion.rst b/docs/ide/clion.rst index 2d04fbbd..185f503e 100644 --- a/docs/ide/clion.rst +++ b/docs/ide/clion.rst @@ -36,7 +36,7 @@ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide clion --board %ID% + platformio init --ide clion --board # For example, generate project for Arduino UNO platformio init --ide clion --board uno diff --git a/docs/ide/codeblocks.rst b/docs/ide/codeblocks.rst index 7ac5b3c6..23df9db1 100644 --- a/docs/ide/codeblocks.rst +++ b/docs/ide/codeblocks.rst @@ -35,7 +35,7 @@ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide codeblocks --board %ID% + platformio init --ide codeblocks --board # For example, generate project for Arduino UNO platformio init --ide codeblocks --board uno diff --git a/docs/ide/eclipse.rst b/docs/ide/eclipse.rst index 418cdec7..3d21ea09 100644 --- a/docs/ide/eclipse.rst +++ b/docs/ide/eclipse.rst @@ -40,7 +40,7 @@ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide eclipse --board %ID% + platformio init --ide eclipse --board # For example, generate project for Arduino UNO platformio init --ide eclipse --board uno diff --git a/docs/ide/emacs.rst b/docs/ide/emacs.rst index 768c6333..fbbc108d 100644 --- a/docs/ide/emacs.rst +++ b/docs/ide/emacs.rst @@ -50,7 +50,7 @@ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide emacs --board %ID% + platformio init --ide emacs --board There are 6 predefined targets for building. diff --git a/docs/ide/netbeans.rst b/docs/ide/netbeans.rst index dfe96f35..a44a3311 100644 --- a/docs/ide/netbeans.rst +++ b/docs/ide/netbeans.rst @@ -38,7 +38,7 @@ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide netbeans --board %ID% + platformio init --ide netbeans --board # For example, generate project for Arduino UNO platformio init --ide netbeans --board uno diff --git a/docs/ide/qtcreator.rst b/docs/ide/qtcreator.rst index 2cacc2c8..42df4feb 100644 --- a/docs/ide/qtcreator.rst +++ b/docs/ide/qtcreator.rst @@ -40,7 +40,7 @@ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide qtcreator --board %ID% + platformio init --ide qtcreator --board # For example, generate project for Arduino UNO platformio init --ide qtcreator --board uno diff --git a/docs/ide/sublimetext.rst b/docs/ide/sublimetext.rst index 150c7a96..3589287d 100644 --- a/docs/ide/sublimetext.rst +++ b/docs/ide/sublimetext.rst @@ -47,7 +47,7 @@ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide sublimetext --board %ID% + platformio init --ide sublimetext --board # For example, generate project for Arduino UNO platformio init --ide sublimetext --board uno diff --git a/docs/ide/visualstudio.rst b/docs/ide/visualstudio.rst index ddcd2d54..7848e6cf 100644 --- a/docs/ide/visualstudio.rst +++ b/docs/ide/visualstudio.rst @@ -40,7 +40,7 @@ command and generate project via :option:`platformio init --ide` command: .. code-block:: shell - platformio init --ide sublimetext --board %ID% + platformio init --ide sublimetext --board # For example, generate project for Arduino UNO platformio init --ide visualstudio --board uno diff --git a/docs/userguide/cmd_ci.rst b/docs/userguide/cmd_ci.rst index 708996e2..87c3735b 100644 --- a/docs/userguide/cmd_ci.rst +++ b/docs/userguide/cmd_ci.rst @@ -63,10 +63,10 @@ Options .. option:: -l, --lib -Source code which will be copied to ``%build_dir%/lib`` directly. +Source code which will be copied to ``/lib`` directly. If :option:`platformio ci --lib` is a path to file (not to directory), then -PlatformIO will create temporary directory within ``%build_dir%/lib`` and copy +PlatformIO will create temporary directory within ``/lib`` and copy the rest files into it. From a1cb089d0df367e75d088cf93303d3dc1539830c Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 2 Sep 2016 16:55:11 +0300 Subject: [PATCH 261/284] Add new articles --- docs/articles.rst | 4 +++- docs/platforms/espressif_extra.rst | 1 + docs/platforms/nordicnrf51_extra.rst | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/articles.rst b/docs/articles.rst index a96f6c40..294922c7 100644 --- a/docs/articles.rst +++ b/docs/articles.rst @@ -18,11 +18,13 @@ Articles about us If you've written article about PlatformIO and would like it listed on this page, `please edit this page `_. -Here are recent articles about PlatformIO: +Here are recent articles/reviews about PlatformIO: 2016 ^^^^ +* Sep 2, 2016 - **Tinkerman** `ESP8266: Optimizing files for SPIFFS with Gulp `_ +* Aug 28, 2016 - **Tom Parker** `Using the BBC micro:bit with PlatformIO `_ * Aug 24, 2016 - **Primal Cortex** `Cloud based continuous integration and delivery for IOT using PlatformIO `_ * Aug 18, 2016 - **Primal Cortex** - `Installing PlatformIO on Arch Linux `_ * Jul 26, 2016 - **Embedded Systems Laboratory** - `แนะนำการใช้งาน PlatformIO IDE สำหรับบอร์ด Arduino และ ESP8266 (Get started with PlatformIO IDE for Arduino board and ESP8266, Thai) `_ diff --git a/docs/platforms/espressif_extra.rst b/docs/platforms/espressif_extra.rst index a67cbff9..19967507 100644 --- a/docs/platforms/espressif_extra.rst +++ b/docs/platforms/espressif_extra.rst @@ -240,6 +240,7 @@ Using Arduino Framework with Staging version Articles -------- +* Sep 2, 2016 - **Tinkerman** `Optimizing files for SPIFFS with Gulp `_ * Jul 15, 2016 - **Jaime** - `ESP8266 Mobile Rick Roll Captive Portal `_ * Jun 13, 2016 - **Daniel Eichhorn** - `New Weather Station Demo on Github `_ * Jun 3, 2016 - **Daniel Eichhorn** - `ESP8266: Continuous Delivery Pipeline – Push To Production `_ diff --git a/docs/platforms/nordicnrf51_extra.rst b/docs/platforms/nordicnrf51_extra.rst index b77d8629..e54631f4 100644 --- a/docs/platforms/nordicnrf51_extra.rst +++ b/docs/platforms/nordicnrf51_extra.rst @@ -9,6 +9,11 @@ See the License for the specific language governing permissions and limitations under the License. +Articles +-------- + +* Aug 28, 2016 - **Tom Parker ** `Using the BBC micro:bit with PlatformIO `_ + Examples -------- From ec035c25a1009cefa68601e4228ca2517e55e55e Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 2 Sep 2016 18:45:19 +0300 Subject: [PATCH 262/284] Improve "clean" target // Resolve #747 --- platformio/builder/main.py | 11 ++++++++--- platformio/builder/tools/piomisc.py | 18 ++++++++++++++++-- platformio/managers/platform.py | 2 ++ 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/platformio/builder/main.py b/platformio/builder/main.py index f78c4942..2da97908 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -94,7 +94,6 @@ DEFAULT_ENV_OPTIONS = dict( PYTHONEXE=util.get_pythonexe_path()) if not int(ARGUMENTS.get("PIOVERBOSE", 0)): - print "Verbose mode can be enabled via `-v, --verbose` option" DEFAULT_ENV_OPTIONS['ARCOMSTR'] = "Archiving $TARGET" DEFAULT_ENV_OPTIONS['LINKCOMSTR'] = "Linking $TARGET" DEFAULT_ENV_OPTIONS['RANLIBCOMSTR'] = "Indexing $TARGET" @@ -108,6 +107,12 @@ for k in commonvars.keys(): if k in env: env[k] = base64.b64decode(env[k]) +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" + # 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"): @@ -138,8 +143,8 @@ if env.get("EXTRA_SCRIPT"): if "envdump" in COMMAND_LINE_TARGETS: print env.Dump() - env.Exit() + env.Exit(0) if "idedata" in COMMAND_LINE_TARGETS: print json.dumps(env.DumpIDEData()) - env.Exit() + env.Exit(0) diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 46ba5ab4..c38258af 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -18,8 +18,8 @@ import atexit import re import sys from glob import glob -from os import environ, remove -from os.path import basename, isfile, join +from os import environ, remove, walk +from os.path import basename, isdir, isfile, join, relpath from tempfile import mkstemp from SCons.Action import Action @@ -317,6 +317,19 @@ def VerboseAction(_, act, actstr): return Action(act, actstr) +def PioClean(env, clean_dir): + if not isdir(clean_dir): + print "Build environment is clean" + env.Exit(0) + 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) + env.Exit(0) + + def exists(_): return True @@ -327,4 +340,5 @@ def generate(env): env.AddMethod(GetCompilerType) env.AddMethod(GetActualLDScript) env.AddMethod(VerboseAction) + env.AddMethod(PioClean) return env diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 2896ceae..6baab0f4 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -279,6 +279,8 @@ class PlatformRunMixin(object): self._echo_line(line, level=3 if is_error else 2) def _echo_line(self, line, level): + if line.startswith("scons: "): + line = line[7:] assert 1 <= level <= 3 if self.silent and (level < 2 or not line): return From 65b5f20cf71562e19d6cbab63246e84cbd814c41 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 2 Sep 2016 18:50:14 +0300 Subject: [PATCH 263/284] Fix typo in docs --- docs/platforms/nordicnrf51_extra.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/nordicnrf51_extra.rst b/docs/platforms/nordicnrf51_extra.rst index e54631f4..79140038 100644 --- a/docs/platforms/nordicnrf51_extra.rst +++ b/docs/platforms/nordicnrf51_extra.rst @@ -12,7 +12,7 @@ Articles -------- -* Aug 28, 2016 - **Tom Parker ** `Using the BBC micro:bit with PlatformIO `_ +* Aug 28, 2016 - **Tom Parker** `Using the BBC micro:bit with PlatformIO `_ Examples -------- From 9b2999d64b02cc65dc62434a29d0fe841b3d1886 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 2 Sep 2016 22:23:26 +0300 Subject: [PATCH 264/284] Fix test for "pio test" --- tests/commands/test_test.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/commands/test_test.py b/tests/commands/test_test.py index 1ecaac39..173f8113 100644 --- a/tests/commands/test_test.py +++ b/tests/commands/test_test.py @@ -14,13 +14,16 @@ from os.path import join -from platformio.commands.test import cli as cli_test +import pytest + +from platformio import util -def test_local_env(clirunner, validate_cliresult): - result = clirunner.invoke( - cli_test, - ["-d", join("examples", "unit-testing", "calculator"), "-e", "local"]) - validate_cliresult(result) +def test_local_env(): + result = util.exec_command(["platformio", "test", "-d", + join("examples", "unit-testing", "calculator"), + "-e", "local"]) + if result['returncode'] != 0: + pytest.fail(result) assert all( - [s in result.output for s in ("[PASSED]", "[IGNORED]", "[FAILED]")]) + [s in result['out'] for s in ("[PASSED]", "[IGNORED]", "[FAILED]")]) From 21d34482daf3b5753546036c98c6e5c42577660f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 2 Sep 2016 22:41:27 +0300 Subject: [PATCH 265/284] Fix package manager when "git@url" is used --- platformio/vcsclient.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/platformio/vcsclient.py b/platformio/vcsclient.py index 0d3af892..a509302b 100644 --- a/platformio/vcsclient.py +++ b/platformio/vcsclient.py @@ -28,11 +28,16 @@ class VCSClientFactory(object): def newClient(src_dir, remote_url): result = urlparse(remote_url) type_ = result.scheme - if "+" in result.scheme: + if not type_ and remote_url.startswith("git@"): + type_ = "git" + elif "+" in result.scheme: type_, _ = result.scheme.split("+", 1) remote_url = remote_url[len(type_) + 1:] if result.fragment: remote_url = remote_url.rsplit("#", 1)[0] + if not type_: + raise PlatformioException("VCS: Unknown repository type %s" % + remote_url) obj = getattr(modules[__name__], "%sClient" % type_.title())( src_dir, remote_url, result.fragment) assert isinstance(obj, VCSClientBase) From 139bd4c10a6372f63177deac5d7de0ebf288284d Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 2 Sep 2016 23:30:24 +0300 Subject: [PATCH 266/284] Export library path for PlatformIO Plus --- platformio/pioplus.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/platformio/pioplus.py b/platformio/pioplus.py index aae5c646..edfc1166 100644 --- a/platformio/pioplus.py +++ b/platformio/pioplus.py @@ -14,7 +14,8 @@ import os import subprocess -from os.path import join +from os.path import dirname, join +from platform import system from platformio import util from platformio.managers.package import PackageManager @@ -48,6 +49,9 @@ def pioplus_update(): def pioplus_call(args, **kwargs): + pioplus_path = get_pioplusexe_path() + if system() == "Linux": + os.environ['LD_LIBRARY_PATH'] = dirname(pioplus_path) os.environ['PYTHONEXEPATH'] = util.get_pythonexe_path() util.copy_pythonpath_to_osenv() - subprocess.call([get_pioplusexe_path()] + args, **kwargs) + subprocess.call([pioplus_path] + args, **kwargs) From e2d229586694da4f4ac0a3463151493e0a820980 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 3 Sep 2016 01:27:34 +0300 Subject: [PATCH 267/284] Handle url with ".git" extension as Git package/library --- platformio/__init__.py | 2 +- platformio/managers/package.py | 16 ++++++++++++---- tests/commands/test_lib.py | 5 +++-- tests/test_managers.py | 2 ++ 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 7852e081..0ba9b049 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0b9") +VERSION = (3, 0, "0b10") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 39626f76..14e9644f 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -324,13 +324,19 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): if "=" in text and not text.startswith("id="): name, url = text.split("=", 1) - # Handle GitHub URL (https://github.com/user/package) - if url.startswith("https://github.com/") and \ - not url.endswith((".zip", ".tar.gz")): + git_conditions = [ + # Handle GitHub URL (https://github.com/user/package) + url.startswith("https://github.com/") and not url.endswith( + (".zip", ".tar.gz")), + url.startswith("http") and + (url.split("#", 1)[0] if "#" in url else url).endswith(".git") + ] + + if any(git_conditions): url = "git+" + url # Handle Developer Mbed URL # (https://developer.mbed.org/users/user/code/package/) - if url.startswith("https://developer.mbed.org"): + elif url.startswith("https://developer.mbed.org"): url = "hg+" + url # git@github.com:user/package.git @@ -342,6 +348,8 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): url = "file://" + url elif url.count("/") == 1 and not url.startswith("git@"): url = "git+https://github.com/" + url + + # determine name if url_marker in url and not name: _url = url.split("#", 1)[0] if "#" in url else url if _url.endswith(("\\", "/")): diff --git a/tests/commands/test_lib.py b/tests/commands/test_lib.py index af9d60da..0daae542 100644 --- a/tests/commands/test_lib.py +++ b/tests/commands/test_lib.py @@ -52,6 +52,7 @@ def test_global_install_repository(clirunner, validate_cliresult, ["-g", "install", "https://github.com/gioblu/PJON.git#3.0", + "https://gitlab.com/ivankravets/rs485-nodeproto.git", # "https://developer.mbed.org/users/simon/code/TextLCD/", "http://dl.platformio.org/libraries/archives/3/3756.tar.gz", "knolleary/pubsubclient"]) @@ -72,7 +73,7 @@ def test_global_lib_list(clirunner, validate_cliresult, isolated_pio_home): for n in ("PJON", "git+https://github.com/knolleary/pubsubclient")]) items1 = [i['name'] for i in json.loads(result.output)] items2 = ["OneWire", "DHT22", "PJON", "ESPAsyncTCP", "Json", "ArduinoJson", - "pubsubclient"] + "pubsubclient", "rs485-nodeproto"] assert set(items1) == set(items2) @@ -106,7 +107,7 @@ def test_global_lib_uninstall(clirunner, validate_cliresult, validate_cliresult(result) items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] items2 = ["DHT22_ID58", "Json_ID64", "ESPAsyncTCP_ID305", "pubsubclient", - "PJON"] + "PJON", "rs485-nodeproto"] assert set(items1) == set(items2) diff --git a/tests/test_managers.py b/tests/test_managers.py index f41c31a1..f99038e6 100644 --- a/tests/test_managers.py +++ b/tests/test_managers.py @@ -30,6 +30,8 @@ def test_pkg_name_parser(): ("LocalName", None, "file://" + util.get_home_dir())], ["https://github.com/user/package.git", ("package", None, "git+https://github.com/user/package.git")], + ["https://gitlab.com/user/package.git", + ("package", None, "git+https://gitlab.com/user/package.git")], ["https://github.com/user/package/archive/branch.zip", ("branch", None, "https://github.com/user/package/archive/branch.zip")], From c8849a4648af1226f524bc1656b199abed17e724 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 3 Sep 2016 14:59:50 +0300 Subject: [PATCH 268/284] Extend JSON output when listing installed development platforms --- platformio/commands/platform.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index 7f98b257..4a349cfc 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -138,7 +138,11 @@ def platform_list(json_output): "title": p.title, "description": p.description, "version": p.version, - "packages": p.get_installed_packages().keys() + "url": p.manifest.get("url"), + "packages": p.get_installed_packages().keys(), + 'forDesktop': any([ + p.name.startswith(n) for n in ("native", "linux", "windows") + ]) }) if json_output: From 7f1b569d6fd69d5604c8e2819145088f3777c7bb Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 3 Sep 2016 16:26:52 +0300 Subject: [PATCH 269/284] Update docs for embedded platforms, frameworks and boards --- docs/frameworks/arduino.rst | 2 +- docs/frameworks/mbed.rst | 20 ++++ docs/platforms/atmelavr.rst | 29 +++-- docs/platforms/atmelsam.rst | 28 ++--- docs/platforms/embedded_boards.rst | 22 +++- docs/platforms/espressif.rst | 18 ++-- docs/platforms/freescalekinetis.rst | 3 + docs/platforms/intel_arc32.rst | 3 + docs/platforms/lattice_ice40.rst | 3 + docs/platforms/linux_arm.rst | 3 + docs/platforms/linux_i686.rst | 3 + docs/platforms/linux_x86_64.rst | 5 +- docs/platforms/microchippic32.rst | 9 +- docs/platforms/native.rst | 14 ++- docs/platforms/nordicnrf51.rst | 11 +- docs/platforms/nxplpc.rst | 3 + docs/platforms/siliconlabsefm32.rst | 3 + docs/platforms/ststm32.rst | 54 +++++++--- docs/platforms/teensy.rst | 18 ++-- docs/platforms/timsp430.rst | 17 +-- docs/platforms/titiva.rst | 20 ++-- docs/platforms/windows_x86.rst | 3 + platformio/commands/platform.py | 2 +- platformio/managers/platform.py | 4 + platformio/util.py | 39 ------- scripts/docspregen.py | 159 ++++++++++++++-------------- scripts/mbed_to_package.py | 120 --------------------- 27 files changed, 288 insertions(+), 327 deletions(-) delete mode 100644 scripts/mbed_to_package.py diff --git a/docs/frameworks/arduino.rst b/docs/frameworks/arduino.rst index ff28614b..41de2ea1 100644 --- a/docs/frameworks/arduino.rst +++ b/docs/frameworks/arduino.rst @@ -151,7 +151,7 @@ Adafruit * - ``protrinket3ftdi`` - `Adafruit Pro Trinket 3V/12MHz (FTDI) `_ - ATMEGA328P - - 16 MHz + - 12 MHz - 32 Kb - 2 Kb diff --git a/docs/frameworks/mbed.rst b/docs/frameworks/mbed.rst index 05009466..fb45d9a6 100644 --- a/docs/frameworks/mbed.rst +++ b/docs/frameworks/mbed.rst @@ -266,6 +266,26 @@ Freescale - 256 Kb - 32 Kb +Generic +~~~~~~~ + +.. list-table:: + :header-rows: 1 + + * - Type ``board`` + - Name + - Microcontroller + - Frequency + - Flash + - RAM + + * - ``bluepill_f103c8`` + - `BluePill F103C8 `_ + - STM32F103C8T6 + - 72 MHz + - 64 Kb + - 20 Kb + JKSoft ~~~~~~ diff --git a/docs/platforms/atmelavr.rst b/docs/platforms/atmelavr.rst index 0c5faa9a..88d545f0 100644 --- a/docs/platforms/atmelavr.rst +++ b/docs/platforms/atmelavr.rst @@ -28,21 +28,34 @@ Packages * - Name - Contents - * - ``toolchain-atmelavr`` - - `avr-gcc `_, `GDB `_, `AVaRICE `_, `SimulAVR `_ - - * - ``tool-avrdude`` - - `AVRDUDE `_ + * - ``framework-arduinoavr`` + - `Arduino Wiring-based Framework (AVR Core, 1.6) `_ * - ``framework-simba`` - `Simba Framework `_ - * - ``framework-arduinoavr`` - - `Arduino Wiring-based Framework (AVR Core, 1.6) `_ + * - ``tool-avrdude`` + - `AVRDUDE `_ * - ``tool-micronucleus`` - `Micronucleus `_ + * - ``tool-scons`` + - `SCons software construction tool `_ + + * - ``toolchain-atmelavr`` + - `avr-gcc `_, `GDB `_, `AVaRICE `_, `SimulAVR `_ + +.. warning:: + **Linux Users:** Don't forget to install "udev" rules file + `99-platformio-udev.rules `_ (an instruction is located in the file). + + + **Windows Users:** Please check that you have correctly installed USB + driver from board manufacturer + + + Frameworks ---------- .. list-table:: @@ -124,7 +137,7 @@ Adafruit * - ``protrinket3ftdi`` - `Adafruit Pro Trinket 3V/12MHz (FTDI) `_ - ATMEGA328P - - 16 MHz + - 12 MHz - 32 Kb - 2 Kb diff --git a/docs/platforms/atmelsam.rst b/docs/platforms/atmelsam.rst index 8bc92bbc..a73ab057 100644 --- a/docs/platforms/atmelsam.rst +++ b/docs/platforms/atmelsam.rst @@ -28,30 +28,30 @@ Packages * - Name - Contents - * - ``framework-mbed`` - - `mbed Framework `_ - - * - ``toolchain-gccarmnoneeabi`` - - `gcc-arm-embedded `_, `GDB `_ - * - ``framework-arduinosam`` - `Arduino Wiring-based Framework (SAM Core, 1.6) `_ - * - ``ldscripts`` - - `Linker Scripts `_ + * - ``framework-mbed`` + - `mbed Framework `_ * - ``framework-simba`` - `Simba Framework `_ - * - ``tool-openocd`` - - `OpenOCD `_ - * - ``tool-avrdude`` - `AVRDUDE `_ * - ``tool-bossac`` - `BOSSA CLI `_ + * - ``tool-openocd`` + - `OpenOCD `_ + + * - ``tool-scons`` + - `SCons software construction tool `_ + + * - ``toolchain-gccarmnoneeabi`` + - `gcc-arm-embedded `_, `GDB `_ + .. warning:: **Linux Users:** Don't forget to install "udev" rules file `99-platformio-udev.rules `_ (an instruction is located in the file). @@ -73,12 +73,12 @@ Frameworks * - :ref:`framework_arduino` - Arduino Wiring-based Framework allows writing cross-platform software to control devices attached to a wide range of Arduino boards to create all kinds of creative coding, interactive objects, spaces or physical experiences. - * - :ref:`framework_mbed` - - The mbed framework The mbed SDK has been designed to provide enough hardware abstraction to be intuitive and concise, yet powerful enough to build complex projects. It is built on the low-level ARM CMSIS APIs, allowing you to code down to the metal if needed. In addition to RTOS, USB and Networking libraries, a cookbook of hundreds of reusable peripheral and module libraries have been built on top of the SDK by the mbed Developer Community. - * - :ref:`framework_simba` - Simba is an RTOS and build framework. It aims to make embedded programming easy and portable. + * - :ref:`framework_mbed` + - The mbed framework The mbed SDK has been designed to provide enough hardware abstraction to be intuitive and concise, yet powerful enough to build complex projects. It is built on the low-level ARM CMSIS APIs, allowing you to code down to the metal if needed. In addition to RTOS, USB and Networking libraries, a cookbook of hundreds of reusable peripheral and module libraries have been built on top of the SDK by the mbed Developer Community. + Boards ------ diff --git a/docs/platforms/embedded_boards.rst b/docs/platforms/embedded_boards.rst index 9bf44d69..8353ed67 100644 --- a/docs/platforms/embedded_boards.rst +++ b/docs/platforms/embedded_boards.rst @@ -137,7 +137,7 @@ Adafruit * - ``protrinket3ftdi`` - `Adafruit Pro Trinket 3V/12MHz (FTDI) `_ - ATMEGA328P - - 16 MHz + - 12 MHz - 32 Kb - 2 Kb @@ -1123,6 +1123,26 @@ Fubarino - 512 Kb - 128 Kb +Generic +~~~~~~~ + +.. list-table:: + :header-rows: 1 + + * - Type ``board`` + - Name + - Microcontroller + - Frequency + - Flash + - RAM + + * - ``bluepill_f103c8`` + - `BluePill F103C8 `_ + - STM32F103C8T6 + - 72 MHz + - 64 Kb + - 20 Kb + Generic ATTiny ~~~~~~~~~~~~~~ diff --git a/docs/platforms/espressif.rst b/docs/platforms/espressif.rst index fca7b8ab..0bbe1ba1 100644 --- a/docs/platforms/espressif.rst +++ b/docs/platforms/espressif.rst @@ -28,26 +28,26 @@ Packages * - Name - Contents - * - ``toolchain-xtensa`` - - `xtensa-gcc `_, `GDB `_ + * - ``framework-arduinoespressif`` + - `Arduino Wiring-based Framework (ESP8266 Core) `_ * - ``framework-simba`` - `Simba Framework `_ + * - ``sdk-esp8266`` + - `ESP8266 SDK `_ + * - ``tool-esptool`` - `esptool-ck `_ * - ``tool-mkspiffs`` - `Tool to build and unpack SPIFFS images `_ - * - ``framework-arduinoespressif`` - - `Arduino Wiring-based Framework (ESP8266 Core) `_ + * - ``tool-scons`` + - `SCons software construction tool `_ - * - ``ldscripts`` - - `Linker Scripts `_ - - * - ``sdk-esp8266`` - - `ESP8266 SDK `_ + * - ``toolchain-xtensa`` + - `xtensa-gcc `_, `GDB `_ .. warning:: **Linux Users:** Don't forget to install "udev" rules file diff --git a/docs/platforms/freescalekinetis.rst b/docs/platforms/freescalekinetis.rst index aba52b24..29323287 100644 --- a/docs/platforms/freescalekinetis.rst +++ b/docs/platforms/freescalekinetis.rst @@ -31,6 +31,9 @@ Packages * - ``framework-mbed`` - `mbed Framework `_ + * - ``tool-scons`` + - `SCons software construction tool `_ + * - ``toolchain-gccarmnoneeabi`` - `gcc-arm-embedded `_, `GDB `_ diff --git a/docs/platforms/intel_arc32.rst b/docs/platforms/intel_arc32.rst index 3127fd76..dbfe8f16 100644 --- a/docs/platforms/intel_arc32.rst +++ b/docs/platforms/intel_arc32.rst @@ -34,6 +34,9 @@ Packages * - ``tool-arduino101load`` - `Genuino101 uploader `_ + * - ``tool-scons`` + - `SCons software construction tool `_ + * - ``toolchain-intelarc32`` - `GCC for Intel ARC `_ diff --git a/docs/platforms/lattice_ice40.rst b/docs/platforms/lattice_ice40.rst index fd54c760..d4e60376 100644 --- a/docs/platforms/lattice_ice40.rst +++ b/docs/platforms/lattice_ice40.rst @@ -28,6 +28,9 @@ Packages * - Name - Contents + * - ``tool-scons`` + - `SCons software construction tool `_ + * - ``toolchain-icestorm`` - `GCC for FPGA IceStorm `_ diff --git a/docs/platforms/linux_arm.rst b/docs/platforms/linux_arm.rst index 0b69a2d3..1e01001d 100644 --- a/docs/platforms/linux_arm.rst +++ b/docs/platforms/linux_arm.rst @@ -31,6 +31,9 @@ Packages * - ``framework-wiringpi`` - `GPIO Interface library for the Raspberry Pi `_ + * - ``tool-scons`` + - `SCons software construction tool `_ + * - ``toolchain-gccarmlinuxgnueabi`` - `GCC for Linux ARM GNU EABI `_, `GDB `_ diff --git a/docs/platforms/linux_i686.rst b/docs/platforms/linux_i686.rst index fb1f3dd7..386c8dd5 100644 --- a/docs/platforms/linux_i686.rst +++ b/docs/platforms/linux_i686.rst @@ -28,5 +28,8 @@ Packages * - Name - Contents + * - ``tool-scons`` + - `SCons software construction tool `_ + * - ``toolchain-gcclinux32`` - `GCC for Linux i686 `_ \ No newline at end of file diff --git a/docs/platforms/linux_x86_64.rst b/docs/platforms/linux_x86_64.rst index 445eb691..91068819 100644 --- a/docs/platforms/linux_x86_64.rst +++ b/docs/platforms/linux_x86_64.rst @@ -15,7 +15,7 @@ Platform ``linux_x86_64`` ========================= Linux x86_64 (64-bit) is a Unix-like and mostly POSIX-compliant computer operating system (OS) assembled under the model of free and open-source software development and distribution. Using host OS (Mac OS X or Linux 64-bit) you can build native application for Linux x86_64 platform. -For more detailed information please visit `vendor site `_. +For more detailed information please visit `vendor site `_. .. contents:: @@ -28,5 +28,8 @@ Packages * - Name - Contents + * - ``tool-scons`` + - `SCons software construction tool `_ + * - ``toolchain-gcclinux64`` - `GCC for Linux x86_64 `_ \ No newline at end of file diff --git a/docs/platforms/microchippic32.rst b/docs/platforms/microchippic32.rst index dc5db46a..91269d85 100644 --- a/docs/platforms/microchippic32.rst +++ b/docs/platforms/microchippic32.rst @@ -31,12 +31,15 @@ Packages * - ``framework-arduinomicrochippic32`` - `Arduino Wiring-based Framework (PIC32 Core) `_ - * - ``toolchain-microchippic32`` - - `GCC for Microchip PIC32 `_ - * - ``tool-pic32prog`` - `pic32prog `_ + * - ``tool-scons`` + - `SCons software construction tool `_ + + * - ``toolchain-microchippic32`` + - `GCC for Microchip PIC32 `_ + .. warning:: **Linux Users:** Don't forget to install "udev" rules file `99-platformio-udev.rules `_ (an instruction is located in the file). diff --git a/docs/platforms/native.rst b/docs/platforms/native.rst index a4174222..a6794951 100644 --- a/docs/platforms/native.rst +++ b/docs/platforms/native.rst @@ -17,4 +17,16 @@ Native development platform is intended to be used for desktop OS. This platform For more detailed information please visit `vendor site `_. -.. contents:: \ No newline at end of file +.. contents:: + +Packages +-------- + +.. list-table:: + :header-rows: 1 + + * - Name + - Contents + + * - ``tool-scons`` + - `SCons software construction tool `_ \ No newline at end of file diff --git a/docs/platforms/nordicnrf51.rst b/docs/platforms/nordicnrf51.rst index 75fd69d8..b7f8c8d9 100644 --- a/docs/platforms/nordicnrf51.rst +++ b/docs/platforms/nordicnrf51.rst @@ -28,20 +28,23 @@ Packages * - Name - Contents + * - ``framework-arduinonordicnrf51`` + - `Arduino Wiring-based Framework (RFduino Core) `_ + * - ``framework-mbed`` - `mbed Framework `_ * - ``tool-rfdloader`` - `rfdloader `_ - * - ``toolchain-gccarmnoneeabi`` - - `gcc-arm-embedded `_, `GDB `_ + * - ``tool-scons`` + - `SCons software construction tool `_ * - ``tool-sreccat`` - `Merging tool `_ - * - ``framework-arduinonordicnrf51`` - - `Arduino Wiring-based Framework (RFduino Core) `_ + * - ``toolchain-gccarmnoneeabi`` + - `gcc-arm-embedded `_, `GDB `_ .. warning:: **Linux Users:** Don't forget to install "udev" rules file diff --git a/docs/platforms/nxplpc.rst b/docs/platforms/nxplpc.rst index c733fa3e..3b76506c 100644 --- a/docs/platforms/nxplpc.rst +++ b/docs/platforms/nxplpc.rst @@ -31,6 +31,9 @@ Packages * - ``framework-mbed`` - `mbed Framework `_ + * - ``tool-scons`` + - `SCons software construction tool `_ + * - ``toolchain-gccarmnoneeabi`` - `gcc-arm-embedded `_, `GDB `_ diff --git a/docs/platforms/siliconlabsefm32.rst b/docs/platforms/siliconlabsefm32.rst index c1ccc8a5..ac92c554 100644 --- a/docs/platforms/siliconlabsefm32.rst +++ b/docs/platforms/siliconlabsefm32.rst @@ -31,6 +31,9 @@ Packages * - ``framework-mbed`` - `mbed Framework `_ + * - ``tool-scons`` + - `SCons software construction tool `_ + * - ``toolchain-gccarmnoneeabi`` - `gcc-arm-embedded `_, `GDB `_ diff --git a/docs/platforms/ststm32.rst b/docs/platforms/ststm32.rst index 6edea8b9..d66e1f71 100644 --- a/docs/platforms/ststm32.rst +++ b/docs/platforms/ststm32.rst @@ -28,26 +28,26 @@ Packages * - Name - Contents - * - ``framework-libopencm3`` - - `libOpenCM3 Framework `_ - - * - ``toolchain-gccarmnoneeabi`` - - `gcc-arm-embedded `_, `GDB `_ - - * - ``tool-stlink`` - - `ST-Link `_ - - * - ``framework-spl`` - - `Standard Peripheral Library for STM32 MCUs `_ - * - ``framework-cmsis`` - `Vendor-independent hardware abstraction layer for the Cortex-M processor series `_ + * - ``framework-libopencm3`` + - `libOpenCM3 Framework `_ + * - ``framework-mbed`` - `mbed Framework `_ - * - ``ldscripts`` - - `Linker Scripts `_ + * - ``framework-spl`` + - `Standard Peripheral Library for STM32 MCUs `_ + + * - ``tool-scons`` + - `SCons software construction tool `_ + + * - ``tool-stlink`` + - `ST-Link `_ + + * - ``toolchain-gccarmnoneeabi`` + - `gcc-arm-embedded `_, `GDB `_ .. warning:: **Linux Users:** Don't forget to install "udev" rules file @@ -73,12 +73,12 @@ Frameworks * - :ref:`framework_libopencm3` - The libOpenCM3 framework aims to create a free/libre/open-source firmware library for various ARM Cortex-M0(+)/M3/M4 microcontrollers, including ST STM32, Ti Tiva and Stellaris, NXP LPC 11xx, 13xx, 15xx, 17xx parts, Atmel SAM3, Energy Micro EFM32 and others. - * - :ref:`framework_mbed` - - The mbed framework The mbed SDK has been designed to provide enough hardware abstraction to be intuitive and concise, yet powerful enough to build complex projects. It is built on the low-level ARM CMSIS APIs, allowing you to code down to the metal if needed. In addition to RTOS, USB and Networking libraries, a cookbook of hundreds of reusable peripheral and module libraries have been built on top of the SDK by the mbed Developer Community. - * - :ref:`framework_spl` - The ST Standard Peripheral Library provides a set of functions for handling the peripherals on the STM32 Cortex-M3 family. The idea is to save the user (the new user, in particular) having to deal directly with the registers. + * - :ref:`framework_mbed` + - The mbed framework The mbed SDK has been designed to provide enough hardware abstraction to be intuitive and concise, yet powerful enough to build complex projects. It is built on the low-level ARM CMSIS APIs, allowing you to code down to the metal if needed. In addition to RTOS, USB and Networking libraries, a cookbook of hundreds of reusable peripheral and module libraries have been built on top of the SDK by the mbed Developer Community. + Boards ------ @@ -142,6 +142,26 @@ Armstrap - 512 Kb - 192 Kb +Generic +~~~~~~~ + +.. list-table:: + :header-rows: 1 + + * - Type ``board`` + - Name + - Microcontroller + - Frequency + - Flash + - RAM + + * - ``bluepill_f103c8`` + - `BluePill F103C8 `_ + - STM32F103C8T6 + - 72 MHz + - 64 Kb + - 20 Kb + MultiTech ~~~~~~~~~ diff --git a/docs/platforms/teensy.rst b/docs/platforms/teensy.rst index 80e92de9..a7be6d65 100644 --- a/docs/platforms/teensy.rst +++ b/docs/platforms/teensy.rst @@ -15,7 +15,7 @@ Platform ``teensy`` =================== Teensy is a complete USB-based microcontroller development system, in a very small footprint, capable of implementing many types of projects. All programming is done via the USB port. No special programmer is needed, only a standard USB cable and a PC or Macintosh with a USB port. -For more detailed information please visit `vendor site `_. +For more detailed information please visit `vendor site `_. .. contents:: @@ -31,20 +31,20 @@ Packages * - ``framework-arduinoteensy`` - `Arduino Wiring-based Framework `_ - * - ``tool-teensy`` - - `Teensy Loader `_ - - * - ``toolchain-gccarmnoneeabi`` - - `gcc-arm-embedded `_, `GDB `_ - * - ``framework-mbed`` - `mbed Framework `_ + * - ``tool-scons`` + - `SCons software construction tool `_ + + * - ``tool-teensy`` + - `Teensy Loader `_ + * - ``toolchain-atmelavr`` - `avr-gcc `_, `GDB `_, `AVaRICE `_, `SimulAVR `_ - * - ``ldscripts`` - - `Linker Scripts `_ + * - ``toolchain-gccarmnoneeabi`` + - `gcc-arm-embedded `_, `GDB `_ .. warning:: **Linux Users:** Don't forget to install "udev" rules file diff --git a/docs/platforms/timsp430.rst b/docs/platforms/timsp430.rst index b807d4b1..2218f8c8 100644 --- a/docs/platforms/timsp430.rst +++ b/docs/platforms/timsp430.rst @@ -28,17 +28,20 @@ Packages * - Name - Contents - * - ``toolchain-timsp430`` - - `msp-gcc `_, `GDB `_ - - * - ``tool-mspdebug`` - - `MSPDebug `_ + * - ``framework-arduinomsp430`` + - `Arduino Wiring-based Framework (MSP430 Core) `_ * - ``framework-energiamsp430`` - `Energia Wiring-based Framework (MSP430 Core) `_ - * - ``framework-arduinomsp430`` - - `Arduino Wiring-based Framework (MSP430 Core) `_ + * - ``tool-mspdebug`` + - `MSPDebug `_ + + * - ``tool-scons`` + - `SCons software construction tool `_ + + * - ``toolchain-timsp430`` + - `msp-gcc `_, `GDB `_ .. warning:: **Linux Users:** Don't forget to install "udev" rules file diff --git a/docs/platforms/titiva.rst b/docs/platforms/titiva.rst index 88b960b1..2dae6a51 100644 --- a/docs/platforms/titiva.rst +++ b/docs/platforms/titiva.rst @@ -28,20 +28,20 @@ Packages * - Name - Contents - * - ``ldscripts`` - - `Linker Scripts `_ + * - ``framework-energiativa`` + - `Energia Wiring-based Framework (LM4F Core) `_ * - ``framework-libopencm3`` - `libOpenCM3 Framework `_ - * - ``toolchain-gccarmnoneeabi`` - - `gcc-arm-embedded `_, `GDB `_ - * - ``tool-lm4flash`` - `Flash Programmer `_ - * - ``framework-energiativa`` - - `Energia Wiring-based Framework (LM4F Core) `_ + * - ``tool-scons`` + - `SCons software construction tool `_ + + * - ``toolchain-gccarmnoneeabi`` + - `gcc-arm-embedded `_, `GDB `_ .. warning:: **Linux Users:** Don't forget to install "udev" rules file @@ -61,12 +61,12 @@ Frameworks * - Name - Description - * - :ref:`framework_energia` - - Energia Wiring-based framework enables pretty much anyone to start easily creating microcontroller-based projects and applications. Its easy-to-use libraries and functions provide developers of all experience levels to start blinking LEDs, buzzing buzzers and sensing sensors more quickly than ever before. - * - :ref:`framework_libopencm3` - The libOpenCM3 framework aims to create a free/libre/open-source firmware library for various ARM Cortex-M0(+)/M3/M4 microcontrollers, including ST STM32, Ti Tiva and Stellaris, NXP LPC 11xx, 13xx, 15xx, 17xx parts, Atmel SAM3, Energy Micro EFM32 and others. + * - :ref:`framework_energia` + - Energia Wiring-based framework enables pretty much anyone to start easily creating microcontroller-based projects and applications. Its easy-to-use libraries and functions provide developers of all experience levels to start blinking LEDs, buzzing buzzers and sensing sensors more quickly than ever before. + Boards ------ diff --git a/docs/platforms/windows_x86.rst b/docs/platforms/windows_x86.rst index 690c955b..a35f48d6 100644 --- a/docs/platforms/windows_x86.rst +++ b/docs/platforms/windows_x86.rst @@ -28,5 +28,8 @@ Packages * - Name - Contents + * - ``tool-scons`` + - `SCons software construction tool `_ + * - ``toolchain-gccmingw32`` - `MinGW `_ \ No newline at end of file diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index 4a349cfc..825422cb 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -138,7 +138,7 @@ def platform_list(json_output): "title": p.title, "description": p.description, "version": p.version, - "url": p.manifest.get("url"), + "url": p.vendor_url, "packages": p.get_installed_packages().keys(), 'forDesktop': any([ p.name.startswith(n) for n in ("native", "linux", "windows") diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 6baab0f4..82e41b08 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -333,6 +333,10 @@ class PlatformBase(PlatformPackagesMixin, PlatformRunMixin): def homepage(self): return self._manifest.get("homepage") + @property + def vendor_url(self): + return self._manifest.get("url") + @property def license(self): return self._manifest.get("license") diff --git a/platformio/util.py b/platformio/util.py index 88c5832f..faf6a6bf 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -429,45 +429,6 @@ def get_api_result(path, params=None, data=None): "Please try later.") -@memoized -def _lookup_frameworks(): - frameworks = {} - frameworks_path = join(get_source_dir(), "builder", "scripts", - "frameworks") - - frameworks_list = [f[:-3] for f in os.listdir(frameworks_path) - if not f.startswith("__") and f.endswith(".py")] - for _type in frameworks_list: - script_path = join(frameworks_path, "%s.py" % _type) - with open(script_path) as f: - fcontent = f.read() - assert '"""' in fcontent - _doc_start = fcontent.index('"""') + 3 - fdoc = fcontent[_doc_start:fcontent.index('"""', - _doc_start)].strip() - doclines = [l.strip() for l in fdoc.splitlines() if l.strip()] - frameworks[_type] = { - "name": doclines[0], - "description": " ".join(doclines[1:-1]), - "url": doclines[-1], - "script": script_path - } - return frameworks - - -def get_frameworks(type_=None): - frameworks = _lookup_frameworks() - - if type_ is None: - return frameworks - else: - if type_ not in frameworks: - raise exception.UnknownFramework(type_) - return frameworks[type_] - - return frameworks - - def get_pythonexe_path(): return os.environ.get("PYTHONEXEPATH", normpath(sys.executable)) diff --git a/scripts/docspregen.py b/scripts/docspregen.py index 8b42e242..f977c49a 100644 --- a/scripts/docspregen.py +++ b/scripts/docspregen.py @@ -20,12 +20,17 @@ from sys import path path.append("..") from platformio import util -from platformio.platforms.base import PlatformFactory, get_packages +from platformio.managers.platform import PlatformFactory, PlatformManager + +API_PACKAGES = util.get_api_result("/packages") +API_FRAMEWORKS = util.get_api_result("/frameworks") +BOARDS = PlatformManager().get_installed_boards() +PLATFORM_MANIFESTS = PlatformManager().get_installed() def is_compat_platform_and_framework(platform, framework): p = PlatformFactory.newPlatform(platform) - for pkg in p.get_packages().keys(): + for pkg in p.packages.keys(): if pkg.startswith("framework-%s" % framework): return True return False @@ -56,34 +61,29 @@ def generate_boards(boards): - Flash - RAM""") - for board in sorted(boards): - for type_, data in board.iteritems(): - assert type_ in util.get_boards() - board_ram = float(data['upload']['maximum_ram_size']) / 1024 - lines.append(""" - * - ``{type}`` + for data in sorted(boards, key=lambda item: item['id']): + board_ram = float(data['ram']) / 1024 + lines.append(""" + * - ``{id}`` - `{name} <{url}>`_ - {mcu} - {f_cpu:d} MHz - {rom} Kb - {ram} Kb""".format( - type=type_, - name=data['name'], - url=data['url'], - mcu=data['build']['mcu'].upper(), - f_cpu=int((data['build']['f_cpu'][:-1])) / 1000000, - ram=int(board_ram) if board_ram % 1 == 0 else board_ram, - rom=_round_memory_size( - data['upload']['maximum_size'] / 1024) - )) + id=data['id'], + name=data['name'], + url=data['url'], + mcu=data['mcu'].upper(), + f_cpu=int(data['fcpu']) / 1000000, + ram=int(board_ram) if board_ram % 1 == 0 else board_ram, + rom=_round_memory_size(data['rom'] / 1024))) return "\n".join(lines + [""]) -def generate_packages(platform, packages, is_embedded): - if not packages: +def generate_packages(platform, packagenames, is_embedded): + if not packagenames: return - allpackages = get_packages() lines = [] lines.append(""" Packages @@ -94,17 +94,15 @@ Packages * - Name - Contents""") - for type_, data in packages.iteritems(): - assert type_ in allpackages + for name in sorted(packagenames): + assert name in API_PACKAGES contitems = [ - "`%s <%s>`_" % (name, url) - for name, url in allpackages[type_] + "`{name} <{url}>`_".format(**item) for item in API_PACKAGES[name] ] lines.append(""" - * - ``{type_}`` + * - ``{name}`` - {contents}""".format( - type_=type_, - contents=", ".join(contitems))) + name=name, contents=", ".join(contitems))) if is_embedded: lines.append(""" @@ -134,7 +132,8 @@ def generate_platform(name): print "Processing platform: %s" % name lines = [] - lines.append(""".. Copyright 2014-present PlatformIO + lines.append( + """.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -154,33 +153,31 @@ def generate_platform(name): lines.append("=" * len(_title)) p = PlatformFactory.newPlatform(name) - lines.append(p.get_description()) + lines.append(p.description) lines.append(""" For more detailed information please visit `vendor site <%s>`_.""" % - p.get_vendor_url()) + p.vendor_url) lines.append(""" .. contents::""") # # Packages # - _packages_content = generate_packages(name, p.get_packages(), p.is_embedded()) + _packages_content = generate_packages(name, p.packages.keys(), + p.is_embedded()) if _packages_content: lines.append(_packages_content) # # Frameworks # - _frameworks = util.get_frameworks() _frameworks_lines = [] - for framework in sorted(_frameworks.keys()): - if not is_compat_platform_and_framework(name, framework): + for framework in API_FRAMEWORKS: + if not is_compat_platform_and_framework(name, framework['name']): continue _frameworks_lines.append(""" - * - :ref:`framework_{type_}` - - {description}""".format( - type_=framework, - description=_frameworks[framework]['description'])) + * - :ref:`framework_{name}` + - {description}""".format(**framework)) if _frameworks_lines: lines.append(""" @@ -197,14 +194,13 @@ Frameworks # Boards # vendors = {} - for board, data in util.get_boards().items(): - platform = data['platform'] - vendor = data['vendor'] - if name in platform: + for board in BOARDS: + vendor = board['vendor'] + if name in board['platform']: if vendor in vendors: - vendors[vendor].append({board: data}) + vendors[vendor].append(board) else: - vendors[vendor] = [{board: data}] + vendors[vendor] = [board] if vendors: lines.append(""" @@ -227,9 +223,10 @@ Boards def update_platform_docs(): - for name in PlatformFactory.get_platforms().keys(): - platforms_dir = join(dirname(realpath(__file__)), - "..", "docs", "platforms") + for manifest in PLATFORM_MANIFESTS: + name = manifest['name'] + platforms_dir = join( + dirname(realpath(__file__)), "..", "docs", "platforms") rst_path = join(platforms_dir, "%s.rst" % name) with open(rst_path, "w") as f: f.write(generate_platform(name)) @@ -241,7 +238,8 @@ def generate_framework(type_, data): print "Processing framework: %s" % type_ lines = [] - lines.append(""".. Copyright 2014-present PlatformIO + lines.append( + """.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -276,16 +274,15 @@ Platforms - Description""") _found_platform = False - for platform in sorted(PlatformFactory.get_platforms().keys()): - if not is_compat_platform_and_framework(platform, type_): + for manifest in PLATFORM_MANIFESTS: + if not is_compat_platform_and_framework(manifest['name'], type_): continue _found_platform = True - p = PlatformFactory.newPlatform(platform) + p = PlatformFactory.newPlatform(manifest['name']) lines.append(""" * - :ref:`platform_{type_}` - {description}""".format( - type_=platform, - description=p.get_description())) + type_=manifest['name'], description=p.description)) if not _found_platform: del lines[-1] @@ -300,14 +297,14 @@ Boards """) vendors = {} - for board, data in util.get_boards().items(): + for data in BOARDS: frameworks = data['frameworks'] vendor = data['vendor'] if type_ in frameworks: if vendor in vendors: - vendors[vendor].append({board: data}) + vendors[vendor].append(data) else: - vendors[vendor] = [{board: data}] + vendors[vendor] = [data] for vendor, boards in sorted(vendors.iteritems()): lines.append(str(vendor)) lines.append("~" * len(vendor)) @@ -316,18 +313,18 @@ Boards def update_framework_docs(): - for name, data in util.get_frameworks().items(): - frameworks_dir = join(dirname(realpath(__file__)), - "..", "docs", "frameworks") + for framework in API_FRAMEWORKS: + name = framework['name'] + frameworks_dir = join( + dirname(realpath(__file__)), "..", "docs", "frameworks") rst_path = join(frameworks_dir, "%s.rst" % name) with open(rst_path, "w") as f: - f.write(generate_framework(name, data)) + f.write(generate_framework(name, framework)) if isfile(join(frameworks_dir, "%s_extra.rst" % name)): f.write("\n.. include:: %s_extra.rst\n" % name) def update_create_platform_doc(): - allpackages = get_packages() lines = [] lines.append(""".. _platform_creating_packages: @@ -342,32 +339,28 @@ Packages * - Name - Contents""") - for type_, data in sorted(allpackages.iteritems()): - contitems = [ - "`%s <%s>`_" % (name, url) - for name, url in allpackages[type_] - ] + for name, items in sorted(API_PACKAGES.iteritems()): + contitems = ["`{name} <{url}>`_".format(**item) for item in items] lines.append(""" - * - ``{type_}`` + * - ``{name}`` - {contents}""".format( - type_=type_, - contents=", ".join(contitems))) + name=name, contents=", ".join(contitems))) - with open(join(util.get_source_dir(), "..", "docs", "platforms", - "creating_platform.rst"), "r+") as fp: + with open( + join(util.get_source_dir(), "..", "docs", "platforms", + "creating_platform.rst"), "r+") as fp: content = fp.read() fp.seek(0, 0) - fp.write( - content[:content.index(".. _platform_creating_packages:")] + - "\n".join(lines) + "\n\n" + - content[content.index(".. _platform_creating_manifest_file:"):] - ) + fp.write(content[:content.index(".. _platform_creating_packages:")] + + "\n".join(lines) + "\n\n" + content[content.index( + ".. _platform_creating_manifest_file:"):]) def update_embedded_boards(): lines = [] - lines.append(""".. Copyright 2014-present PlatformIO + lines.append( + """.. Copyright 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -400,20 +393,21 @@ popular embedded boards and IDE. lines.append("") vendors = {} - for board, data in util.get_boards().items(): + for data in BOARDS: vendor = data['vendor'] if vendor in vendors: - vendors[vendor].append({board: data}) + vendors[vendor].append(data) else: - vendors[vendor] = [{board: data}] + vendors[vendor] = [data] for vendor, boards in sorted(vendors.iteritems()): lines.append(str(vendor)) lines.append("~" * len(vendor)) lines.append(generate_boards(boards)) - emboards_rst = join(dirname(realpath(__file__)), - "..", "docs", "platforms", "embedded_boards.rst") + emboards_rst = join( + dirname(realpath(__file__)), "..", "docs", "platforms", + "embedded_boards.rst") with open(emboards_rst, "w") as f: f.write("\n".join(lines)) @@ -424,5 +418,6 @@ def main(): update_framework_docs() update_embedded_boards() + if __name__ == "__main__": sys_exit(main()) diff --git a/scripts/mbed_to_package.py b/scripts/mbed_to_package.py deleted file mode 100644 index 6effd7ea..00000000 --- a/scripts/mbed_to_package.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2014-present PlatformIO -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import argparse -import zipfile -from os import getcwd, listdir, makedirs, mkdir, rename -from os.path import isdir, isfile, join -from shutil import move, rmtree -from sys import exit as sys_exit -from sys import path - -path.append("..") - -from platformio.util import exec_command, get_home_dir - - -def _unzip_generated_file(mbed_dir, output_dir, mcu): - filename = join( - mbed_dir, "build", "export", "MBED_A1_emblocks_%s.zip" % mcu) - variant_dir = join(output_dir, "variant", mcu) - if isfile(filename): - with zipfile.ZipFile(filename) as zfile: - mkdir(variant_dir) - zfile.extractall(variant_dir) - for f in listdir(join(variant_dir, "MBED_A1")): - if not f.lower().startswith("mbed"): - continue - move(join(variant_dir, "MBED_A1", f), variant_dir) - rename(join(variant_dir, "MBED_A1.eix"), - join(variant_dir, "%s.eix" % mcu)) - rmtree(join(variant_dir, "MBED_A1")) - else: - print "Warning! Skipped board: %s" % mcu - - -def buildlib(mbed_dir, mcu, lib="mbed"): - build_command = [ - "python", - join(mbed_dir, "workspace_tools", "build.py"), - "--mcu", mcu, - "-t", "GCC_ARM" - ] - if lib is not "mbed": - build_command.append(lib) - build_result = exec_command(build_command, cwd=getcwd()) - if build_result['returncode'] != 0: - print "* %s doesn't support %s library!" % (mcu, lib) - - -def copylibs(mbed_dir, output_dir): - libs = ["dsp", "fat", "net", "rtos", "usb", "usb_host"] - libs_dir = join(output_dir, "libs") - makedirs(libs_dir) - - print "Moving generated libraries to framework dir..." - for lib in libs: - if lib == "net": - move(join(mbed_dir, "build", lib, "eth"), libs_dir) - continue - move(join(mbed_dir, "build", lib), libs_dir) - - -def main(mbed_dir, output_dir): - print "Starting..." - - path.append(mbed_dir) - from workspace_tools.export import gccarm - - if isdir(output_dir): - print "Deleting previous framework dir..." - rmtree(output_dir) - - settings_file = join(mbed_dir, "workspace_tools", "private_settings.py") - if not isfile(settings_file): - with open(settings_file, "w") as f: - f.write("GCC_ARM_PATH = '%s'" % - join(get_home_dir(), "packages", "toolchain-gccarmnoneeabi", - "bin")) - - makedirs(join(output_dir, "variant")) - mbed_libs = ["--rtos", "--dsp", "--fat", "--eth", "--usb", "--usb_host"] - - for mcu in set(gccarm.GccArm.TARGETS): - print "Processing board: %s" % mcu - buildlib(mbed_dir, mcu) - for lib in mbed_libs: - buildlib(mbed_dir, mcu, lib) - result = exec_command( - ["python", join(mbed_dir, "workspace_tools", "project.py"), - "--mcu", mcu, "-i", "emblocks", "-p", "0", "-b"], cwd=getcwd() - ) - if result['returncode'] != 0: - print "Unable to build the project for %s" % mcu - continue - _unzip_generated_file(mbed_dir, output_dir, mcu) - copylibs(mbed_dir, output_dir) - - with open(join(output_dir, "boards.txt"), "w") as fp: - fp.write("\n".join(sorted(listdir(join(output_dir, "variant"))))) - - print "Complete!" - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--mbed', help="The path to mbed framework") - parser.add_argument('--output', help="The path to output directory") - args = vars(parser.parse_args()) - sys_exit(main(args["mbed"], args["output"])) From 6036c54b05a86a4ecd43717ce964b0b6d606a300 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 3 Sep 2016 17:07:10 +0300 Subject: [PATCH 270/284] Fix broken URL for Teensy site --- docs/platforms/teensy.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/teensy.rst b/docs/platforms/teensy.rst index a7be6d65..ef95fc5b 100644 --- a/docs/platforms/teensy.rst +++ b/docs/platforms/teensy.rst @@ -15,7 +15,7 @@ Platform ``teensy`` =================== Teensy is a complete USB-based microcontroller development system, in a very small footprint, capable of implementing many types of projects. All programming is done via the USB port. No special programmer is needed, only a standard USB cable and a PC or Macintosh with a USB port. -For more detailed information please visit `vendor site `_. +For more detailed information please visit `vendor site `_. .. contents:: From fda7392b8478ef20ce3ed54cda030ae1dcaa148b Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 3 Sep 2016 19:35:40 +0300 Subject: [PATCH 271/284] Rename "espressif" platform to "espressif8266" --- docs/frameworks/arduino.rst | 2 +- docs/frameworks/simba.rst | 2 +- docs/platforms/creating_platform.rst | 2 +- .../{espressif.rst => espressif8266.rst} | 10 +++++----- ...ssif_extra.rst => espressif8266_extra.rst} | 19 ++++++++++++++---- docs/platforms/index.rst | 2 +- docs/projectconf.rst | 8 ++++---- docs/quickstart.rst | 2 +- docs/unit_testing.rst | 4 ++-- docs/userguide/cmd_run.rst | 16 +++++++-------- docs/userguide/cmd_update.rst | 6 +++--- docs/userguide/lib/cmd_list.rst | 2 +- docs/userguide/lib/cmd_show.rst | 2 +- docs/userguide/platforms/cmd_list.rst | 8 ++++---- docs/userguide/platforms/cmd_search.rst | 6 +++--- docs/userguide/platforms/cmd_update.rst | 4 ++-- examples | 2 +- platformio/__init__.py | 2 +- platformio/commands/run.py | 11 ++++++++++ platformio/maintenance.py | 20 +++++++++++++++++-- 20 files changed, 84 insertions(+), 46 deletions(-) rename docs/platforms/{espressif.rst => espressif8266.rst} (98%) rename docs/platforms/{espressif_extra.rst => espressif8266_extra.rst} (94%) diff --git a/docs/frameworks/arduino.rst b/docs/frameworks/arduino.rst index 41de2ea1..d53926b3 100644 --- a/docs/frameworks/arduino.rst +++ b/docs/frameworks/arduino.rst @@ -33,7 +33,7 @@ Platforms * - :ref:`platform_atmelsam` - Atmel | SMART offers Flash- based ARM products based on the ARM Cortex-M0+, Cortex-M3 and Cortex-M4 architectures, ranging from 8KB to 2MB of Flash including a rich peripheral and feature mix. - * - :ref:`platform_espressif` + * - :ref:`platform_espressif8266` - Espressif Systems is a privately held fabless semiconductor company. They provide wireless communications and Wi-Fi chips which are widely used in mobile devices and the Internet of Things applications. * - :ref:`platform_intel_arc32` diff --git a/docs/frameworks/simba.rst b/docs/frameworks/simba.rst index 93512001..99c80e16 100644 --- a/docs/frameworks/simba.rst +++ b/docs/frameworks/simba.rst @@ -33,7 +33,7 @@ Platforms * - :ref:`platform_atmelsam` - Atmel | SMART offers Flash- based ARM products based on the ARM Cortex-M0+, Cortex-M3 and Cortex-M4 architectures, ranging from 8KB to 2MB of Flash including a rich peripheral and feature mix. - * - :ref:`platform_espressif` + * - :ref:`platform_espressif8266` - Espressif Systems is a privately held fabless semiconductor company. They provide wireless communications and Wi-Fi chips which are widely used in mobile devices and the Internet of Things applications. Boards diff --git a/docs/platforms/creating_platform.rst b/docs/platforms/creating_platform.rst index 29ceec6f..44fe48f0 100644 --- a/docs/platforms/creating_platform.rst +++ b/docs/platforms/creating_platform.rst @@ -56,7 +56,7 @@ Packages * - ``framework-arduinoavr`` - `Arduino Wiring-based Framework (AVR Core, 1.6) `_ - * - ``framework-arduinoespressif`` + * - ``framework-arduinoespressif8266`` - `Arduino Wiring-based Framework (ESP8266 Core) `_ * - ``framework-arduinointel`` diff --git a/docs/platforms/espressif.rst b/docs/platforms/espressif8266.rst similarity index 98% rename from docs/platforms/espressif.rst rename to docs/platforms/espressif8266.rst index 0bbe1ba1..8530ea18 100644 --- a/docs/platforms/espressif.rst +++ b/docs/platforms/espressif8266.rst @@ -9,10 +9,10 @@ See the License for the specific language governing permissions and limitations under the License. -.. _platform_espressif: +.. _platform_espressif8266: -Platform ``espressif`` -====================== +Platform ``espressif8266`` +========================== Espressif Systems is a privately held fabless semiconductor company. They provide wireless communications and Wi-Fi chips which are widely used in mobile devices and the Internet of Things applications. For more detailed information please visit `vendor site `_. @@ -28,7 +28,7 @@ Packages * - Name - Contents - * - ``framework-arduinoespressif`` + * - ``framework-arduinoespressif8266`` - `Arduino Wiring-based Framework (ESP8266 Core) `_ * - ``framework-simba`` @@ -386,4 +386,4 @@ WeMos - 4096 Kb - 80 Kb -.. include:: espressif_extra.rst +.. include:: espressif8266_extra.rst diff --git a/docs/platforms/espressif_extra.rst b/docs/platforms/espressif8266_extra.rst similarity index 94% rename from docs/platforms/espressif_extra.rst rename to docs/platforms/espressif8266_extra.rst index 19967507..02db956f 100644 --- a/docs/platforms/espressif_extra.rst +++ b/docs/platforms/espressif8266_extra.rst @@ -181,7 +181,7 @@ For the full list with available options please run .. code-block:: bash - ~/.platformio/packages/framework-arduinoespressif/tools/espota.py -h + ~/.platformio/packages/framework-arduinoespressif8266/tools/espota.py -h Usage: espota.py [options] @@ -221,9 +221,20 @@ Using Arduino Framework with Staging version -------------------------------------------- 1. Clone/Copy `main repository `_ to - :ref:`projectconf_pio_home_dir` + ``packages/framework-arduinoespressif`` - and create new file ``packages/framework-arduinoespressif/version.txt`` - with the new version (for example, ``2.2.0``). + :ref:`projectconf_pio_home_dir` + ``packages/framework-arduinoespressif8266`` + and create new file ``packages/framework-arduinoespressif8266/package.json`` + with the next contents (you can specify own version if you want) + + .. code-block:: json + + { + "description":"Arduino Wiring-based Framework (ESP8266 Core)", + "name":"framework-arduinoespressif8266", + "system":"all", + "url":"https://github.com/esp8266/Arduino", + "version":"1.20300.0" + } + 2. Try to build project 3. If you see build errors, then try to build this project using the same ``stage`` on Arduino IDE diff --git a/docs/platforms/index.rst b/docs/platforms/index.rst index cdfa1003..99261396 100644 --- a/docs/platforms/index.rst +++ b/docs/platforms/index.rst @@ -30,7 +30,7 @@ Embedded atmelavr atmelsam - espressif + espressif8266 freescalekinetis intel_arc32 lattice_ice40 diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 30f82968..9cf240fe 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -208,7 +208,7 @@ Multiple environments are allowed if they are separated with ", " board = uno [env:nodemcu] - platform = espressif + platform = espressif8266 framework = arduino board = nodemcu @@ -342,7 +342,7 @@ format of this option is ``C-like long integer`` value with ``L`` suffix. The 1 Hertz is equal to ``1L``, then 40 Mhz (Mega Hertz) is equal to ``40000000L``. This option isn't available for the all development platforms. The only -:ref:`platform_espressif` supports it. +:ref:`platform_espressif8266` supports it. .. _projectconf_board_flash_mode: @@ -350,7 +350,7 @@ This option isn't available for the all development platforms. The only ^^^^^^^^^^^^^^^^^^^^ Flash chip interface mode. This option isn't available for the all development -platforms. The only :ref:`platform_espressif` supports it. +platforms. The only :ref:`platform_espressif8266` supports it. Build options ~~~~~~~~~~~~~ @@ -682,7 +682,7 @@ This option can be set by global environment variable ^^^^^^^^^^^^^^^^^^^^^^ Specify reset method for "uploader" tool. This option isn't available for all -development platforms. The only :ref:`platform_espressif` supports it. +development platforms. The only :ref:`platform_espressif8266` supports it. Library options ~~~~~~~~~~~~~~~ diff --git a/docs/quickstart.rst b/docs/quickstart.rst index c3e61cfa..83442cb9 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -160,7 +160,7 @@ The result of just generated ``platformio.ini``: board = uno [env:nodemcuv2] - platform = espressif + platform = espressif8266 framework = arduino board = nodemcuv2 diff --git a/docs/unit_testing.rst b/docs/unit_testing.rst index 1ea3e74c..204e0670 100644 --- a/docs/unit_testing.rst +++ b/docs/unit_testing.rst @@ -90,7 +90,7 @@ Workflow board = uno [env:nodemcu] - platform = espressif + platform = espressif8266 framework = arduino board = nodemcuv2 @@ -278,7 +278,7 @@ Source files board = uno [env:nodemcu] - platform = espressif + platform = espressif8266 framework = arduino board = nodemcu diff --git a/docs/userguide/cmd_run.rst b/docs/userguide/cmd_run.rst index b785a7a5..a3b71939 100644 --- a/docs/userguide/cmd_run.rst +++ b/docs/userguide/cmd_run.rst @@ -131,21 +131,21 @@ Examples .. code-block:: bash $ platformio run -e arduino_pro5v -e launchpad_lm4f120 - [Sun Jul 17 00:10:14 2016] Processing nodemcu (platform: espressif, board: nodemcu, framework: arduino) + [Sun Jul 17 00:10:14 2016] Processing nodemcu (platform: espressif8266, board: nodemcu, framework: arduino) -------------------------------------------------------------------------------------------------------- Looking for dependencies... Collecting 29 compatible libraries Processing src/main.cpp Processing .pioenvs/nodemcu/libFrameworkArduinoVariant.a - Processing .platformio/packages/framework-arduinoespressif/cores/esp8266/Esp.cpp + Processing .platformio/packages/framework-arduinoespressif8266/cores/esp8266/Esp.cpp ... - Processing .platformio/packages/framework-arduinoespressif/cores/esp8266/pgmspace.cpp - Processing .platformio/packages/framework-arduinoespressif/cores/esp8266/setjmp.S + Processing .platformio/packages/framework-arduinoespressif8266/cores/esp8266/pgmspace.cpp + Processing .platformio/packages/framework-arduinoespressif8266/cores/esp8266/setjmp.S Processing .pioenvs/nodemcu/libFrameworkArduino.a - Processing .platformio/packages/framework-arduinoespressif/tools/sdk/lib/libmesh.a + Processing .platformio/packages/framework-arduinoespressif8266/tools/sdk/lib/libmesh.a ... - Processing .platformio/packages/framework-arduinoespressif/tools/sdk/lib/libaxtls.a - Processing .platformio/packages/framework-arduinoespressif/tools/sdk/lib/libstdc++.a + Processing .platformio/packages/framework-arduinoespressif8266/tools/sdk/lib/libaxtls.a + Processing .platformio/packages/framework-arduinoespressif8266/tools/sdk/lib/libstdc++.a Processing .pioenvs/nodemcu/firmware.elf Processing .platformio/packages/tool-esptool/esptool Processing .pioenvs/nodemcu/firmware.bin @@ -154,7 +154,7 @@ Examples 221456 884 29496 251836 3d7bc .pioenvs/nodemcu/firmware.elf -3. Process specific target +3. Process specific target (clean project) .. code-block:: bash diff --git a/docs/userguide/cmd_update.rst b/docs/userguide/cmd_update.rst index 137b8172..da5d9327 100644 --- a/docs/userguide/cmd_update.rst +++ b/docs/userguide/cmd_update.rst @@ -93,14 +93,14 @@ Examples Updating toolchain-atmelavr @ 1.40801.0: [Up-to-date] Updating tool-scons @ 2.4.1: [Up-to-date] - Platform espressif + Platform espressif8266 -------- - Updating espressif @ 0.0.0: [Up-to-date] + Updating espressif8266 @ 0.0.0: [Up-to-date] Updating tool-scons @ 2.4.1: [Up-to-date] Updating toolchain-xtensa @ 1.40802.0: [Up-to-date] Updating tool-esptool @ 1.409.0: [Up-to-date] Updating tool-mkspiffs @ 1.102.0: [Up-to-date] - Updating framework-arduinoespressif @ 1.20300.0: [Up-to-date] + Updating framework-arduinoespressif8266 @ 1.20300.0: [Up-to-date] Updating sdk-esp8266 @ 1.10502.0: [Up-to-date] Platform linux_x86_64 diff --git a/docs/userguide/lib/cmd_list.rst b/docs/userguide/lib/cmd_list.rst index db521e2b..b0274fc7 100644 --- a/docs/userguide/lib/cmd_list.rst +++ b/docs/userguide/lib/cmd_list.rst @@ -67,5 +67,5 @@ Examples [ ID ] Name Compatibility "Authors": Description ----------------------------------------------------------------------------------------------------------- [ 4 ] IRremote arduino, atmelavr "Rafi Khan, Ken Shirriff": Send and receive infrared signals with multiple protocols | @2.2.1 - [ 64 ] Json arduino, atmelavr, atmelsam, timsp430, titiva, teensy, freescalekinetis, ststm32, nordicnrf51, nxplpc, espressif, siliconlabsefm32, linux_arm, native, intel_arc32 "Benoit Blanchon": An elegant and efficient JSON library for embedded systems | @5.4.0 + [ 64 ] Json arduino, atmelavr, atmelsam, timsp430, titiva, teensy, freescalekinetis, ststm32, nordicnrf51, nxplpc, espressif8266, siliconlabsefm32, linux_arm, native, intel_arc32 "Benoit Blanchon": An elegant and efficient JSON library for embedded systems | @5.4.0 [ VCS ] TextLCD - "Unknown": hg+https://developer.mbed.org/users/simon/code/TextLCD/ | @308d188a2d3a diff --git a/docs/userguide/lib/cmd_show.rst b/docs/userguide/lib/cmd_show.rst index b1f09e95..b0befe1d 100644 --- a/docs/userguide/lib/cmd_show.rst +++ b/docs/userguide/lib/cmd_show.rst @@ -81,5 +81,5 @@ Examples Authors: Benoit Blanchon http://blog.benoitblanchon.fr Keywords: json, rest, http, web Frameworks: arduino - Platforms: atmelavr, atmelsam, timsp430, titiva, teensy, freescalekinetis, ststm32, nordicnrf51, nxplpc, espressif, siliconlabsefm32, linux_arm, native, intel_arc32 + Platforms: atmelavr, atmelsam, timsp430, titiva, teensy, freescalekinetis, ststm32, nordicnrf51, nxplpc, espressif8266, siliconlabsefm32, linux_arm, native, intel_arc32 Version: 5.4.0 diff --git a/docs/userguide/platforms/cmd_list.rst b/docs/userguide/platforms/cmd_list.rst index 9aacba4c..2ae465c8 100644 --- a/docs/userguide/platforms/cmd_list.rst +++ b/docs/userguide/platforms/cmd_list.rst @@ -62,11 +62,11 @@ Examples Packages: framework-arduinosam, framework-mbed, framework-simba, toolchain-gccarmnoneeabi, tool-bossac Version: 0.0.0 - espressif ~ Espressif - ===================== + espressif8266 ~ Espressif 8266 + ============================== Espressif Systems is a privately held fabless semiconductor company. They provide wireless communications and Wi-Fi chips which are widely used in mobile devices and the Internet of Things applications. - Home: http://platformio.org/platforms/espressif - Packages: framework-simba, tool-esptool, framework-arduinoespressif, sdk-esp8266, toolchain-xtensa + Home: http://platformio.org/platforms/espressif8266 + Packages: framework-simba, tool-esptool, framework-arduinoespressif8266, sdk-esp8266, toolchain-xtensa Version: 0.0.0 ... diff --git a/docs/userguide/platforms/cmd_search.rst b/docs/userguide/platforms/cmd_search.rst index 00a3f63a..9f0dc648 100644 --- a/docs/userguide/platforms/cmd_search.rst +++ b/docs/userguide/platforms/cmd_search.rst @@ -65,12 +65,12 @@ Examples Packages: framework-arduinosam, framework-mbed, framework-simba, toolchain-gccarmnoneeabi, tool-bossac Version: 0.0.0 - espressif ~ Espressif - ===================== + espressif8266 ~ Espressif 8266 + ============================== Espressif Systems is a privately held fabless semiconductor company. They provide wireless communications and Wi-Fi chips which are widely used in mobile devices and the Internet of Things applications. Home: http://platformio.org/platforms/espressif - Packages: framework-simba, tool-esptool, framework-arduinoespressif, sdk-esp8266, toolchain-xtensa + Packages: framework-simba, tool-esptool, framework-arduinoespressif8266, sdk-esp8266, toolchain-xtensa Version: 0.0.0 ... diff --git a/docs/userguide/platforms/cmd_update.rst b/docs/userguide/platforms/cmd_update.rst index 581c2c35..79612b0d 100644 --- a/docs/userguide/platforms/cmd_update.rst +++ b/docs/userguide/platforms/cmd_update.rst @@ -63,14 +63,14 @@ Examples Updating toolchain-atmelavr @ 1.40801.0: [Up-to-date] Updating tool-scons @ 2.4.1: [Up-to-date] - Platform espressif + Platform espressif8266 -------- Updating espressif @ 0.0.0: [Up-to-date] Updating tool-scons @ 2.4.1: [Up-to-date] Updating toolchain-xtensa @ 1.40802.0: [Up-to-date] Updating tool-esptool @ 1.409.0: [Up-to-date] Updating tool-mkspiffs @ 1.102.0: [Up-to-date] - Updating framework-arduinoespressif @ 1.20300.0: [Up-to-date] + Updating framework-arduinoespressif8266 @ 1.20300.0: [Up-to-date] Updating sdk-esp8266 @ 1.10502.0: [Up-to-date] Platform teensy diff --git a/examples b/examples index 5cafb1f7..72b3153a 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 5cafb1f792a240d719036a9b36fb21e6fd746d05 +Subproject commit 72b3153af021232552eafccb247186e5563ed533 diff --git a/platformio/__init__.py b/platformio/__init__.py index 0ba9b049..d1a55985 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0b10") +VERSION = (3, 0, "0b11") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 2bac6643..1b4899da 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -130,6 +130,8 @@ class EnvironmentProcessor(object): RENAMED_OPTIONS = {"lib_use": "lib_force"} + RENAMED_PLATFORMS = {"espressif": "espressif8266"} + def __init__(self, # pylint: disable=R0913 cmd_ctx, name, @@ -191,6 +193,15 @@ class EnvironmentProcessor(object): "`%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( diff --git a/platformio/maintenance.py b/platformio/maintenance.py index 2d2605c4..cb169092 100644 --- a/platformio/maintenance.py +++ b/platformio/maintenance.py @@ -25,6 +25,8 @@ from platformio import __version__, app, exception, telemetry, util from platformio.commands.lib import lib_update as cmd_lib_update from platformio.commands.platform import \ platform_install as cmd_platform_install +from platformio.commands.platform import \ + platform_uninstall as cmd_platform_uninstall from platformio.commands.platform import platform_update as cmd_platform_update from platformio.commands.upgrade import get_latest_version from platformio.managers.lib import LibraryManager @@ -82,7 +84,8 @@ class Upgrader(object): util.pepver_to_semver(to_version)) self._upgraders = [ - (semantic_version.Version("3.0.0-a1"), self._upgrade_to_3_0_0) + (semantic_version.Version("3.0.0-a1"), self._upgrade_to_3_0_0), + (semantic_version.Version("3.0.0-b11"), self._upgrade_to_3_0_0) ] def run(self, ctx): @@ -97,7 +100,8 @@ class Upgrader(object): return all(result) - def _upgrade_to_3_0_0(self, ctx): # pylint: disable=R0201 + @staticmethod + def _upgrade_to_3_0_0(ctx): # convert custom board configuration boards_dir = join(util.get_home_dir(), "boards") if isdir(boards_dir): @@ -115,10 +119,22 @@ class Upgrader(object): # re-install PlatformIO 2.0 development platforms installed_platforms = app.get_state_item("installed_platforms", []) if installed_platforms: + if "espressif" in installed_platforms: + installed_platforms[installed_platforms.index( + "espressif")] = "espressif8266" ctx.invoke(cmd_platform_install, platforms=installed_platforms) return True + @staticmethod + def _upgrade_to_3_0_0b11(ctx): + current_platforms = [m['name'] + for m in PlatformManager().get_installed()] + if "espressif" not in current_platforms: + return + ctx.invoke(cmd_platform_install, platforms=["espressif8266"]) + ctx.invoke(cmd_platform_uninstall, platforms=["espressif"]) + def after_upgrade(ctx): last_version = app.get_state_item("last_version", "0.0.0") From a05d192bebe96fd1be37ba8325af752b9052ab55 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 4 Sep 2016 00:35:47 +0300 Subject: [PATCH 272/284] Implement installing packages/libraries from different archive (with/without manifests) // Resolve #767 --- docs/librarymanager/index.rst | 1 + docs/userguide/lib/cmd_install.rst | 14 ++++++- platformio/__init__.py | 2 +- platformio/commands/lib.py | 2 +- platformio/downloader.py | 21 +++++----- platformio/exception.py | 5 +++ platformio/managers/lib.py | 67 +++++++++++++++++++++++++++++- platformio/managers/package.py | 40 ++++++------------ tests/commands/test_lib.py | 39 ++++++++++++----- 9 files changed, 139 insertions(+), 52 deletions(-) diff --git a/docs/librarymanager/index.rst b/docs/librarymanager/index.rst index 8291dd38..52d8ec87 100644 --- a/docs/librarymanager/index.rst +++ b/docs/librarymanager/index.rst @@ -50,6 +50,7 @@ You can use library ID, Name or even repository URL. For example, Json@~5.6,!=5.4 https://github.com/gioblu/PJON.git@v2.0 https://github.com/me-no-dev/ESPAsyncTCP.git + https://github.com/adafruit/DHT-sensor-library/archive/master.zip Please follow to :ref:`cmd_lib_install` for detailed documentation about possible values. diff --git a/docs/userguide/lib/cmd_install.rst b/docs/userguide/lib/cmd_install.rst index ae130e38..60a846b3 100644 --- a/docs/userguide/lib/cmd_install.rst +++ b/docs/userguide/lib/cmd_install.rst @@ -76,7 +76,7 @@ The ``version`` supports `Semantic Versioning `_ ( * ``>0.1.0,!=0.2.0,<0.3.0`` - any version greater than ``0.1.0``, not equal to ``0.2.0`` and less than ``0.3.0`` -Also, PlatformIO supports installing from local directory or archive. Need +PlatformIO supports installing from local directory or archive. Need to use ``file://`` prefix before local path. Also, directory or archive should contain ``.library.json`` manifest (see :ref:`library_config`). @@ -243,3 +243,15 @@ Examples updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved TextLCD @ 308d188a2d3a has been successfully installed! + +5. Install from archive using URL + +.. code:: + + > platformio lib -g install https://github.com/adafruit/DHT-sensor-library/archive/master.zip + + Library Storage: /storage/dir/... + LibraryManager: Installing master + Downloading [####################################] 100% + Unpacking [####################################] 100% + DHT sensor library @ 1.2.3 has been successfully installed! diff --git a/platformio/__init__.py b/platformio/__init__.py index d1a55985..7e0bed98 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0b11") +VERSION = (3, 0, "0b12") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index 5b72b57d..bbb196b7 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -143,7 +143,7 @@ def echo_liblist_item(item): click.echo( LIBLIST_TPL.format( id=click.style( - str(item.get("id", "VCS")), fg="green"), + str(item.get("id", "-")), fg="green"), name=click.style( item['name'], fg="cyan"), compatibility=click.style( diff --git a/platformio/downloader.py b/platformio/downloader.py index e91f75db..29db6a05 100644 --- a/platformio/downloader.py +++ b/platformio/downloader.py @@ -30,16 +30,6 @@ class FileDownloader(object): CHUNK_SIZE = 1024 def __init__(self, url, dest_dir=None): - self._url = url - self._fname = url.split("/")[-1] - - self._destination = self._fname - if dest_dir: - self.set_destination(join(dest_dir, self._fname)) - - self._progressbar = None - self._request = None - # make connection self._request = requests.get(url, stream=True, @@ -47,6 +37,17 @@ class FileDownloader(object): 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:] + else: + self._fname = url.split("/")[-1] + + self._progressbar = None + self._destination = self._fname + if dest_dir: + self.set_destination(join(dest_dir, self._fname)) + def set_destination(self, destination): self._destination = destination diff --git a/platformio/exception.py b/platformio/exception.py index 4baf827f..5d8f3b76 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -75,6 +75,11 @@ class UnknownPackage(PlatformioException): MESSAGE = "Detected unknown package '{0}'" +class MissingPackageManifest(PlatformioException): + + MESSAGE = "Could not find '{0}' manifest file in the package" + + class UndefinedPackageVersion(PlatformioException): MESSAGE = "Could not find a version that satisfies the requirement '{0}'"\ diff --git a/platformio/managers/lib.py b/platformio/managers/lib.py index 2ebb7c07..2f8e6ad3 100644 --- a/platformio/managers/lib.py +++ b/platformio/managers/lib.py @@ -13,7 +13,9 @@ # limitations under the License. import json -from os.path import join +import os +from hashlib import md5 +from os.path import dirname, join import click import semantic_version @@ -33,6 +35,69 @@ class LibraryManager(BasePkgManager): def manifest_name(self): return ".library.json" + def check_pkg_structure(self, pkg_dir): + try: + return BasePkgManager.check_pkg_structure(self, pkg_dir) + except exception.MissingPackageManifest: + # we will generate manifest automatically + pass + + manifest = { + "name": "Library_" + md5(pkg_dir).hexdigest()[:5], + "version": "0.0.0" + } + manifest_path = self._find_any_manifest(pkg_dir) + if manifest_path: + _manifest = self._parse_manifest(manifest_path) + pkg_dir = dirname(manifest_path) + for key in ("name", "version"): + if key not in _manifest: + _manifest[key] = manifest[key] + manifest = _manifest + else: + for root, dirs, files in os.walk(pkg_dir): + if len(dirs) == 1 and not files: + manifest['name'] = dirs[0] + continue + if dirs or files: + pkg_dir = root + break + + with open(join(pkg_dir, self.manifest_name), "w") as fp: + json.dump(manifest, fp) + + return pkg_dir + + @staticmethod + def _find_any_manifest(pkg_dir): + manifests = ("library.json", "library.properties", "module.json") + for root, _, files in os.walk(pkg_dir): + for manifest in manifests: + if manifest in files: + return join(root, manifest) + return None + + @staticmethod + def _parse_manifest(path): + manifest = {} + if path.endswith(".json"): + return util.load_json(path) + elif path.endswith("library.properties"): + with open(path) as fp: + for line in fp.readlines(): + if "=" not in line: + continue + key, value = line.split("=", 1) + manifest[key.strip()] = value.strip() + manifest['frameworks'] = ["arduino"] + if "author" in manifest: + manifest['authors'] = [{"name": manifest['author']}] + del manifest['author'] + if "sentence" in manifest: + manifest['description'] = manifest['sentence'] + del manifest['sentence'] + return manifest + @staticmethod def normalize_dependencies(dependencies): if not dependencies: diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 14e9644f..c536a9e6 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -15,7 +15,7 @@ import json import os from os.path import basename, dirname, isdir, isfile, islink, join -from shutil import copyfile, copytree +from shutil import copytree from tempfile import mkdtemp import click @@ -147,32 +147,13 @@ class PkgInstallerMixin(object): def check_pkg_structure(self, pkg_dir): if self.manifest_exists(pkg_dir): - return True + return pkg_dir for root, _, _ in os.walk(pkg_dir): - if not self.manifest_exists(root): - continue - # copy contents to the root of package directory - for item in os.listdir(root): - item_path = join(root, item) - if isfile(item_path): - copyfile(item_path, join(pkg_dir, item)) - elif isdir(item_path): - copytree(item_path, join(pkg_dir, item), symlinks=True) - # remove not used contents - while True: - util.rmtree_(root) - root = dirname(root) - if root == pkg_dir: - break - break + if self.manifest_exists(root): + return root - if self.manifest_exists(pkg_dir): - return True - - raise exception.PlatformioException( - "Could not find '%s' manifest file in the package" % - self.manifest_name) + raise exception.MissingPackageManifest(self.manifest_name) def _install_from_piorepo(self, name, requirements): pkg_dir = None @@ -226,8 +207,8 @@ class PkgInstallerMixin(object): "requirements": requirements }, fp) - self.check_pkg_structure(tmp_dir) - pkg_dir = self._install_from_tmp_dir(tmp_dir, requirements) + pkg_dir = self.check_pkg_structure(tmp_dir) + pkg_dir = self._install_from_tmp_dir(pkg_dir, requirements) finally: if isdir(tmp_dir): util.rmtree_(tmp_dir) @@ -554,7 +535,12 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): manifest['version'] = vcs.get_current_revision() json.dump(manifest, fp) else: - latest_version = self.get_latest_repo_version(name, requirements) + latest_version = None + try: + latest_version = self.get_latest_repo_version(name, + requirements) + except exception.PlatformioException: + pass if not latest_version: click.echo("[%s]" % (click.style("Unknown", fg="yellow"))) return diff --git a/tests/commands/test_lib.py b/tests/commands/test_lib.py index 0daae542..9e8f1c26 100644 --- a/tests/commands/test_lib.py +++ b/tests/commands/test_lib.py @@ -36,15 +36,31 @@ def test_search(clirunner, validate_cliresult): def test_global_install_registry(clirunner, validate_cliresult, isolated_pio_home): - result = clirunner.invoke(cmd_lib, - ["-g", "install", "58", "OneWire", - "ArduinoJson@5.4.0", "ArduinoJson@>5.4"]) + result = clirunner.invoke(cmd_lib, [ + "-g", "install", "58", "OneWire", + "http://dl.platformio.org/libraries/archives/3/3756.tar.gz", + "ArduinoJson@5.4.0", "ArduinoJson@>5.4" + ]) validate_cliresult(result) items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] - items2 = ["DHT22_ID58", "ArduinoJson_ID64", "Json_ID64", "OneWire_ID1"] + items2 = ["DHT22_ID58", "ArduinoJson_ID64", "Json_ID64", "OneWire_ID1", + "ESPAsyncTCP_ID305"] assert set(items1) == set(items2) +def test_global_install_archive(clirunner, validate_cliresult, + isolated_pio_home): + result = clirunner.invoke(cmd_lib, [ + "-g", "install", "https://github.com/adafruit/Adafruit-ST7735-Library/" + "archive/master.zip", + "http://www.airspayce.com/mikem/arduino/RadioHead/RadioHead-1.62.zip" + ]) + validate_cliresult(result) + items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] + items2 = ["Adafruit ST7735 Library", "RadioHead"] + assert set(items1) >= set(items2) + + def test_global_install_repository(clirunner, validate_cliresult, isolated_pio_home): result = clirunner.invoke( @@ -54,7 +70,6 @@ def test_global_install_repository(clirunner, validate_cliresult, "https://github.com/gioblu/PJON.git#3.0", "https://gitlab.com/ivankravets/rs485-nodeproto.git", # "https://developer.mbed.org/users/simon/code/TextLCD/", - "http://dl.platformio.org/libraries/archives/3/3756.tar.gz", "knolleary/pubsubclient"]) validate_cliresult(result) items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] @@ -73,7 +88,8 @@ def test_global_lib_list(clirunner, validate_cliresult, isolated_pio_home): for n in ("PJON", "git+https://github.com/knolleary/pubsubclient")]) items1 = [i['name'] for i in json.loads(result.output)] items2 = ["OneWire", "DHT22", "PJON", "ESPAsyncTCP", "Json", "ArduinoJson", - "pubsubclient", "rs485-nodeproto"] + "pubsubclient", "rs485-nodeproto", "Adafruit ST7735 Library", + "RadioHead"] assert set(items1) == set(items2) @@ -102,12 +118,13 @@ def test_global_lib_update(clirunner, validate_cliresult, isolated_pio_home): def test_global_lib_uninstall(clirunner, validate_cliresult, isolated_pio_home): - result = clirunner.invoke( - cmd_lib, ["-g", "uninstall", "1", "ArduinoJson@!=5.4.0", "TextLCD"]) + result = clirunner.invoke(cmd_lib, + ["-g", "uninstall", "1", "ArduinoJson@!=5.4.0", + "TextLCD", "Adafruit ST7735 Library"]) validate_cliresult(result) items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()] items2 = ["DHT22_ID58", "Json_ID64", "ESPAsyncTCP_ID305", "pubsubclient", - "PJON", "rs485-nodeproto"] + "PJON", "rs485-nodeproto", "RadioHead_ID124"] assert set(items1) == set(items2) @@ -121,8 +138,8 @@ def test_project_lib_complex(clirunner, validate_cliresult, tmpdir): result = clirunner.invoke(cmd_lib, ["install", "54", "ArduinoJson"]) validate_cliresult(result) items1 = [d.basename - for d in tmpdir.join(basename(util.get_projectlibdeps_dir( - ))).listdir()] + for d in tmpdir.join(basename(util.get_projectlibdeps_dir())) + .listdir()] items2 = ["DallasTemperature_ID54", "OneWire_ID1", "ArduinoJson_ID64"] assert set(items1) == set(items2) From 0f300a24a1c42f82bb823376bffa5af6d8dec7a2 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 4 Sep 2016 12:03:57 +0300 Subject: [PATCH 273/284] Fix issue with archive downloader --- platformio/__init__.py | 2 +- platformio/downloader.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/platformio/__init__.py b/platformio/__init__.py index 7e0bed98..c435e6d2 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0b12") +VERSION = (3, 0, "0b13") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/downloader.py b/platformio/downloader.py index 29db6a05..f35aeda4 100644 --- a/platformio/downloader.py +++ b/platformio/downloader.py @@ -39,7 +39,8 @@ class FileDownloader(object): disposition = self._request.headers.get("content-disposition") if disposition and "filename=" in disposition: - self._fname = disposition[disposition.index("filename=") + 9:] + self._fname = disposition[disposition.index("filename=") + + 9:].replace('"', "").replace("'", "") else: self._fname = url.split("/")[-1] From 93aa0c2b081a93ae1d2cdf0e60739503d4759a13 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sun, 4 Sep 2016 18:25:28 +0300 Subject: [PATCH 274/284] Test PlatformIO 3.0 packages --- tests/test_pkgmanifest.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/test_pkgmanifest.py b/tests/test_pkgmanifest.py index 476666a0..8793f9ab 100644 --- a/tests/test_pkgmanifest.py +++ b/tests/test_pkgmanifest.py @@ -15,13 +15,12 @@ import pytest import requests -from platformio.util import get_api_result - def pytest_generate_tests(metafunc): if "package_data" not in metafunc.fixturenames: return - pkgs_manifest = get_api_result("/packages/manifest") + pkgs_manifest = requests.get( + "https://dl.bintray.com/platformio/dl-packages/manifest.json").json() assert isinstance(pkgs_manifest, dict) packages = [] for _, variants in pkgs_manifest.iteritems(): From f6491b22858d5875a55fef9ef3f3e8af503d3f3b Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 7 Sep 2016 13:47:42 +0300 Subject: [PATCH 275/284] Add links to PlatformIO Plus --- README.rst | 18 ++++++++++-------- docs/_static/extra.css | 10 ++++++++++ docs/_templates/footer.html | 2 +- docs/index.rst | 14 ++++++++++---- .../unit-testing.rst} | 0 platformio/__init__.py | 2 +- 6 files changed, 32 insertions(+), 14 deletions(-) rename docs/{unit_testing.rst => plus/unit-testing.rst} (100%) diff --git a/README.rst b/README.rst index b0d469df..346a1b4b 100644 --- a/README.rst +++ b/README.rst @@ -25,25 +25,26 @@ PlatformIO :alt: Donate for PlatformIO.Org :target: http://platformio.org/donate - -`Home `_ | -`IDE `_ | +**Quick Links:** `Home Page `_ | +`PlatformIO Plus `_ | +`PlatformIO IDE `_ | `Project Examples `_ | `Docs `_ | -`Twitter `_ | +`Donate `_ | +`Contact Us `_ + +**Social:** `Twitter `_ | `Facebook `_ | `Hackaday `_ | `Bintray `_ | `Community `_ | -`Donate `_ | -`Contact Us `_ .. image:: https://raw.githubusercontent.com/platformio/platformio/develop/docs/_static/platformio-logo.png :target: http://platformio.org `PlatformIO `_ is an open source ecosystem for IoT development. Cross-platform build system and library manager. Continuous and -IDE integration. Arduino and MBED compatible. Ready for Cloud compiling. +IDE integration. Arduino, ESP8266 and ARM mbed compatible * **PlatformIO IDE** - The next-generation integrated development environment for IoT. C/C++ Intelligent Code Completion and Smart Code Linter for the super-fast coding. @@ -68,9 +69,10 @@ TI MSP430 & Tiva, Teensy, Arduino, mbed, libOpenCM3, etc.* .. image:: https://raw.githubusercontent.com/platformio/platformio/develop/docs/_static/platformio-demo-wiring.gif :target: http://platformio.org +* `PlatformIO Plus and professional solutions `_ * `PlatformIO IDE `_ * `Get Started `_ -* `Web 2.0 Library Search `_ +* `Library Search and Registry `_ * `Development Platforms `_ * `Frameworks `_ * `Embedded Boards Explorer `_ diff --git a/docs/_static/extra.css b/docs/_static/extra.css index 6c61b363..a422d397 100644 --- a/docs/_static/extra.css +++ b/docs/_static/extra.css @@ -292,6 +292,16 @@ nav { } } +.navbar-inverse .navbar-nav > li.nav-pioplus > a, +.navbar-inverse .navbar-nav > li.nav-pioplus > a:visited +{ + color: #ff6600; +} + +.navbar-inverse .navbar-nav > li.nav-pioplus > a:hover { + color: #ff9900; +} + .top-banner { display: block; padding: 10px 20px; diff --git a/docs/_templates/footer.html b/docs/_templates/footer.html index 6c39a60e..6ac869f3 100644 --- a/docs/_templates/footer.html +++ b/docs/_templates/footer.html @@ -27,7 +27,7 @@ diff --git a/docs/index.rst b/docs/index.rst index abea5247..9116b5c5 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -13,7 +13,7 @@ PlatformIO is an open source ecosystem for IoT development ========================================================== **Cross-platform build system and library manager. Continuous and IDE -integration. Arduino and MBED compatible. Ready for Cloud compiling.** +integration. Arduino, ESP8266 and ARM mbed compatible.** * **PlatformIO IDE** - The next-generation integrated development environment for IoT. C/C++ Intelligent Code Completion and Smart Code Linter for the super-fast coding. @@ -35,9 +35,10 @@ integration. Arduino and MBED compatible. Ready for Cloud compiling.** Silicon Labs EFM32, ST STM32, TI MSP430 & Tiva, Teensy, Arduino, mbed, libOpenCM3, etc.* -* `Website `_ +* `Home Page `_ +* `PlatformIO Plus and professional solutions `_ * :ref:`ide_atom` -* `Web 2.0 Library Search `_ | +* `Library Search and Registry `_ | `Embedded Boards Explorer `_ * `Project Examples `_ * `Source Code `_ | @@ -111,7 +112,12 @@ Contents platforms/embedded_boards frameworks/index platforms/custom_platform_and_board - unit_testing + +.. toctree:: + :caption: PlatformIO Plus + :maxdepth: 3 + + plus/unit-testing .. toctree:: :caption: Library Manager diff --git a/docs/unit_testing.rst b/docs/plus/unit-testing.rst similarity index 100% rename from docs/unit_testing.rst rename to docs/plus/unit-testing.rst diff --git a/platformio/__init__.py b/platformio/__init__.py index c435e6d2..834b821e 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -21,7 +21,7 @@ __title__ = "platformio" __description__ = ("An open source ecosystem for IoT development. " "Cross-platform build system and library manager. " "Continuous and IDE integration. " - "Arduino and MBED compatible. Ready for Cloud compiling.") + "Arduino, ESP8266 and ARM mbed compatible") __url__ = "http://platformio.org" __author__ = "Ivan Kravets" From 9e3b2a381e240480d4563e96eeb5d97568cc67d6 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 7 Sep 2016 13:50:47 +0300 Subject: [PATCH 276/284] Add PlatformIO Plus badge --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 346a1b4b..53990a72 100644 --- a/README.rst +++ b/README.rst @@ -21,7 +21,7 @@ PlatformIO .. image:: https://img.shields.io/community/PlatformIO.png :alt: Community Forums :target: https://community.platformio.org -.. image:: https://img.shields.io/donate/PlatformIO.png?color=yellow +.. image:: https://img.shields.io/PlatformIO/Plus.png?color=orange :alt: Donate for PlatformIO.Org :target: http://platformio.org/donate From f525165758f2bf90a2cde04ae9d1f82954528c1f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 7 Sep 2016 13:51:59 +0300 Subject: [PATCH 277/284] Update PIO Plus badge title and link --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 53990a72..0505c762 100644 --- a/README.rst +++ b/README.rst @@ -22,8 +22,8 @@ PlatformIO :alt: Community Forums :target: https://community.platformio.org .. image:: https://img.shields.io/PlatformIO/Plus.png?color=orange - :alt: Donate for PlatformIO.Org - :target: http://platformio.org/donate + :alt: PlatformIO Plus: Professional solutions for an awesome open source PlatformIO ecosystem + :target: https://pioplus.com **Quick Links:** `Home Page `_ | `PlatformIO Plus `_ | From 960de87585cb140ba7ab04b7e634aa86a56d764e Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 7 Sep 2016 15:46:48 +0300 Subject: [PATCH 278/284] Add Unit Testing Demo --- docs/_static/pioplus-unit-testing-demo.png | Bin 0 -> 162980 bytes docs/plus/unit-testing.rst | 147 ++++++++++++--------- 2 files changed, 85 insertions(+), 62 deletions(-) create mode 100644 docs/_static/pioplus-unit-testing-demo.png diff --git a/docs/_static/pioplus-unit-testing-demo.png b/docs/_static/pioplus-unit-testing-demo.png new file mode 100644 index 0000000000000000000000000000000000000000..d34dad140253dd19af97518f75e2add5796fd5f1 GIT binary patch literal 162980 zcmeAS@N?(olHy`uVBq!ia0y~yU^>UZz!cBH#K6GtV9W8j3=9mCC9V-A!TD(=<%vb9 z42~)JNvR5+xryniL8*x;m4zo$Z5SAsRWd^&N+NuHtdjF{^%6m9^eS=-7(l?rzM>#8 zIXksPAt^OIGtXA({qFrr3YjUkO5vuy2EGN(sTr9bRYj@6RemAKRoTgwDN6Qs3N{s1 z6}bhusU?XD6}dTi#a0!zN?>!X@`|lM!um=IU?nBlwn`93Mfe6NIOi9oDwygS>n0l* z8Y-BX=^2`snwc5uC>R+S8tEGt=^L2o8k$&{npqi{D?ovgoq|nKN}5%WiyPFgqLegS zrHqo20xNy}^73-Ma$~*xqI7*jOG`_T8Ae9BMJZ{z#g%y_i50qe#mX=fTvCgZi!uvJ zGV}8kKqe+8<(HP&Dk(vYt;j8a8=F@Q4W{J$T>Xl~0)0b01CW;>e$6fL^~J9=Hy5tD zxFjeQ;a;o;7l%|9r0NHy7U!21C8q|ZrYVEmRAA*?l$uzQUlfv`p92fUfQG2Fqm13SQjv*Dd-o$do^hW--_rH64U%IZ-$|;JZ z;xmT-3cG;@x*FWbM&wIY}d*!>@TL!m( z&wHP4x6JSPckAcd=iIkEU-Vv_foT*#L!jw9YuAp32m7V_{w}Y3ny-o}HJA`W7el$}m{2*fsUn z?u5e1Cr_>?-@R)EVkirG6)$D&6G9$-%+#@8O5}^&x7LRn?EGtIB%b+IvMd?B|8l z-(~uR`EMq&dhaw1I+edR`lqcyPnGn_hwsZ2Kb)QU?#pSnFXyXnzB$X9c)B}HRQ%P{ zEWY1sZv4DGamkXFB_c0g9g&dV*jM{4{rSlsJGQK^SGL(7BC+0%J+;#P2>UN%gOY#u zWHOxmj@|kw`!`+I#s1lXwr=-n)*RJ-H>c@Zf6uR*|7P*&w~QZtWaU=z6`j~OBVm&V z#I^3dmF=nFWgq)F7 zuxQI^ac}uC)$z>wsCRpr|J*txzhuSVq$&GXEuZ%NlXm6J4Xj^3<{$rd@^s&`Up+lm zJfXQV`A*j~57wJ+>EP!0x7+cgrk9do*gTtKXE|Q8)oW{T~yXB{Gy-j1u=x$*ByzolIo~;ZIc0RpgdUL1l9^1>s*}t~l z**tru_Xo}Boaejmwb<9pT{U^;!ri(urf&0IaP3Hj(AC;yVIJn7nJgSdZ! zyNgmRZ{D04y{vju`oxaA>HhC;?)WUycm3bSz8!^c_6KcR_n?|{=Ej)w-x<$W-mg*7 zzh|0ICG)x3_u0oIB2V5uoO_$$)k)iXn-^~lY|Pio|79on-Ba&aZ4N_4(6O&Kzx_?G zUZ=fh-@lV{bwZl{XL($y`_3(qmAh{BufLurV=wqz`1Hk3^X{2bG41z@rsru**;Ool z<+jqINaudH`P(nAx#(oC*%%fP&EdX2Q!7L8>Ke_ZhR=f-{szyFm8$Z3xh(8iugqS> ze-|a@9y89_GT(IVg*l(AyC2BDah_YHv|^#9nPI5$(M*ne|DNA@tNi`jvxd6MXOFXc zyzu^B?r|pEm9_lj-H&HKB(Hn9F_C-udmc;sUG>w&(*N5Qe3ANGIQi{^eHZ#CGF9c- z?F%^dd)KtZ~cb zmotU4$E9_lBKlCu%4X}aFw+`erv|XpZ7kC`}(eti;7>a;rw7xv2|Iyx5tU66TJ_t znQW{4@x`@hTkUP>M`T%Y`@Y{0t7@y`dFH-FcJt59rRR+IevsR^Fg;7InN={?J-6(-g{tqyC7)8`3#Mv-+SJ_-KE{f_lD_)-K2x|Zmhdw?i!{Z*_gLH>9ErB z_cDcbAr8~UB>&40vxJI#`mG^pw+{px$>ZFScC z_^l6Kd}uw)?EWjq?%h_aMe~)OKR6?Qu5O>wvewpn)z&+AeS4P>QJV8OsqXQexzC+< zEjT%4xqjs7z10r|3oqRMbZt`H>zVP--<;uko5WFHF-LCmwC{Dt9+|qcul@f1Iiu0} z#;VnYni+aA;!3YWazneW>}p$caC^-Aq**VQm0tI;IBe8AYh@t+>-Dc@CGR!Aef0am zs`MKRq}J_=&!}4CxUGB3mEFRf@0-8A6JKPx%&;owQKwa()VzcD&%8;CTAWZnwdwiI z@R#ReLv)2c{JAuBmY@8ri>s!k-we-~&VTmR)K_O-ANDAH_R=xvRc!!w{N|RrX>++_ ze#}Zd9qMbl!S!alTh+QxOEWnC#>Dc^IUl-J?4l*}bpD_JD$71**;bi63qBn&OHO!; zgLa&Q_toP;-~Vjxo~0|5Y*@F9b=sqitFpgtjwqRT^?j&}?7f;JNek~?5?HTwylGbE zQqjoD&Xtjiem55tGbfzg(U5$ZPgdf0)~xRve7q~JJ5MeH&uqq@SIs{pB-si~xv%l>qxJ+ghp6Au|2XAk|Gz0;Iz`QG zr?S6Aitxfvkw1jUTvUIzq zCjDAbmelpgGP-7S*uN)l-!RzbKQv67zuRtCVdBLuy`7<}80KC0EH88O+u=V<3|z<9 z<=p4hi$1iS!~JgS4xP0Njh#wZO5c17I=|tqNrrV*LO8>(-&L~%cE+=vZ#?+wPl{vq zE8Bhl*DdB1nYy0E_jlOYeV6WR%KkrL;oh_ynfih|ZO<>P4IlxJ|zlu(>VV^sUgxRR#G;-!AK=m6R?na}zu}^SY3K%C)*H6-7^D)N@+4stioTHpKA87aSX1%ib!B6*EojZ#Rzy^x>RpZxJL~3hi?5Nrf4}_0rg^pYQ9pk6*nW?ae95@eYgOZmj4q#iC&qvOs-Ig` ztX19_s5<>G*DC*c#uKdOP13BoC9Y@1$M%oIZVuU*-MuEz7^|_f6qv8kfboFOD{0{WCY< zv|noXjX8f8dmZ!+J9YC#*wznnLA82~%^w~)+G_2Y^*QSJkEnN+=RTV&UHAQQCjG;v zxW9H?JTCLhuQ7A&{7}l~_1Dw)YxnMoC#$kVF0PA>I>mjtVCm~!pZ8?%$kK^Ab!%PRM(r!P?6YRMmI;K)ulTt$>g(k@Yo}B*#)hvI{&+rgqS)C} z{8~>+-_Ogs_dsWAwu}4Opo9Nfbwtycw#B}1ej0aj{pzfp2Y*KN5*9Kr=e$~qOwA@#XC>_UCv}16jiIUWcePi+%N1II^O?Y zoX|@=U7Oe~61i&G@h=Z2SN-yk+#MD5!KQ7EKp*S##V_TrxX(@(-xPb(>9Ua56}^3O zW^uY}bX)HQ%r>^3HZ4KNR6grmRxrsgkRm?w+N3C62XTQ4NHM^?kE8Ef2y}Nnu z==zCGXUdgM=bsRD&-%bJh5cJ(8m>L~wM+80ob|W=yZV>TJU*eaG1q86xBL!)9?xmD zw@)7Be6zFsQ<~(2EoEiw>hr$5yuXaWzUsX}`r)GTmp3C9C-30DV0HH9hBMC3@AL#- zWIc2EN6g*OxCe_9Htf6dZ8v|HpSWkEID@$3bkCyu@8|5>c2audo5T55DZ8x??|Ucu z$>(_7oDlsF7Xvh|zWeQWwA(~(L5%LT#;S}p$Ddm-?_8UIq2l@>bI~i;zwbZ4CCBgX zXB4d?0;uQOzlT~^xr zCG@yw?yMkNgT?x%yqcNz9<$oAz3)$W_~BWvL(h0;`W2fms?c1_tZY$!n5%s5W@C5P z&&nD-D;Z2Pr=NCccs}9ZgBYR9k6wtsahlufy>I2)*ZFRZo2IYVyuN~Sp4v)obq&)8 zcF!M8>fTygJ)1G$S5RrVNfJ8o}t_iqufLYerz6yG^ z`waKjTTZLPJxmTS&x#Y>_}8(rw$#VjOXuzW z_|8VG3f$a9M13RI;mn~~Q zb3RQsDEIyTWroP=Up{GNPCMFnh%nR&7kx^ptY!|mt$q8@Z;ABh)uL5rqUZZxzVP1j zsO*jD4o@E(bQIXNy!})7F0LcI;uB}>-P;)t)Y@~`Ic-#_=;f|gbUC8_)vc$^P4A5#em`loCu(YM+2u>csmslJRbNkO zXlQsKUw37~(ldP0Hbr-SY*5Hg-Q7Na|NPx^KZSoOJi;JfJvD~?%R`_2d0Dpt7Q0tJ zUC)>Ik5R7d4+Z_Pe2C-Y*C@6P`6%SZ?!IBKTX*c- zSGMMJ8{Fr2-wr>|^C4lAl7U9XlL-y$&dhIb>%HgE&r=L-l32>jXnP*AYi?st&cp{Z{sOV@O|-?O*bK4-_A$!8z@t=sfP*HE^;Leh`( z@9b>{-}6f(d41XT<;|P9cNCX>%-pH1tzCNh)OuNuUjl#l8)^(K85s}OE8eMX-d&Ot zRrud4Cr0Wc8zTmAe7x}PgL!_5o0s=W-8sKFdGn?o?f(BiX71#dyubKqa^%O$Y~T2$ z%#Uu5eyuK^@>FG2K7Z&GZ{u})#QlTv4j=oueP_YW2WyvDx14SK{POj=)YuzyJoxv{ z7Vnz(k8|G#Zi!dVZrGUb|B)}D-ru0#%)Dn;X|Z8l*~T9q>;3;_{$}eh%`Q^>{_OXc z&Wm{B! zFnitDQd{%sXzU$tf5T48O?%!vc``Zu^0t4L`qz%CJXc%)C9mK+BYSFPWhLh+{c187?{iSfrXTrpx(+}J5Nso6P55M-yP}a`=EJ+a3PuD$D(^ZFLdq$jzi(U2@Bg#l z*hl;Pv{2EhU8~yi%RlbizWBEHdX=L1gp|Cm3pbxOUi^Po!_4UN(s!TE?3fso78X0l z+TMKS@7wBcpB>Op_kC$){8Ki)!zTX>w+cho@BD=v=Z;Uav-x>ga@9|n--{L-S4iJ} z{Ym1fRBhs0hNIdHOM;&5)?OUe9W8!Y~v z+hEc6_*rmVT;$JBg4JE}=E`Tz&NzPfrdy6iDW9jpgPA>B#JA14wf(@pZQX4jcwgSE zlxa^X@9&6hlC-MG@v@%3=F9md5y$LjJ*dpl3$o7Ee{SgiV&mLm+loJnxFzZWZ>U#Z zpCoE+eBs5*+lOUXgQETB+;3ePk$2{&mR_*w0uBGN_P}kt9YJoDeCG1UJ~Mo|Iq%#2 zQ0{9>o^rga`1sJg%<7TvQr(a}D@9mW`R>2h8ev|1{$27T*1cW(0v(P%Us*Z(;c3=~ z1$L9lGVC`0cHX`0?XjA9kQ^Kpf7+~jH1orwCw~IZCGP&z zxUR+WcHM`>?8=J|>rXYR-t#?qe)Z3e&pQib zP4+BYd2?Rk@zT)L^%-)9f>%1_?PMz6@@$UV&ok$p(_%T^?3&d2)@kO?$2As*ZEOy| zYw}839+X%)-% zqQKn5*KH1)Jxu+c7rrXu6tP}kf2Y)S{rc+@*YhZ@c)WsfiNn#>n`gJ}-tMmb!})ez zoP7PA%lCXXS09@tZ&1Zrm9Bz~dX+r&AB*%l_7we%`z}TmKAO=DTN)xu4%zy14N~#JvvZPjB|KTUqx< zeto^sx*%L)la|(vr^ov8t=f(*7nz`V!DLNnRh+gVxT zXhCw2SkIL1&HI*#YMi@zUchnar^N0<9EXIwBqg@JHomey z$;!m*4ka$wcGAhWIU3wIOA_5@zb*Yc*>jS3%QT( zd6jnk@bS%}=JVzFmMNIl7GIgPqbPRqGPhG1m(JAWz5n;{#@$(IVpUOgi+}GnvH$(v zQDd2P-?Rrl9|S6VRD@srN$z~!uvIaRTf=SMH{GrCrizu!*s{KSw)M;D^Ik@6FBU&J z{~{0j$|9X(>zdvMTeamim$~}2OCOxE>njB_4)--*ut;=VDxO(ZE-+o?M z#SoeG&Z=e!e~kFTQ>7mhInFri=1+}XdaEt%#p{!SY2SF?#cry8YG~pdyKK@6G1ap& zmeOHDoqoMH?yk8f+w-5L{b9lGYDX0>6Pg`w`6XY=OH{Tk5wYF)j= zRhE$6M4g@l(`_%Fq(<|s{^%UhyFVoL*&mcbhAFzRV7@V^>$-T?tII|Ajr=4v$f*e zlFOlgpPH=IUbcMy{Oz14WF>9Xxf}fam7_0inO<%E^J{L;ydRF?PBzsS)R!>aiMwQ5 zV$FN2SMJBcA8(%?czl`f?f+L#P2NA8xium#xM(xa#`3(|-w$4lH>gg}R~J3JoHOmm zmuuUvw>_`<{;~QlZ$Y;y!>c14lbwD^?l~tRCp4M=mtRQ0uAcCfla}6fPR_hg#xpDN z)1tGk&WoGO`J$vRUtRt4^^q4}XMO%yl)YTzhMBQgl$B{+0^b&qCEDKwkNjBB`sUD@ zCGmShHpTopKe^%6pH{oYk1`UzRwhhXE$$I+r?POv{FkOY+M17y)?SsK71%fDy5Gd} z6?Lx|)9e(4UtHQ=KU-32vdNUPec``cj(pZ(Ue(opxqcdBm-yjbmT3v$vA1qZ{*xp`ZgITe7})paSRmh#K)00G zruM{petbRQ-yg=bE^cqHVKOd`@bFJ7Jn3MHh0VQAAFgFz zbzeMJHFziceyVMvWaQoB#|wi@RkwRRJuo?ay8ZT9j}oS2CgkPqWjpHByEv42mycb4 zSk$Y~t6_ZFoV)b`SUK|Vo_}yva?hh*HD}jZXn5TJmFt#q=HWsO;dxv$W0hTJ#%3P5 z7!~_7s`d-(y~W=SU1XN9=Pug!=ACf9diBENYbL&Rl1nJ~Eq0Fgi2vy;VjrhmX5Di& zhRtpw>Yb_W)Ic z<$C_bDM`^0SJMryN*rfekQK9Oi+e;4Z-#kVLioPw`O43%R~p_-;mq2+;Q0 z<a#!+pvT`-H$8Jxbx2tlgzm}KWNFyV~ch+{>kH8r{>F}TCuvR)c4;XK4a%;uihOv zb~yEf{l$Hg)YbQ`{+in1W!hh8aK-gX|B9tsC+cnK-d?9Fy8Zl-h5Jh~^4ES{V9;N_ zG<$)5YQ6KF8CQcITgBHdj42KH8tf)nSh7m#gvOP1b(MAcNi%P4esWv&cF_@A{^OIp zS|3J;$NZx=bgydZY}Il=0n_uJlD zrbN~}`?TO$h24eZNmci6JygwTTeIZUw(kqd_=DMw%-Nim7V~$9MzBr&vO|9ok3|`7 zVNH-oDlRVA_U7jNpfeWn{qMg?7qkVu(mS&&_2csiAD*NI)ie=FZHYozhPI|$(b|dy8Jh&7XTKI@$Z8i1trW zhFeQD_BMsb1S@kM7Vb8B_~_o@J3RX3e>W^$^n&a7n^o%ts$D%#v&fldFuH5^hFy+3 zcfP_@(jz-gv$!rZhwn7=nX4?<%AQ=c&aL80GhSFAyH2;fFxPT>jLoSmitEE(U)i}_`)yIsY59og1k1WXg#(eU+$x#g?Sl8kHTly=VT?|#|3qxZx0N7DRD_~!eSu^h;o zRPX+_z4dy)+1$5=EEdO(=;yRo%yNknKQ(RY%Ntd_#asIC{0t6Pj*4UbYSUD8Xyd$l zva0+KAGN=3a^D$q`;36}k}HR9G6#Iy`}=pN&HgVEM*6>^HyG43%>K;3^uUVE-Jf%h z7-zOssHLB|G3}$n^-FL3A}twmyx-hx-!<*otg2J*?Wb>hX?o;fa_XTRX$GxTaf_a+ zhkn1iaHe(l(`|OKKIh-x)UbN^NSa@jZ+=3*Z_6~JcD7jQHyc}Ax4n?~B(!bLfwIys z30vu4b-u6SmdVVPuHNOttG9jEp%_pUKRanZGKoYD4j}KaU@^6v>_Y`727L^jTw{>)MSEe(z*i$9-#x zG`Hu%t0uB8eo_r@joM}bn?riCia5Z zmg3h;VGW0`sjpJmUH2->qkCUMT=AnK$qV0Q zKF!p+sc_@s!uc0pC~cd*3Y5gvmieeXut~|{{<7In{Atyms^|BF9cCKJb+^hn$EALj z%v{!MU0%4a*_~Z${jB8m(-=8FX|3W++RC>!EB4%KgZd4zyVlw^1x)QYa`lJhYWLeQ zq0u)g3bSwSzv~;(`!;lALYByyQkms?c49>wKMsXX*Ah-%qpIM}`(+mYuMMxo%Y;04 zC)`_IZxH(Q>t6AFsrko}9b)hQ7Pbn_>F%(s-G21?N2AC`DyuhraTWf)blLnmjyGbb z9@%f)5$t#P@wyY!rv8|}C1~f_D?gf@bMj*L{B>K^{AJ1gOhdufnSsB4KkEGb!7{3J z>Y^1-Hz?jO{BTJ5b!T+yPWJHrmsdlUxEHrGCWk#VpR;f4DlHGIibucBFN`)iRhzyr ze2&mG|BpFq%X_a2?awLVm!7y?_?qmGy)nlt6AxXpJ2qYa-a3Q)R{g_Ixt{7Bymy^p z_TvflpCtchG(F!~kn^(ciQz4=$}@lXbewM8NbZtt*R#v}`Za9kn+LBh#`!v=w&tB~ zEU4Pdw(YcUN8gQNdGAE~+4n=ePA&|oT-~|fA%Bfi&{n6f-~MmQ^uF|d+ngB(+zhfF z{bLhq(JoVot2k3pcXdXb?}P~oaSXqIZalSm?bqzv@tR(5_g1cYC7SyAWzo%_cNeX{ z6?j&by~r>(a%TOH2b|}U@6;U0Sst@Exj5CE{U*b$!o+oNu8VHw)9te=^uG62dZv!% zl?88(EZV8=a$L&bm;1kn>t?M6Hz&=W&Hc9NCv(@dV@Kwhf0f|fEAjvGpNDbVJiJT~ zzdpmmm~r>qx|LJ256rnGmlGcPVyg^GY8wBhsj5d@ju^_nSh!ltVYYv`!JB11>wXo) zz0F*FJ|!*X(6xJR8pdZ6(mp-Q32lAWll-xz_h^wy=xtefyLGui@!}#ezH^?5O}$?K zIBYV1zG-1)M7U0a%(Kr5YV%Vq=5Ke^vE=<6uvPDy;_i~U;&OkMuJ=6G8l68OR?67N z>QnW~J*KNv*5)6uyOs1li{ZoT#^CkN>FOMU#5hg?}tR&***dNz*n#r{ZUhs=h~;f9vA>XVqJ$ z>IJ_}@SSnu3d_YP_Rq(=HgiAYUnTUCzae+YDz6y^7aO(1L!)?8X zP)ar8?g#f&nVjWkWm1CY?aR0JHH&Qe-t&-idg{s5?Hud=T-j+j*Mw8r^n&9Yzu?6i z6$6srUyh&-)X)@vjWX?rvLx5_@?{f zH;(M>ziLi+Zq1*^M~)>$l%diLh>jR*y|u*RiZE1Z+xUJ>V3 zcP}q*ullsXnfcNt#nnMaFW$NzyLHwZ=||5U_PzDfc-Xp?@7&G%`!C)u!sZ@5+Jy zivPU1IPXVe!=L~U>P2qVpVIJibi7+!{Q19^b#3$UU8XxHRBvwlYulvuCFi5Y_8%)Z z9j!g_W1g=3=V%kg-(NC*MyS2`eEs&jd;d>AXo$PJYo~N2AtydlC;lm zxf0Lk{{3E^?e3e~E}Ylb3*CC_JKyW~S(lGET=?;Pq4SM7`R=^$UVn7lyvaEH-eUd3 z&s=uB7K_)Z`__K$-&>=`sYS1ozC1Y;KifXzY1Gu`Vk^Uz9-qKzyH?IvSNXY1)r-4( z0=|6F|6a`e@Iw8oIi1aRZ@)+GuVegcmlZu_(p87|UUsIJ%Pz9HUHuX}EB7bQHjjph zPB(+frTqJ5iHqIX?!VvvkNwBuD?6uE{IPy%TPo@KV+NxHh{@@qJ?3d+vXm`3`YDfAZu&{pNnX?ZV; z=thN!Uw9vt*ViNT%sw|i!Qiyx%9}OHZyxPTx}NVoX_C;SAgO2{4i1%BzMzrm*m=_C zK@(?QZ9f+~PcoQ+ITd@YHuGI?ajV`}=>5O&6%%*%dxmO|DO@3_OA_kcbDrJVym8-}G>ue2gL=k!{?UQPEmbz=s`D-9&Cr<~duLzL-^|Fk zU)MI8Owbnb4SQqLx-Q>8pTCqLX)$yEM*C$cv5mTp+p4DSkf`kWJ3XrVlJxR#E0;{# zX_sH2UGR2ML)V=73*TPoGRSew-DYjD?Y-5(%Bfprk2Y?Iuk7lZZO&xQ<4$EeC7D-o-d|@qJ5u{n*_oqGwPj0WBey2_-b%f4BJ-NX=WqR1vr2t4 zTmP@wdvf=*HFstnJa$^}faIZRqI<-6&g(8;ck*0rqMmcMQUBp$wm*p#>Cz1Irc7HJpZ~o{yW4C4R`^vD-dQ(1c+Wh;NRa4dHbnEH%FK@2WFrKO4 z8tK5fwBqBez28}8+t2&+XX1gm6YFntKJD+h`X{&i>8ocp_uJ;%t8Y7>n5T8%&(Fet zuO?e&cRLJ%34= z+~%y~7ljz+?5=%s@1D$sG>=oe)5X(k-DbNVam??2WP13T@vOVImCxR-sY#fB?pzgQ z@ngc-+ZxLsv|fI@b&vb^=O*j_eZ3*O;-;wg#fVprPT zQ2W%08%H{JPBS*zZeVcDFl3t4tleqtv!?s~@t7xVZCMjM^T>@m9`k1}oOwy_|Ic=3 zTi(gjcxAUfS&?{s!Vixfn!#0UxxaY6>fii)c;jwUU)?W9)<{g=QnSGI<-e2hJ$*6z zAAdT0z2VZvqMv_+SKFw?9d`f4pwOy2KQjLDR)vu8u&}T_VY$pdWGq(iKl}J{^z}G) zU0oiHlk6WJY%M)&7U}oukHfavi=0%SKDpI>)+av2ReZ*03*(zFEcjzhnBCjYo>`x8 z?(mC}lHWJx=I@@|5qtN|uHO~gn(Vi{z4rQXf7OlIj4#rSlb^{==w$u0dE&&reVvu+ z`nzYZ7JE~Z@J7T!s4C}7zQ(eT7FHLe*Ix;5++3IS>)8s`!v50US;Zf}&M&uE(thw^ z>cRM92J^lrn{L;R6W#fFq37}Q?p^mj9-CPpo_6R(tA+54KYoq6Z%wDNu!&$b=A z?f-lZw1`{ZFtJl|w!PY)KaCfchnWA|kam-A%FJ7C&yKZeoloAqtHk6*?o4Bh zRKJ>hc{r~q_VBVby?45jSIf`hf1G|}`OHh_Ee_w5EaUY}_>*&S@<;CCBbSV8; zZWFm6q}(!twXA9T+ z#bR=Ebz7sXpHG=S z&Gt>oJHxv5yX|beW=BR`zq2oN*#aB&oZHu5zSuVP^Jm5r^5P9kDYZ~to0rZ4q6 zKtz1s+-KQ!wr8s)R#(nrzVyZ}Z~bn@T~jt>ga$X6eE(rpcAwpS+usJ$e(|e14dv|B zZs+aFnJt`)xi4S8wV>elmmYqz9U|}Ji|*8B@7T9;9gD^%VX?q?_a+y@uW}2Oq}n^%acqyT)%vG){Wl&V zkvrRY$Ds2{(VHhrZ7f(*n|LSXTG=uCZI9AxgJ<5mc=hu z-fs|>YGd{-wB`GUTRHFT-f~L^YWtV5A z3yagrrOY8g|2{W<`n6eVDeKZTnx~k(Do&`gtv7CK)zf6CRnuzdGg@Y|TS@r#N$zcD z@077Nbbu!`5?5Ngzif=&f0m=y(q>B8zVh##GeqYv{<$G+&e5FRwaeIICBUjN^ zrk6rDHa&P8Sk1WMmrVgj4x>8535nP54~1{7zj|l&S=|_Br=~q=ITH0Bra3Y4%(C~H zakDt@;IAjm2OmGzx7xztUHZ&cfx~BBS;qfx{pGbbbLP)9uqyO9H~a9M_KOQ=y!cS` zFTf^B^RQ8N=eeD}kN29prk!RIK3<`}tIzbiV>EO19mWgoAJR1!cugzeZ(ez+>`Mbb zBk$tNQd9K)Cap8FN{BvCXmNO>{?s})1%18X>=!+PR(B%e-sL|1xzTvrQ-$;VZS&qU z`Z*})>3`+vcAdpuw$@g78c#r_+|%=`dju6N>Yr?pldkQ0_BQVf&%zL`9Nhyyjs2Gf zAFRJE6X{+2^D=*Gng`FNH4M9Md_LZ4s%W%v?H-1x#?R>r+nDAs@A~rgep=fx72c)R z_q0V%&iB+hTU(fR>F-~=w$-0bCu}LQwvSCtc5hfEVe^~K zcFX0BnpGQkGt4JP^(Ft>Q(^L?_2GB3H0QkN_smP<8)vO~-rr_p{%76Rn-hdq*DlD> zS-tv~^W8DwGFPtGqOx;}<)$3>9?`Nk>g1%Vo?wv>E%d1#I8`H~B&-l7vi zrp@Vee!aPQ?$&FE4`o*@)o{Ph{PxwYrAzl%uuqrpe;&rRA*rl1bEU?`+j~nnmm6w@nc*47&E~>YBHcbL0N6%iHawRm1k@gIk`TU~;vW;Es*!=7Yw`cjs2| z#mUXzS(8z`bc$yze_m#W{eP$Pi)POI^G@`SpObL%(}|4N)l)AnFW|f=8lxO25*^M{ zx;6ARbN%XuS)%2|To?L%dsW_CQ%(zK{p}KS?$3RX-M@~u?rneQUp=j6w~3ki9WI71 zESlgR7PJk7g*a{;<&Xht>nfTAIF(D*MGiZyRtl?BxGjh8t>DprTfzz zb}r&tdpTN)dyzo?iTy<--%C&7*}U}?Zkhw$RIS9Qx&52ZRZdNn>@c5vY%q`y5cwArta&3rOWRwn%UTN+GoYgRjIKn)+FdJ=1u%J z=l<-L&*`@&&YV4ao5_)xoYyxk(omngf7EN~x?2iT3sqR`*(xJQMcnXX3U3J3;C$Ed1U%vTc7+a9{ez)R-LIQg(2R=?I zl)PY8UdBG9cK*M*-1k!sp5`#Ns=wPKX`FQ4?#fn^&k{!ZRaRRKY8s-C%X>8zs*9`Z zgmS5fos$b#Ro)P9eaf_|X}RaCuJu3PKU{jyE{I!wjpR2?P2KkEpVvI=Y2PIl@cH|i zwCD1t8aNkAdS=cp|KcDY`9}ZSIycTaidTwjb+3JPxE?e;lGDdG{hzD!GC8YtEv~wy zS6831tK{nC^Re75ci`gY&!?8W-E++HmixP3D_1A>F6!DfBV29cTgz()?TXZI2L*+# zlX`uocCXsAo12VQuJ!VYb1mHFuOU!1byAd*wnn=h)ZYueuRV#BW6o}ad~>CbJ){+G8(_?cvrgv4$Jec14!NmKKx$kHiIvsBG& z7d{jHxcR}glNo-=kIo&rvOo4?Z+lR?|KWvkyFLHOZoMeTcwJle>*7V1=kT^a+J2@q zAc`@H@AjXywhVmxGVC-mc6p?wT)DJv*C%iF%O9s@9NHSPQFj6JmB|~vT0fIBNao%b z{yv}W#dQ7nwg28~Es*`)yQRf;IqR*^dr5qKJy&9?Q%kx6`Yekr%bwp8PA%D%YI7kw z>6lA;;tz+qG$qYW)-KI$d%s!V6?va$egQoF<91xXg(?3)@e{d{X8~XB%0K9QVe8R+ z%_~!WFrw~FMA58i5*w}S3J*GW9#)?$yYRXCw|5!`=RLn0w<47}#b&+K>HV=ko1Y6w zuUC*sl@@s_eyTb)DD>Z)#z=FSbXjHAwHLM~zTL!n>JQ_eHO{kcZ)DO#wbNc$HPN}?oa4PrwnwZL|VP*Gh zcT9U|6}zF>H12fNsnUhHOY~O+RvcYedTOo3oAlbH^Ot`6tG3xV<*$$D!TH;NF1oC_ z)=M*!*J_PiUFhMv?S`M$2iY+Amq|>^zrLYug>QLEKc`d%I`_@1-6OVT!GnEi z=f#4`7raeg@m4wTSDtvkXYpglYxah+`5*pS zsJy>}=jNlCW>wcTZ|Z!xemYt&b>BvLgQ^=17tbtpKloqP=AcLHoDD9TUpxONtZmYL zSj{p^bjSH4@hQTLJLJrZ98zASofl4KnI+5CBX=(IT)K&NnaZc<&XKHEGcJan%HDtK z&U~}BoR@V@mWREg#X_$Kn1uSB7TvMq^u??0p{;SJ9gS`(SOiBp`5c+|o1rD|<-}u? zcWwE1;^fJ{P0NqTFF9STcW0CNbwIv!pTREejE*00mQP}@bh)I9C(QN#vCCYvD$Hk($WG3S266v3Yn4RvO*zSCq#OMG z&f%(C3AR&ZH3A%%XU|(W@!;qE;TkGJCs#ju{9k;sCi~37`DrYMbzygYSiW*!I;DAw z&^vL~Rdd3BRyr(+a*I7D($6<3=$J^_vb`&#O6roYXxs0aIIHg0!3_^uH~r{hH=o~7 z7If@97wi9*%n6GQS1Q}*6~&zL-THOvjG&$``>r(^POWTjE9br^CV2UC^V9g_i}|`X z1z-4lWzEF}Q3vz5Od6uS9B!ENEtC4G{K4kb{Dt%WD$mr|{Ij_)-9mWUX*<4|Z^Y&V zZ81^1CV6hc+4;5)o9q1R4RR#5bf1?0mcg+39Gh2V`vJ*y%`p0=s%t?bXETO`(>(^fyW`KPhybAH`B*CvP-h;Hz;S`f62@2sVR<@0H4qtxH} z&c0M0;c`eZO?URoD=Pn6U%|D@J&m$j{o*&3L}RCjtt*q)0? zzZ`BaoWFNc_=Y+?Th{ayrr9QI1Mc=u`p?N9uxjfRb?FGMms$Vj&wgzwW^c=&b!|V> zgR9!n>dNz%SIM0{(`L&Q_#q@T=rh-zF7_(BvuE1u7l|`-ZQH}P{_)M(VZP}H{_k&k z{Z+22Tv9eEDzAq5eE9lv4y{e;DOOJyxeiu0?w&t?zI*l6yZq+=8yMoNuim#_z*l$I zWyzh1Apsc?x%bTCTrPY1eLUmXwrC7uM*3!^9v$t&huWOmR-PgvY=AO4XEx}i4_xOaB`BN4qCW-Uc z&C(55c$R+ny#Bkl(h<|$zqyjS)MDmqv6ug6nAcHc*Hi!Jx$NEwl~ar*0c;}MQshOq z7!@8Ne{{8)RAirndS^HQT%7oG3@|M2_=oBTFE4PhIp+4fmMvVZO;|GSdcdf>d| zDXs-G_aZemYfAq#OF)=mO8&tV3eX^uRf5nFGtI-@B|JWZI>Y8cK zJ_uS8|NjW@{o>P|-j;7JL~h*U|6d5SYF^pVvLt->nk8>`U$0&0>3|J<`1j$t!S1pj z(FVJBnK#`GoxJ#J?THpSUHOx*Qp&DAY5r?{=I;Tf^A zcmDj{V=^Q5f09M(*?DGJ1@`@YXHOa3Q{SBJ9N~H2{a?YEb^g*b?HTv(+F5E?SM~7y z1p8ZchmY+t&#hqnaog?q!v9xp3bWU>&4^|G{dJS3k8S)t1IKAMuLd|y=Zda~SzkK+ z4!!aEz*k{ycF}6dvLkUxH+-%4nC^c0uKX$ATiK~v z-kn($^}c;!zI7ggD<22EN?!Q({h2qrs$W_g@7~92yu9mt@yYlzXKog(Fx+ibpzD?L zcD`<&E61nLw+(ii9r*Ub#bSPU$4%4R)$f1DOsy6ECz2K(_wUCZ-+xzTmdgHH^XFr{ z&Y`z=6u|Ui z=Eu&7uW;V~}Y~>{e^V8dFr$7Gs>dEHR9qIqo z&aBg1X@7QCz>FC&I=pu)D)ZhO)Em4%uNtwJFgD+^``Ti z2`4gMZMZwfuB_zJly&dVyjgW}d(D?_`_{rK4>Ru07rw8NmY`O@A>?k^Uf$*JZab`7 zap6IkS?Z4!_an{M<(zN5`u>Le5q57z))mi;cUvi@UDum&v-DnWcdJucczM8N&Lzrc zLTuK}xH({<^<#gGBGl*!KEkca|PL>e8JvpM|%*YF9x_ z_p3jvpQl!CEtrs(ZsBp*z+CM(`|Yrm1#cgn*EZO^`hP^*-77{7#~*1N%3F2t&8Y(2 zPtO-~nx*LB^Tn)>X{yl?a6pRf0GuABOH*6qEFVI}To*6ogzyMFrR?ZXyn*Qf3d z(S4I+xLLc{(KB5YGL*jDtU+&oIMa)!t)$%)dU*!BqcwN3)LX&ax>xd`mB6EK# z&0LvO_VnYsUx7UD^K56XeER!oQ$e}2!dBjnuD*G9<)bGaOLl0j`}W}T`l3AxUR{(t zUG#@-mGSOX5uS|=H@6D*EWY*kr_Lq~tGdZ1Gh=UO7*`A0*Z(+kV9y^xqupGmyC>9N zou67Q_M_n4G!x&n>!IA&49=|EYQSv0a>ugs$CTE+yeak5M|+j%G;M?CymK#QH5R-4 znD+af#maL^+9}5G*1a@58~Q+gqqcilWN&$R@5dRvzt6dSK6vRvh(chX!-XQ}?OCA0P8%CiX?uPgrA{iqjRp|KI1WRB@p?GgJUY?HoXM(oG!I*Xr~uf94XHZbC( zc!l7e%Yn^LC#38Yv*f#!F#XTl$@U4A!G@=oc28;+*%)J0{`ul zH&w;GlkQ&eJNoFwrHc(u!|t9dTJ4r}E}}Foyf1Uw%>HhP-76=xZ&p4%>DHAcovl;n zPDw1QE&03Bb$Q&gqSlGI^Zg~$!nvDp1SyTnAGTOo;YtHx28+5f-4PVJi+TxV)l zbLm)6=fqaQ;}^XGw>V@OJp1f&X3lgug*3n5zL}RVUAoZmn0aBPG*4RDTh-%#W(I8D zxlwUeVs&w-&)lzq`&TSaymV>djCd0f>ulqkl+HHy zm(7mlpZ~7o=GNZT;%^=^?3R|&{F{@Q$nZDk%!l>2l>S|1*U^75_OitPn1-?Xgxv zW%!Ihne}T}?VEnFb+~@Jwoa6X+i>@+qU1=ks4cUO{n=Ktz{qO4{Jyks#?v3WE6e@! zJEJy*AK1P6U`39OYvKFONBdqoF8-0A`Segq;9?S@AAi8L9{zyGW+^jb zb#2s+RK6%Yv+iie&8g@2cSY*)_dGWCUzF{ACT~?r8E-&(S*mIO{nrN#HYxq{F+9t( zEYi2a+FIjg*u&IiJ9lT$M{2D_EaPORpU zPIs22Tv>QL-E z*0i$LZRPV1+=^pxU_9O$&AwXq(TyeVbbmS>-DsKmS?uujbi>Wr_dU71+O@e&@>d@S z^0M<6O!JeCiwu7Es3z@PXT)ZX&Dla}Wxc60VvF5M-ZMIgtxbAXqPII*FYV~_+!fV^ zHg$pjf6nN17d!FR==mT$dS4I@xu>8%lqi+8ncub*RBzTUdHpH&KG!y$Ik3w9^XK+@^_HjcM`xbQ zxVFY@VrPfBs4=tu(;2bGl4;jBsCqg#T5Q%nYDk@tRW3hWbgDc=+SO~vMku&V#3BUw{E-(6nY7cMiu+&rN9vAMq9 zWGSr&%||aL{!A!#tN6yU(!feJr^Jo_#jO?Y8Z~^C0nVNlY1frLY|%>#Kl50sy&@)i zQ$Y8{?`F%I^A}Gm>`)NXT3g4Jb??HL?6bvfVybtvPh>VfnENh^fmbbb&SidX!PBX6 zL5JkdyxFxc|9SqSpvZq$MRoqKS||1Y)sM5mIdSvGpGn0fw9*M}Eu$KRaFoVQE; zDc_|z6HY$vS=)V6H2v>lr6ub8#z*W#4R(8dUC1lCrRBKDs=o^i_&+bU*P4{5*|#_} za7{|{mGy3aCg?uVkybhVri=UCVd;+N(rNULcNy@#j|ZF>5wbkpW#0_N)_B+{<8KAtYZnEBdloyNV%`#u_I-Zv|bl;u0J zXQh*u#Vf(CPrOs4d1e>dPvmMc8&e&rC&2*FN)j0-gfN|cRyq3Np7v@71yuq zJ^1UU$782Pp*Idrej&4#M+RQMx8T?tt@NMOvo#j;w3weUT;KJJXJ?4vg{xtkj$i!4 zvMFcX`lPa_&-)v8&tQ`}v+mNY@KWR5Np2Z2=2d)6+3hPmWOzzd&nQNpddeTpID>=h z+Vn=V>8lI9_qQe|nkAb(=MC-I>Y!{jOJ@I+Z4HgR^0IlFVdffEv%Fm^-d$)q)N!+P zj@9PXl_z39eGnFT{vOWpVha|-MPN?h|cuOnr+QncxKcrcoLr~A!vAdsmA8lCugUw zva8FL%nLoRarUbSgE<=;9-h}(+H0k4nY?t`xviULC&~FuTP*sqAnMho-76=YpLr?R zs5LCsuJYHpy+sbQFI|t^{bg1}in5u9ejo3oY2kr4E59$7BsI;nHk$Shb`z`*}I#~>2Vjr4x9ULcMm!& zP_CilX(s1*z)-C&(AuH+%p8$5T|&un#_DNhv7IwwGy7%=pS{ren9=Rb9G>^7)kn_! zWcVC+so`3}vy`2omTA|GvwSwM__E1okN1p(l6e6O#kz3{p(qa>zAK=bL!K(qu$wP&M(obelk(ihLZVN;sd7Hr zxhkn_YC-blN7aXSHmAokXtyoCDpTWjF6r~J~X&+av7)eD_7Fb+A!t!HLC`(01$ zHj%V7N1r96CD`iK#~GYir_J&+c-a~=#=5s%`8JOt56W=3%xq+R@cG>|CgqTc8l}r3 zUDD4dv!#7f_dPoO^d`69LmTCai{nmyy0g!wd*_t)&pQf!uAaT!Pf&Z4k(Dbef5h%v zt0l5Sd-nD2cU>@P!nFnFuKfE~J$$!9;`eD$e!uG6UeW=3M&ie{)o7TR1v+Op1oXq|y>t~*y)OEvGTP9@A#;HGFn_46b?q2!z z`L|`JGPR5NR-F2s>3m|^yFHS5aVu7^nLZGlU|iB&q%ggC6<6%Eo1u!{9S8R;Sm^Za z+{M=h-;-SqDYh*Z-R!u`H!bSa`j|br`OBQ+e@C8`zWKWUpWV~Ri5-8ZPLA4M)giI@ zwIU<)Dyz+_C+JWAyh`e^#s)4CgJPwy+eYg*6>VPI?qzycl?8q3-gIWploMv{l95ZN_KBQWF1R_n=R((3Q7yS}$!CRM=YMU> zo_N~ey7uDZi>s^IGg%kA_ul+^-|)x3Z7z!f{=Z;6t$jMZY_CP*Ssyj4*}J)aRI{F0 zcj(NV4XWR>yH?G;DVkUK$!nd?@_AnM5;ii13+!BYR@}-uvrfc8yuXzxEnH&mUY^a` z(>XhCithirs>1o>jM&9{tu!qIBaa0JtX*JvwxFlsf~M4(6W)tHMtn774%XSMJ>5R* zqtlsn2M=ncg-0EI)0NioBcXler{z=T+q3^%UG3mfa-KiTAnb&i_|-H7=GN>?wucHGdF8OG)FLM!y&lcJx>52p4?&z!=P@$l=fsx!r>E11`- zNlVOqaf7ehY3GYKoc-Q<(>`0Q-uWURbiIN0rgDuK>y4MEeR;K~>3qa$+iISk-9@|C zEt4vq?Qrn5uDj=9=i=D*Maw_xY+ilk+Q}Q=JNLO4Z%*t#m{d{VV6$#LA46^YkvCmC z;cNzKL4?R%?CG zt268TwidVF$}}im6_I}I^XkDFKOQ*D>eG>M=8_8YZ4*e~%U#p^?P z%l}7HzF!l`B_5!o#&iy0{eY?Wtt`U;FXV(a+D%pFVy1{r&y% zZH4de+1~JT`s{u{S*a{HLY=eN|JTo%FYi4L{t|R7Mzb;EVByT5&SczC)* z{=Gel57nSX+A|+JcI?`&o7A^C1Q=d5MYMQsgt?>(w>V?Hmr zXgTk{^|RO~o;r2v(W6I;7AaNyYxsX}U+wNCOP+jud|ZW>gX2WtU5;GWXk7LZtV9T z==sK_9ak0oV>^Dfcf~^=uSM)i(k+E-(>jnnSI*Puk(LR-M>}D z=HXo+rk}Uh#3YuT4MOzF6T^pS5hM{(8;I;JG&^xaY{Kx!2!4IAPji ze#x-Aet%yscUDbt|9{)*$>DXfPSag$-SqkA&AquIi)*Rf+DNmUzGvT~{5tPi9{ea{ zlV#DS)7v(y{cPrzXUERF^V;2u_kCNq?4f(F{xRRO-8H@S8-CQ>N%`)5{gqwT0=s~& z@+&ihc4s#|j;y#+z!NKWw?ccumF1?rUuXPUxbT06z<0G>yLPqe<}W#8d-1_yH;<0l zs#CO91$T9x+w|aOWPNkaJKNt6UKv!g{@d_+(QVIzf76~VUaxhY<7HCUKO5te#^?`m zzxMu|*_pX_+i{h*e-HTuR(=0})0+Q)#QXpK_4+%fO7FarDxj$7p%P_0Sz)4p_P2GR zS%0#&gm`bA`oVmabF^#pW~Y_DFAapYL`|CE=+vYjl=A-0(|1Mx-&f3gK2KWFajl*F zk-O&SzyG$m|F>@6>rkES*MG#PNp0JWo{thTsQB_q{QJFG*y8X%r%d!vp zUYGv(`O(dvdAG7$`DBbka_SeUT@<*Ieq{xNd(iAhyP{`%_f-o$Tbv$GP|Pj$)O`&w8%S!M#qmYWLYYz7L2x$*BinvS2|BkyRl zbH^V&fgNd*U$$*%Nn1Sm+pC>_&WW3xFnW=b@Ul(MrhYwJ_GJcNhduxG1XwFH-GlT* zI~Np8x^#GRWpJhGp7qn0zwYh2Z@Kd0Bu`#ewUyVVZe6j#X`V}(@VB2X^&7+|$I9N3 zQ%`9>UL{w&defoOnj24NY0cH#wZUucMZ2z?&XenG%I@6%wAyS^?CWzGwOV&V#BOfo zYmU%Xb9IQ{t@lpMUgY75iZvB~y~V`8zh(El&VTH#P)}6xM`fQf-8uFPdcQp2xzFFX zuiPj#$3f)A&u-EFQ^y~5TU`lw=6j|%&)om;!I!y<|8Lv8eS7}x#m67{&AqiXo88`9 zMJV9&B`)Ky0h5^t{%@Oq+xBTp6XtKKJ@kMzvt#j&EC=bDU->6zW;!P4 zOwf-={26%h^WoM-(I2y~U&{Zc{eS)XUysaN@~jv>^8XBT*7Lag@7V&@mj}{MUc37D z_5$ObjxTR!HZHCdPUqiLA$K}shTX%5-}~z>?$~r`?aEhg)-Rv^h0jz)Cw|7l%dh9y z-T#&T-pp@T)8_g8@_Q|LBksr+#!UC=DwwL&lX^?C>&>YhG1ke4_lcjr{z-N6u8p;U zYi}RYDE-7G@x4HXyZPWY|B{mM>_T~aj%8Whs<-#OzAtt3Za`6*mETpyI)hNwK%Mw$ zh1=imeR2JT<2$1(cjiah*PWTZTzT1F0pop>y?9D?ZQ|bezQ?ip(izFw+xGr{fBnV5 zDeHNKlXBB*Wj^@7Sg_uJ^Kaek`L64XFNN%=j(Ad z*2NJv7P~ETz6AL^n=`XqXYJbsdFN^lAJu*Au49?2EB60;_8Eb4&8kTI-HC_P{;k=W zyKeq^zPESX7V293e%f;J=HK#jx!yZpaGkF+tSix(b&d00MN#sC2lERXA18W;&n=m9 zCZspVb#m92O|Ww*p7D}@VZe(QFC-dytMt$B-T3hNeIX$sBV*&un>KBU(zVKb{6c(Q zRw;ADeg1h(Uu9KlM2pw{KK?JH@?J&F(jOmgD+g4TiO<+py2Mp!tI)P6$+gq;=HCd4 zUuwBM^%%>Z$;L_V*6qx_q#x4$t!XLWHfdqEd^cB)!n~QyFO|~%?)jq|zt^oc@3gh> zKAWRj=bP^?4f)$tDsXKstFV=}D_f9uvbPi4q1~Tn1Z_84{B`;1`=2gmn>??pN@v>J zUvjVQ@#3bKfaTSB-Y-_DHX7IeOA~k>l-At0R@Tw;Rd_P{+S+%MXG=*$i{&|GJ0DZr zvfKD-^WNOl7eAM@n4D&w^lpKUpoCWLgY?~f3*JZ^ow|0NOQ$9uGjOe*jb*|vHHssnBUc`Q?Gw`mh0x!v#WESX1i-lpW(QRGgxmghx$=+)gcJz4>)|fcvaBT{AYSi3B*A@7?!Q_E1=?#qDnKUupBr)Xvm%<-rQR4`06^(@u_F4LXA?w z7p%RKamCH%%AU39J}1}N*M9tbwyIG$Np0J{jpg@>%x;Fpdj8^?V!g)5ZF21G3#s>P z%J*$MBx9z&+brwKitzPu@qN-#au*yHU$m(DWnp=>*=q5!xl$?pZl-3NWT*T+m~cp_ zQuC~Xbg>J&iEeJ_7Q^|S)_dAKStjuXJzsWtx&Qx{%ja*)yZh_s^ZET!rmIp#6_7Wk)}%U)PV?wb&u!$y23y23qam zE6bW6uHW>D`S-1P{Iw_FMm(*Ypp|{zWLI5aNVJRVvMklBX_rExf4%Eqf9-VrW}eB~ z?`M~`Ys#(RxL9Rfb?=u}RrcMA4gcqTtjJO0@`|_3)SJ~+vo6yh^O{~ja3yEPr9GLK za?(O~El=v0sJ;5|o5*&>4%_UH)g-Q zc%U~}b5pj@i`mwU85h>SpHL?2to@=Q@Qa`MnZmtJ7VFlFyP7jK1Vn3Y%1$g%meaqo ze5dXn30vb`;@xk$DmSaaT*0}CLG{a}POj5P5qwZ< zeREE)=ZQJ*mDR+QB7}^VJ7(nQf|D+1dBP}bIy?WDa`EBj2Z#C(UmL>nt zy)fmCmF6o0zjWo|AHrR4x=yp5o9m-}CUMU4oO$X28X|M8O1XG=K77l2`0{1uHjRbf zJ}ducO?JOoq^c=-d&9!BMOzM^J)5hrZOs~{l}<5}Dr{VD><>NmZK*qR-JG=a_@f<` zS5!N13R{(|+_q+_i2iif6jrAr&AoiplQr9STzPol<(XA}Hcgi67Q2+35cyel!2L~> zre=EZM9;g8OV^!gxi&k4`Te;oH~aqemS(nG`>nUmw}rhrJ@Z1wjTL4q8?XI-V=Oeo z;DJEqwYPJ0H|z|Y%Gkx3xlK^*tkrERKeg*qp79-vxv3};zRhZ)+F8DxkG&?QU5u|4 zGzbZMt?kopx@K~krP^t4RnrAKJzX8bRhM6XoS-|i{IOS2Ye3ywuSai_B_ABycp~hj z;p%_at#dx4%PL#zzxaOe+wTs?Rcn*Zm-)w;FAn_K`A=t;=CkxHpR^;D9dDvKo&0u) z)(f}YS$wtk#nj2aOJw(~3GP2PJ1HP;Knn_tr| zeM?HzcrZ1aA-?$e`MEDXiJiSuv2%G)VtaOv_@}8C-`)MSYxeQN#g`8rKkGODRQB~- zq24^;H;wF{5< zF|3l@q`jI+JGLjqPji0N$^$t*YeS8ehxs3x!m;Y~`L|BL`?u-Wu5bIUbfuu1=S@IC zogm-x*}msqhBPa>)IMi%E~_oDx|$VmU8vtdxA4J%xeZgkzLTpHEWVeedOA|pAZKaf ztBX@sCa3jBSr>LMUEgL+D-f$*NC|mlYZT6~S%nt7`?T!)K^}c=^6wY2CS{ z90eUFraKX~Q5+u3usMf{fLT%7yq?L6MHyIbm+MO1_IQtizPZ%VGJBNOd@m=YS^9d#O0@un#4We9G}$sM9`F8cz&Q2M`ez*>9Ys4|*dCY= z8y(1Vsk&vN$BD^%zIFe*?kM=bmGkD*0ujxBi50>wWu_9EE0fekm(31pIabZ~Gh5{5 zS2^GKH+fUvbXm-CI5{EKb;g^l4KZ5hm3Ggw|2RE!&x5-*V$lPwdu zeLQBE6i!jweaLLex6lsF>CT3qFV9Uomb7c-L|g9@>sro8K0K|yBJWDVZ2g^I5+}!U zYF=rXmYMK$`i@tJIw#LK;~6t;o4a29#zQ|l6n6{pt@4d9XI0$Il_(w%)Kgcv*W>UM z_9M-yHH=+yJ(p)H?q*`u&oy24@0r1wM62>AD&^Tjb91Yz zsF?8C>g+VDP0!s=u%|gSW;bWe$~BywrPw}U(q)g6JlsD;jSnjce|W;%oL*Ku+4J_E zi)$xt@!W1M%PjuBcOmDlh6!miqZl&uHcDDXrW@SYw9YWwe8#OK0nwU?XO-?7ZJnfb z{$cOu%(!>YXG~wc>=oZKrOQ0IkEWk(KI?H_u;S~ibI}>gX)wssseAAm%$shS& zPUzq0wC{l0ZmED1Gv;?zY|z=1-CP&PmsS$Ixj-x_C~Y6(#Ms2(_0BA=yuMsdU#@$j z8sl!f?bXk#^$MF_@2>vd+~l49Ucv44L3=-+ewn@)gRP;OCNa_N8C%|@yX{kI-(0z& z<&D)vL7bOngo=H>W<& zb9{DZz7b>Cr7d%f+2&fzG)`i1mPwr$YskOt^oq)57`12_4zPE73{FctFp6hFt zDz3Fl{^(lHXmB7(`+?tybsILjH}!nAu@Ji)9yuxYdDx|#xZG3wmYUq$DwwtI1-GAXdH@Cid_VE2Q6`AkWW$7nw@ULI8hyV1hcjunHP4PHv%kVj2FGsl8($9=X z?%qA|?A@W5f0G}+dvwRpsC~QIJxPNEhl=RL%+3SaDGS!FU3*p7=4Mh;HqU&QvIxKR z5vHG_nKx9f?VNLbb9_NvdTL_c%C!*;skSTIN_1yDGq<_d^rE|S4O{HeUUt3Dmzmo( zcU*|tb@#wzBdM;H-C4qt7uP4W)=XYC^|$1wwVaCA*aedum0YWrWq)_vGUeWawF)|S zE^auMJ8P%Pldt+3ensC-&dh)R?5rgJ7M``!m)AQQd7jt$ydiU&!r5tWSYN$2$lTW1 z-!mc2{nC<~MFHE`I}XnY&3_WA-;!_Uc1fpa+2@=e_EnL){_FkeVvCNw9>R3bH~5my zrSvT)lq5Fxe<6 zd2$xl&NpVw+c$8&xVC%VzgvuIPsA7><`o6V9JgxXOvqZq)B0x9v+w!0v{rxZ3DNSK zBlxpSN%q`T=8vZGm#-YsJ|L%}wuxPOgZ|yC%*Qk0?H)c1x*Q$7D#VxXs+kWRxp>7k3I%J&t%((GC~jw*vVfgUwXl%iI{(mV`$My*7anNIOzLqx zqTX)D?{}q|I7J z7OfxG^In{-|5737{Hiw%VPRoqUtU}kR`-*!ud^{X|2|Py=(f@``Cn_CFKv*Eu6U3Y zHFy4&u&tNYT#2l=={9?KbYq9*{&f=S_x60*t+Vk|z?5w}%hJVf{?N{`ozQdP-KD^@ zkqw8A$tu3ty1R7ip3)x|Hu}o0>gJO6k26@5bo`6PwHDKK{oX4NdNx15Sr=Ilv+?xD zu!sM@$ILr^_3GC0_xIl3-v0g5C!ucFfMkPMsmuTOW_)V;D$({TYm>wxskQqS9^;&` z+%)ctoc)5`#bx68l^$%i8_rhS>2g+g>m;Y0YOcI+<;s^f`q=&Bo{c z38&@fzkmAl>iYQo3l=!|aRz9^LObx_y0GDYQ832B_c61VBuD_ z1B<1vzNxqv)oePy$=vwSy4%xylpgloSz#6sweX75E*}MvPaoa?@YWvDJgFXcWADG< zaJgy1+HMaIOFeH0U$%5&veN3xN`=iR+ zW6DuW?B4smd3MY^;ZyF%wX>=Sz0~f3CY$?aA%ih1y|qJATV>H&4}dYT2JP z_2MrB(~kz5UY`%%BXCzF*kSc_-u2NZX3UTLd-H?(qS$pIJ@fjWx>l)gZwt{sss4A_TjKzU zoXUeewj281E?d$XnDk=CVYQMfC6f}XW75?>7HwMO)O&tW!0LpI5~ILB<=`aN|DCQkTDJUCP*#p$w~@Vh&`x0P9G)~yiv^Vx6+SZz7W&V(tN;J^ zyZQZ^$@9*=; zXZGP}w`;drb@TTXYG@S}uXi@SRa>(~?|at%A6K3+epy+y^maOnp2e>#r?R+r$$GB| z)wYt|zUbLYF~jozU5093P44RdT7M%^YaXA(j|Ypl?~}T8zv->e&i8*7oeuufofco^ zykpZLdDoR#fAB<$2#(0RfCwA9wOH&;h5elt5WOMz|aQ9h-Y z_w_{kY?#yTH*G1pU@l*JWVLk1;fmD1n;Ck_8=N+J2A+{wG&6>+ZR+j$g_@Qz49^T( zk|)+W?G<93_TOO5+sX(2jeoOTIX_NX$#_@ZVn?-E@`>%{+I960m#{rrzfE)F`ecWe z{aLMVq<-CuuDe=oaCgdu__vj%*41nu`J-)FH?3agmlD2}^`@xV#eS9Ds~-BEIk7H* z-?yyx>>S0&*&#>Y1l$vzd(Amw%5J@PqE|cLbX9Da#^Rmre`DFX%3u1Ce>P4nKDR`^ zWA{<{t!kBVENZ*;tUkYWh-D3tVOo7LKx^vV-R1HZE_-Win`+{se{0EM41NL>y&BJrcIeLWs&^}EiJ8u z@sB+d*AyRq^=pN+*!f!x4`;sHSv@UoU(z;q)@34BIFoXOtgQ|IDGMk}P0T*r-s!ok z%&5L8I9x&D6!S}N6|)EOFWCPzv+eKR_(#Fm;KIC98SI@FU-*O>+1Odz*WN4=%F)x) zV`k@Td75~Bo~`|#56*6EmFX6LL^4*hO=QX7(|cj~e2;T6yRF9&>1^BITUW9_ja|Kh zVS|m}oH)B1<(1v4>}6lX{unJeemv8|#O0%W`jeXqOt+f3m7dSp{=IyKpHI!Kr()mv zw&wP(Hj$cZ`XH;uX3g^J{4!@1zLw;${CIKg=nen=^_{ki2da+;t9_A{-gfQNS2va1 zo24~@&W#=)sv2I&=_K~6|GRj1@;dpB(++>qYrg;dsBQ1zwY=lPlgfGXES%Y`H=fw; zpfUXu4?EYv-&y;n_cCUDV3TUxu{GE7%u5aHg0(^_V&cC=xTjqa|GHIIy5%Ul0OLMa zO9AGB1sr?gPx5bB>31Qd-CCg|_KWO+;1kJjytl9R2mTTv< zlyI4I4{x@7d9l*w^Xrw%_U;Z-ui5!v*)@-{r8^ho$i4Y-P-JoG$0d2Z9E-o|xR%A* zXf9&xzIAHX^*(dUka7d5?#8@C$ER-5&Xq zWB#whP1|QoxPLR`j^IU2-amGqpO-J~+$X=z-b`w8ENAy5#ogN^B_1j{yw9>o(cbt& zH_bzN)*GqQ_4$6YOU#Z>oe--paj0tRw)Dxd=6|*tdi*$lSc5m9ty#J2OC$9-HRz@$sUiWV{*I|dS*pSCh zMbnNLZrjr^|AV})wJ7CcEd$)YRbF_+v>0PrFgA6tMC1KytwJC z=7N(md7YxHn=V~hf1D>OIoGr)cfRZXbIZM$e12Y>;V5OiZ?jj9!k@T3?HdF&Ia4lk zE%4ma+oN*tyWO|{vlUm~`e*pH{{B4S?&kC(Uo*3 zL(I;%n4k4pKI&Caz3{RjczN8z)50fb3WT37u}KJaia*R8X0j*pgxEzF`!B5G@1!ri zoBS^K6aVq$+fM(sN%)X<_=^3x{h>QPH-Ei4`T3=<-4iBzR$J6pNORWstuo#Azou6)}wb=8q8mnZI+cdz;DmtXr#BWkx+tnTFwnBTKq#?7|G+Wom= z_6sFb2FJa1hhrQZPdOf%wd}T4Oc?jfeVrdRK9(;l=fC6?5^wD!yzp-2o<-H=^RlL{ zce1{jqVtlmUc||LZJ#FRL!*6*dmXbG=BhmC_Ik8T*VrSWaj)C-*ww200-6tb8cZvg zkk3%)y3{V|s6nCO+c$Z?nbw>#(Py7=_2q%bD+Tfmwj{rv*0SGgqfe#C)1o~S-*o+4 z&BH$}Q6;GPgK<4)=v}3f;3I)46L}!!aaHYT3A8!s)K{n%S#?fe?!&FvC} zG0&6wRv+A^t+cxbIz30`Pf>q;evSOss)h-@3!|AnlHX(lyd!| ziK1DF&FnW->_=svwKn-}Xg;~F$Vg2!TvPR%Q`pr7-kLl=FRz@tMdOL-3_s0G&*R*}wbt7*GsO-6 zU%%M##_G-4rR_`Jx+QK}?Wp6Ja^2d#zEb7(gGU*2{kfADo;r5^^WABmEuU_%Ote@h zDsueli7Hh~kD6BxR@bU_zuDD0A@(lk&8rjYemF2?Xgq)H+JD8gug@qk^W5E<%zn?w zudc4vUlzCe;%SpNMgMr`I<|=>+-H00oVs+^qD6bQY}vA6#fl9Z7A#P(x3}ky*84Sk z_U!5N+3#|F`pm`6^_i>N>r?*pTc>7KZRO$OdvRf5^7(mpqdm^$Th@Mhu+U`Y^!#Mj z{uexFu58`Bq@k@MO@J$7N-5WimiuKy=^XIp>yps`om|Fet(bCV)_2b0ac;tS% zEm-fJInyI>{k~-;&+q-Mj*N^fe|KkJ?dz~(XJ?z|-SgN#Z(5zLt*tHZzrA&TtK5$9 z{Z9OCSeCMI$J{$GM$ASuR_g`L4=lx(+ z{;q81+(R?%R@pFJ4l~?6V@dIj7>$kL`|fSz^h=*Paa-4mgC!?j(o2~O`=9<^Ap58E z@)Cz9Hx?&<{`4f5eVybUt5&1)YAkK;-?$7?dUtI)c0J>Wu)uf6?^YEFw=Xd;)XmtV z7JTK?U;Ar0KmOLg6YV@bT}JUpRM7q_TJ~4u9!=BDJzcWQH0|^JWP$nHn$moOzwQ;? zEqk~o=S6p>@$(+%++_|Kw*4H9m3i{t|Liwkx91oSv;Hlc)qk7!@84{d7!t7J^NSmi zfra~*_&j{4a&6`58@aNX6Fu&i%-XUjy8ntvqCtMP&_ny@!GF?^9kqS`q;0By`O1!i zduCskbXdam=Mh(3DeL5djjt3hO%HEmmTEO$T`IE4Rn3a|`XUJl2YGjizO(sX9ToJh z=CGc#IyiMtitY2n^v{93N2KSZ9+FP^82(mdMrstVw!PwRqba9PcJ%JNKBb8BzOJ}m zPF?cxkhZ+8pEGrKX&&vF>(jBu;z{()sx#+n{`ULEUr@B4^yXD|jgv%Q^QC=v*zVl< z^Ur>L?fy{QaN-ytvYk1StYKnlApt#AFO_Do*_c3(NF^Dp}S$e17P)6(p0g0;i z(v9p}ycLu7PO4s*er%tNPvwTSU5oCnlyObDE^VEqw!7|9kJ|38l{?Z8g|HqBHhWw1 zHsH;45&iEU&cuK7Gx81<=ALzRzu<{95ToSCfula6Fi%Pf7-WF zspp$E+P(1c|C#FbVoRXylBdhv`l4p}87A{;XS~x3j!NP)xwiE9zWpzS6nF1yJh{%s zaL3=+J0OwzSn|pG(jE)i0+?Zo4Aaz1-H@Da_@8s@Mzm zH`f#T+p0`W)YG3VcUE33E@~Bh-mOd9{%@7Z`UOjN>{zlz z<&TAL|9K{#*DCm*yr71`qhvQ;{>ryb{|oI8PS{@eZCl#$HQ&u*GVUa2gyrM*EqX zqCXlVd3f&5m3^ap`0tfpS&3Y<=t^7m=N?>h|HsNpa8CMg<;h zUgI@y!6&<2qBo?z`ps?$t!+B6cYWM!p4kgH6lYJCIhx0>X}4|F!c6VP`*X}6mc7v} zerLY0IN7eu`AXWQwJ%<;IJ@QE;f)+;$zv|xVCEg@13ej z@7ZQO`I|1f_fV6}dzqb9xmRL3GrL==1Z4F)u9`<~js5UWukY>eLt#nZW}W=4_BUV` z_g3k?w~O3(U;jBc>*Ri)UkjgTo?9>@GbtkE^y-6mv!Xfu<6EBjFKImV$=fwS?g6hz zv!~65HnzE+e4aLWMkOT%vK+qnnT0KY!WSZblm|-(EOjAC%JZ^>o5 zMCWOxOMcAcP3@4({%>&g1edz%%dncn`5G^p-6zJfe&}5olbkToN&424IbKgcHuZe; z^4ud@zWMI%bta3qHm{#OSC4f|_TyD&7pz!2!$)YL))E|@5El-8O^)brtOLdXMB8FnYz@%J0D+G zn}&N_{?~atJbm7R&)w6DwOA#bOv?Qd%+~uGyOjBEl;UwN`+7Vjyy=hHL-VY=RR<>= zw6n8IiCxriP13(Mk}W!M!bF~Fb1qCM&-laSo92GOZPKShhql}7xela$S&)-|8I5|%Vv+B9)l!z(!<$9a;HH?n?i%sG&yVQ*w8A0o{? z*Dy8otHiSni@nq?ovL7EZGAhdOzQ6b2X{`b?POvU5s78%y_~A{^vP6*`jn3vvs@;6 zbUd4&cvW$_qqBU<1-oq${ z6WJ@)smv}~S?JTmf2H%Zn*Nge52E*oKIxH=U+&Mqx~KF*$^5O_0k;>LdgdK|Z1(!q z5!YkY3mKW+HMMkYroPW`-=HaSBVtx%Jvo2IJN9;v(NSzFK+sTxqiCOZ#oI`}QpJh}{v$;}pa7ex8rsd$DJV z7sT!bRo;4eHfo9V>caajQ5WUriYu7yNDavBbWgOjDfrMAf9jXpj;S8ri(>vv^sY|c z{c*~bwv$s-YyN668A^2-Jk%B6(NL7mYQfu;a9VH;L-q!nD^Xp{!qW^^{p)N!Rv@*} z&922JA$!HcZ~7-#xV9vlZ)S*pD(rBPkF#F%!k^HIi-iL9?mPbpwLhb<^u#*J?;Og4 zpA%+(xTQZ&C`bPPPRYAd9!(KSdn0Rh^Xq(egOs+sSI>XDnl1P-v%^HYpoZhFh`r*` zhb<2~WRI>fIi|~>raxOis{em!yX^X4%Ov%yJFiqTouAMdcQ$F;x(xNT*TQekIh+#y z=96yW&g%67#`cC2MelWgNU-hw5?;Z3KL6vBgvvk9gU_torsMWH_VRAylyIl5sgL?9 zH}v^*MS`XgUkW+@6@1OHxRgb4x6nT=wcS!2^`iaTBqLI;UtZeAmLsQ=;8@Jlp*@~(b(#PiOZz?AD{k5+Z7|66t_vN+*>TP4rUsXw-Ib_X~# zMz*!BPn@x?Z_nT)%_1olxma* z^c3uyzhLEwHrpfP|SL^+VArrpI9fxqqTgZ>hr$dnE1)rtI7PR!q&LDl4VaW z1 zbLLEbxjXGIBg4X$g{>~Ny8C!-U22)QeTvu8$jxb|r|a{Vi+9$t`F`KX>U)2gx5c8h zM(Xn~n&%zVn;F7>;lz)f{!g+MzCS77X#ZDax8>G5%W|iCc&+@{_;Q6n{IhG83Nn(i zB8w#7oATZa%F$@HVsCSAY5!e0k#l`(V(Rki?|0{P%-LP4G|iiBBhU5qOY6#ReOCYH zv{qw5u|>G;Hs_wqy9-5{88$9hJ$J46-?qyEJZh^`m|KsgYiC!uRusCKa@_o? z_~)w2*6R(N%4`8C*SB14*}p5*e$lo|Qx44&Y|ha=u`X>+(B=vHIWs1#__l4y>{k){ zE|vALuB+`$32zq22;TqqV9(*50jt|PXY-d--Ra0^oab7`I^)f*<_WRBkG8)0{`mbD ziB5^NtRlz1K6u~pwJUbg`MV#B1f zJbQB8?d2O!th+U();le)UcfN?tkQ11%IQ^+3nkWy+}wKj#SFpE_Qz&lJ7wHgvt8xj z&exl!er7)P>9ez&Aj z0k>|Rn)Ng6kJF+;uN3U;e&hcdFY3+lJ|}!6Fwf zT)b?^y5;f2^Y`w#&)B7&zHe{0`FG!lPczfp(iv)x@3|avaFJ5@(g~jqYjLjl6Y%F= z&XM<}TjT2NVtYPk%lqodRy=yoez;xOs6g?<2G%KCuB>8wHl=UYGy9~gajX7hL@H*R z&%W~R-}{B1jEkSooT(yan|xVTiLL+h&e;Vj%dhn5@TtCbyZECmCa?dWWAFj~3yw+? z9W*`PD{fl(x@X2!K|Z6Uht^2vzGC_s_W66=enZ~0S9gWq@7sGi?OnwJ<36d2CNBL4 z6haPZmKom4JWx03onzc0>FWA_-=a-k%zi8>DJy7{l6Io0GiCMZ4^yT*6yM$>U%6uy z*N5Hbf9|s`+q)_C&IHxYXCW!s%NYNhu)LrAanU{F#dFVEzc*f0S9Tnz}@0Qp~;1(+eY|^ImapZ8uhO4=~BOBNt^iulmG` z84p8jb$3^CTnqjgGvn8~{Ct}qW|E(880I?k{A@aRMEJUCe&y1Cte55*mDqe=!@YF% zrWazGvo|c0Zb}ks+^N<3Md8`uZ)$5<9@+1%H@bi3sirpX+LPtMa_cQ3R-9YGa9?b3 zx7-aau@hIEW!{M2n*PB-^UJJPerCI+u57rV;ZPpH>iuPEkiiNW2VKFH3==cXvfY@? z{-_{we)~1;>30K~16$XWN>^w+{dw!~$#vTw3u)d`Ja50q|L-gJPvHyIrcPIOd*u9L znaSd1#|a(29k?SFf^rTkaN zj?F8#Ju6>t_-@ARtkx`R+fQ#*KHcb0oayykyr=cg!-UXR8yC--IYC|dNt)r-M@!i@ zY0vJBjNY{R>{@0u3*SFBmMaZpX1)0(ye3yJ-+K3IPw!zjs&HIe|>s) zf82{pOTE9pyF1(L>k{*Du1MiO{-1BK70Iy0wIAFgu-Y_hYoTCUT>0Z;y|c}Y-`zR6 zr~0~{MMMC1fcm-MIa15Eeo7Px2sx0oq=D^vNV(i}o<9=%vX;z_n$YN*#JJfHTG9~5yo5?m^jsX+1JW-Pom!?6rGE6Iqc#qyh*#{r_zsz>}jW+*F-0>Q?%+ z9XFNPp!v}Lhp(Qyuy)0SX8)FF$sByoVv0`-@@gj2FU2d2~>^~$^^w=^< zH+>Fh5x}mfZZX|9KG{capQ;LQeOx&?>DL|4f0Mg;(o~w~aQTTPID|SLGk9RXHf;L* z>7cet%aJA7*Vj4f9(sCWv!RCitLy8R2i&;bc~K~2VL(S(=o?XwY>lZ}QVZG&vceYoV|W) z@$++`tHYKqTUK=Qpd=_5-b~$e;6Ov%-YV1FTT|AYI&k^3(k9-AoQ6+zCN5N7ZMRZ& z{ud87N5_Xdi=VHH+gtVb7q5oRjy)Csbfx;22i&l>(3mq<=Ixsc#~khA8ARKHmX;Ki zG<7xe6g^nF_)6aMxwP`=qZu>M{1qD)^=~BSuf&rXrxA zU_*$O>Jj}kgU2TgV^e(DZtgktCPr1sdG+PgyL+qu9GU;&uc^9v`{@qx3kit`=qLPvlC;JEHKeRb-G3h3?IK92fw%~d250O3BQtVXi?Ch+ptaNpI zPjj3DuOrak`18k)9tpcUcMr$9B*dOLagp0U(V#gkB}0?R+ICW4VC2lXb4#Ci#1s`7 znfH8rB(1~A$Mw67_wJJ-$(f-OPo{WHRlXwSckbK=b`klA0*{%3eaC0}D+V>kNwnyg zo0lJKVy*uEt~G1wX^wOM9;cmFWlYzf>zF7gDQQ`CMf#lHxgR#_oN`w;ByTgd+jcI& zh3%flqID})Xz07!KiGfh&>?M2&EMbO-``mr9u_8cy?&1foAH*QwRICFM+XIEWhXOF zWjJ$Z(xXR@COz7;$!NyfEYnBZLl^5dvMoDvrS9U2#?&VZf}Vv3T>kRz?(Lg5e_mSZ zea9~SoW;t6lIi-BD=T*NOW4_%=!7%{J`T!B(N^Ajq5r#tw3KJQqf47xbDyX>mvd}n zU_{85^Y;H`EDAn6I2ix_?(Xxc2Tx}h_<#QNsoUG@tJU5Bm6o5eQ9(f=5g~znEbQ|{ znwu8SlH^{wI%?}GvjyMHa&MKqxbX1Z-QC;s?mjAN-28t{WQfZ7o$lrPAFc>~%@BX& z{9Ti!zo+jkeq6SHp_3ky;QxcmG$$T$UAg)S^Fogan=_4eJ=56LR`j#5==;-U`|9Qh zoh)ipJe;jG{kdbja;R0W+%AryK#NLwxx1E!0@pY0Yx%>z@ylMHLygzpNIhI}dBeQt z&JumfrM`SsX(eYp+@Hn0c=ti-QFs4(N5#e2ANI~jKlU)=#`mt*l18I zSLRcE^7Dm<66+UUzB$7#NBnYjz^?`BK0nq^zkY76_18ByH^=R*O1Z=$?~6V%LX4oze$?H}U^YdKTRAM^{%jc6;94Pft(pT)Sb;U-Pp~jYXeb z-js`SEx0D(q7)a%^y;=>j*^~(4pZwgJtaX6tKQh8$m+6Fu=XX_aSFpF&*IysE*T${jfD-#voya$lvo9U($ubCt|1ncXYU;_9&1q-3I5>X1 zSlqv3?S?spi$O)BQq<#Pa);Y^KY#h6qSX9?XHVgQiVHuI`O{vMq!>8+_MOzw)7w|{ z^wYuS{r7g2u3py=a4ycOS@qQ3iL)0k?&>M#ENoRsO4T|)ZMU;+ z<|mqhjrJ7&|M$1@^D|kSiV5D8=l%sBTYL4v8&~uC`u&E<$9C-8`S9ud4}SyNzH@hc zc=0899fRunc`OH`I@d7ipIhPK<8xzQt@Ra2Q^PG5)kk@_&i-jSbm&l0#H0mp8ZHT^ z)p~kz>hOn#O3n52f1(!1U#gY!=INpy{hcxQmix<)toHo;e0^Qrr$X~V z1@Ez&#m4ID%O@(km%I?r5xc!`Abm;!#VqD4b-5D`9+J@Cw{M@U zb=jV>w^3nXV$(lC7LUzqHqF16b7#lKv$IVn-|&2L<3#0xntct4skZl)a7O;)EM@x> z9u`*i;=;rC`~Uy@^z`(dYYgW+6j!cTapLUR>o30=tz?821_{yUtRJO4|jESO}R4-|4%&P zS!A5G|L27*Yu8_U`6VJ{g{f4jtLxKNZt<}7akBFA@sW`yRjt!=nkQ{pvP4CHy@SGo z$E-5D4jpRR^vS5#ZL#xV=_PY+J=niBbni6we24h5va-EZUxhkdJUu<{EG&TfwUv{l zNzPVj@uFW2xr&p$o=!REFxz)t$|aWfsaLZ&IztzqJF#PH>FaC0v&}?BL<%y`Mf$S+ z{o=H_w{o(`et^)Ffq|H)qC-h`6|O zs@Caqu2j6tJ=1R3_$WF(f6-Z1#@b`N{jZ)pzaAA=qo@2o@{X-d){On-d$lw5uQfFs zSQu<|?fmXZAOD!gc&JQjWM*$`X*uxSL&NCJ+qW-W7c?DzR{NOG+1u~*0ruj|`u~5o z^GchksjC-Hoxk~(M2N&s*4C@PvQ|_twA0Yk)6>;$P4(<&SN!0^b?au-?@yVQlbOz5 zzrMZp_qX(Ob55Q=|NPRN&Ee;>R!Iau4q7(t-HdzoYUdt>PuzX3_N{i>T=NAxjh5e? zz`WI>VZqTCsohoK^=5w#AK7KI$oIya_-Q?#MO1vhOADu)^1Xfje{1EAu76dz$GM=Nb~-mI2U z*v6xO&cSE0mG3Nr@I%+;tYJ8+v{*~|@v~=VXP=*Ad3x@&gEx~UrbzWlS8K?MFwBp+ zx1cdvx%_)u9&hZctHlKYUQ2_DX5CTd)?&_VPL1y9ZQOEqM`7}>FE2ekJ!7(pzjaC8 zU-kMC^W<1Y4OZ1_b(JqZe_wvmtJ2m!@}h4+!Lu)SZTesBxMg~`i!HY%dg_VSDy_Hl zt#)TESSMq*a>KLLEkO(Hb}YC)=X2LHzAEQOU#0Y{uiU?WWBU3TcXC-j+?>0|JtXyW z{_>*xKMfOmyRY@W{^Pq?USIdkzl)RB{e6CPcI@O0H5=X+%~xeF|04KCUgqaV<7WTx zm8Mo_i|tOXb!=uk+|HZ*>Y1*`D;Zw{DavP?JDHiHfJtOI`fU(9*#=IWHNs+$Wef3utDdYxYRfIBtpuga05M^)u?FT8BD z)3>u#e3v2g&Ud@&Qib2yBl$YO``pe~Cu9+xoS?hUTqTsCFj)MCW%5-%*Zrt3goc4FloJlqRoG!K9JgBq&UCv5T!}9AJW8Y75?BG3qE@!Sdhr@T>gC5D%=o2ac&wy2Jlp?A)NQw0v)QMsH#`;o^DvzMeS_4ZNm0v8 zB}!C#&T-87arNR7Zy%kew7)gK-oMS>{d`1sha-R4cYTlXGvTv%{mwr|I|iZdU1HeGJ%Nk3qr7qunh z@v+`H=N`P_-~`@dGO*-m2M@!>xp z|L5zXhiflyKa*iuC44^pM$^qWvxScr-@0P|_pd|zea`rN%Q>74>*Jp{r13Fm{B=6K ztK{W{Ti4I2R#rTFgZb|*E9<+uUM}1nc8E7G z?EW&9-&Nf!ckil9nYSlGC+mjAf@2}B)-PA=;heocDUJVQZ*%dn+8F@~p{tG1*G-?fd#}PD_4&xjZN0h&sDFyEng{^tWf1oHu=2{QamyAo~g9`!~NGov8EJc<~)c z;nSZb`{v)2_;jCtOU=XL*#RHEf0s5)n$f*^vyWP^!e;gM^b1zZSN>^a6sg8NS+8!y zY<7SDpHJQ;C1;Lyi|<@@?&jr9U0q#Mretr=yL+(3?(W*2*_xW+m)6DZt^Hk=m&X^f zWy6D+igDRN(jSbr-E#Py`L$|cz>lZX%f*Ar<6|FwEr_}#A_pD8s*I&1r)f&q0 zTejTyU3JQ{f3}mg(pvi#T+1@qJ=J$z<=cMW_;d9qrZhS>=Y|k(GqE6kPLsdF0HnD}3xAm9* zio0#}PQE|iS?(H(YPnm&7SbKlnWD;%EJ?#!GsXHJUIP7jqeXH&QYRo_I4zM7kVO-Ezz z^YiohLpi2Dn6o!2NO{w~n6<_g=i|QD*VxIMNbFw|`ns$6_!|AA30LL+{N5uSK1sXf zQ+Bve-qG|1>ElY#cRS)NcluvHc-rdQi!BPTn&0wEojT$Wof@;cur@Sh_3Mk;%NJxj zJut1czfre;*|{eV6D;fk)a$G=ADX_(?&+SZ_gm=QSJ|aC&C}lPVSQFQFWh;#zUar3 z`Ah!1`m}ksfOO{XOWz-y@A!Ek_}*9T=~{t4!uj&28LlV#tUtbH)+NyHPet2ZIxl|j ztJLvZnv&&SDxY$qGk>Q_;k~$>X8+TCxsz8j^hd6~y{@$O?b*i_tr6_;=GL)Xf{she zKQ0c<476@7cJ%#uRj}V^-@Y$z&c)A6f5$do^2w#0lUe5Pyt{jyLCPN<*_wnC=bKF= z#l)oK?uBYib(-7gW}K1peew$)-A!6QX3dy0XHU`7Rj;qFFE*XCx&AyCceh@w-^ZLs z58u2A2@5Oxnw3>qX*oqYYwN9}M_E^;Z;bHK$m0)}W_W*`ZOu~Yl!Y%^IE52fXWCYq z@l5c}Jr|c{Jlnz2L~BXu>TS8vTeG%4ZTt1?+{S&4iyvpjDIL5rZ}&}B1`CNxVSE4o z`@L~_k!v3xqqAL{jkL}TvkUjXpU!E1^YvPW?X!`F3VE5=+^?A_8~hwJ&)4vM(q3*`#uYA~-7_Y69EjS~l$2G#pt5XvpbvAQ zPx7*$jTL93boA8I56@5E?#n!{_;=-JBmHYT4#lW7y!7gwHP3sm{uiE^FRtoTy`KJd z$`}kU}?Y8LcMsmqUttYsv9Qb^f9pDczbnZXg&j0`0 z?fg_D$>~?-?DYydoZ+oDG zypDX2S$(PQZhu;0Ni^Ra?SkL;k4>5K_kIt5A=B4AJ=ZhVP0T*Cd-At#^W{tGtOQXA%9{uK2!w z^Btqf#ap&Hm1r0x$ZD=&-s5XL{m%eTDK6V|Vj-TH6-9|NuO zG#2ws)*pU%=FB~QruKLHj(Gd(-IKU}O1|p3pcktm)VbI8l4L+`f>O<0Kc-avv;;1j ztVQqd@86zuv@3sK78(+=;N#&rbFN&OvN}B2IPYEy>!uw$ zJl2N2{%Y0yFtMrm%#saP+5UK5Io80)yzl?NYIk>cy_J^Lm2Wfmox8DhH9pS<&yPD){}YbZO?9o| zTr5lzJzCm-U6?5S@#DwK%Y09tJo)g_%+3FIU3u{4<*hfl>BqKDJ0M=R&tu8ipV?_I zp8S|@X;rf?cmBP-w|{S)?y+Qz=Urz?*eY3D^y_z*zyJ4g`TVZ#?wv`8Zx)-> zYzhB+OzvIE|0$chy(g>9d-v|$*VntXrh0X{IBg5N>Xz%!9Ll_km(lFS>-qKnW}0MP z`uqF)&XQ-K;bB`}ZVvf-$F4`tEw(KCy>Ysg(uRd^uCLFZZI+u7q!}a`k$zyB__l?m zS0z8F&%CW>rL3=?e|DC9pNwVKMv*y%-~OCE=y-9@O!X-j8Qw0K?!5Kk!;3f0o;`c< zVxZPkN5(+utq1M=rp(dciWL$TKHe*Ryf?St+a<~N=<0>K+K)foJaVKvJa6xnjSaeK z>*v|t+Lo<7*;97Gg#fL$Z$Z#9?CtM|#1?rt$%KQFIG=cJy$Icm5yYV!Pe z1+mTq#rCWn3i}<_Uq2{x#@$$%$tWps_S5rk-mZ74G0C~HA@}ySc0Soh1xFy=XP;xn zN=k?RGXHt_dydn?1tBXV9!qX3y(H=L+nev@t=;AC)92To>s2rQ#xyH#{rR(}*PBVa zd1@4q#?AF?Chg@N9kf?%ls%uh$H} z$()5rz3DfaqGZ^z%w{-7#ckbHbamC$*VooIukVTBD*kpT%G1*`b!pVXfCHD}Vq%tD z%;>oF;Bw8@U8{H>E%ltN78e)y@#DukmC_JrJ7i2hr>H2~c`jgO$cD43&(p8Or88W1 zKE813)Ty=KZf@FJ{k`bq>6_j8qM}n%pFZVcXT2h}bm`KmQ>SKJRhK`%G$G5dKRvj5 z>p_k8&(6-?y?eL3Ws%GATYt|%#^~+SWvxqITv|F=ub+3bhhWqo*X`dPT{b%>~>Pp^SvHI4BuV2^3 z@2{(=v9ZjYVhkD=zFB{ciRq8C^KOqNMoXKUgPy*4&``0~e}(b8ySu+%beErNS33)2 zt{&)cKpm}Z)0GXpK&w3}CHZBIoBPf?I7@E}DEM$-@v)yeSKVG;TN|o%b$o0aR4Ty-~ zVBJ19Vol&`Z!fQem1@gN56V}BpIRJvY>D24RgTwkw`5=E`(;!4No6}{Hz-cO$!|K= zYg^?~wmn=!MkJ$_ZHko9%$^Uva?$BAyQchk*e>t1^&rUf^)J6xtuR|~MPYV=cUO1k ztpnXIxgUK_ExyXOfHU{Zjkfvo;~gCj{`~xWrwBOD{Z&76^XAU@{Tf@CuEafj@ua1+ zEk;G?YFxU(u@^lpEtfw(t38sN_4JMChF7m%H62n~u_x6?Q|`G&gX*2OTa4bEd;#1- zI@LMMT~p7^wO+n#Sy6{0IIvge7wxpsT2=nH>g!ukE_ZkLr9rCGPrE1;=3d}8ec7Yz z-go4PPQ&}Am`_FDvLtk_{`|=rAb;Ri;}myCyC7+^Z7eeJ)mt5Vd=@*r6_S#wdUa*x zn>RUnt(Kr2lIz#p>^!=+>U++chlGFE#xstI+?r=wJxw?ISYniA z_185UR&a2!weFRvJ9qxPc}V!}Pr01$mY8KV>sp++(H5e`%gJe3^+jX(X^6SY4t_IS zlbz8mru)Qb=i%ZiSStV~@RwX){-zGML=$W)Ld}d@QOS=ZC|Wa`82PkUaD6l`}p|0p1t^Z>ow1^ zmsehvcu&*0xiOi2du9LT|4j=YyPQ5HBO5y9)`8>}r-dA^cx^OJtiEi*Wg;&xAMv$M z-u~QD@TB1z(T!}pF}us(t4%*W)obbG#go03PV!1s60A{wd_B{qIcClE*Wqg-HrD$&)7w3JOX}f>y~q{d6lYH?^(iVOg zr-rR8X)s;1VFQB}kD^)8lVi%3nmKaP8~x^5{r!C2KA@l=^R%S8sYP`suUFTF3wm;L z?~1BhCvO&xTeMK1`{;(kHG9t`ytlf!IsLr({hH4_eG%W@eSX&-%>MP&#og}x`)sW$ z?{xTURs7uixVPVC`kru$4fZRha|`9$M_O#=X6Ix0`pMyu?u!dazaIG?`}X$YUibbF za(%14Dd-nwzC%OxPk;i29N)v3H2+_>JpdGqJ*-^Y(0b#-;^IM%iK zd7fE}P{Fr~Yr9Id*FQVE#Aqg$ylvn1ZCzQ#Uv?}#*PyGDBW(ZwPjRo?XP$X?_QtM{ zyIZyY+L^_X!ROO_r7aKqOZ>7a_VzTkD~2+UPVevAcPRXq_#JlTiqg+lzXtAO+oSpF zE;o-H%QU^(MMoqJ{I2X)m#~?@>HhNGlE}+xXQj-m_m+RRyW2b~@~fyxb~sn=@%n!k zRv&w?n_tQ{$Kkr#l=UkvF1{!6fB*lpb1b*5e!BFpn&138n+;z+WABl((zx@vQuJ%$ z=W?~>HDC8TF1+{k;=PdD>x%j2dHGrjXaBrloV5Mup6kbt>HkXcI<= z3h!-f&fa{%ZgSW=@0&YQZaC+am}^^WbIbNDyqdLs`SQCv>i*u_`{vQ3q^(hlufLWz zy2W14s^740)dt7CeEX}atB)T!av+>(-Nr|6c1q9pW;!Q#c$Rs#n8bs8^@$3nI2RqZ z?l}7BR!;8LRmMU>LSlL`5s{HUbL8$ZY;manc-T&P(hTtzpkd7ECtgYPG5yL4R$9M! zJ=@tMUhWT0IG+!!F3#?&y;^hdLE1`&E7}+A1nh2}Yd(1PWr4=k@>hQ+?(N)kYwDix znAE>dUGz3HKZq(h&G>5O#?$wt4Aqie9>4Z*cl+<3zYOBTeEK3BS+kd(3CT3EI`uc8 zKK}mm&?|f0*LKR?`*bVckU8zW1M7~zkBqh1Uz|$3t!Yx7F?+-Ld!LNo%rrb2aL4}J z<;U4c{tO@Pbxzs-tB*I@IzQ_8)`Tat?R`3h)&42pGU2s!lh01S!1N=0Hn-D6 z=f6j)-yJ!+fbnw9hV^A9uK$13+PU1t-fy*LlGkR=i#vGoh5DZ9JyrU>BH2|`q3`=Q z<>}>hd>1b2-TZwrly6&D%Y@wz6kqYalHU7k8{?m{wLA>5p_(tu%CCRCYrIm#qOR=q zo&y~-Z%+!Ibbh{njJ@@Yr&paD-lgt|esJVzq384jEB>z{t5@eJfkt18KK}WsaxDD9 zn)&|!_tu`hwm%?k&OOtMvw!@0m7(-$>YO<{ZmRrI-}1o!-pe(of6RQrlcK6_C;8mE zDqBk6<}B5Vr&?>To_xLFn9-8=hpm_^_Fp|VbNN1r`kokp-=6bjuYXbeAN}*g#0{^_ zjXr(4;Nl$_85vb|>+EcE(Amo|F^eu{ESOR8;|5!xbZBVkhvk0DoAr#-&%L?5UH^Jk z;kTsTtQL3P;^0keceviCNzS<&;wJ8#n6~X;>sux+=zbZyYToW1Fwa#GgJq-*c; z-f|vPexLf5bM;y0Z62Y;@nJ<1>YQr0HaTcbJ@NLb*V0ptE02^^JXGGkZPNWs-)A2v z+puAS!NU{(rq#vnTK(#u&9t4#)7o6ilj}RT-%?rpeBu6|ze>O5zhdA~+P}ddLQ(I| zeVu^1y%`m+wWIGzR<8IPKl}KRGxw}so%vz6_SM{9bq`uZPkCOReW-7DJ7gGFA>M}3 z;(vnif%hM8d6iBLIJ<9V81HV5tOLu6(`PU1@>vqYw0gn0@H>p3+!PHJ)r%iD-0nX( zb+-T88~k_pw|^+Nsw?NuFj;eQ*?eQY(B_wOHRA7W(ciGC?W5GRy~R2!vJYPtuVaXB zT5#j!^6oz7_6rSjX6!$@G~w8RD!Je{dp_rPE-(F;bz%N4_Jn84bM1b=YTDa$N_(|r zMn#1Fa^`Jv#^!(CNM6~clKArw%LQGpbrU8QD(&=A-6(kKQQw;QDdHwS4^PxH>P&s` z<-mbI`Dx!S#NGLS@KbQD{crp5#L_?UuNSQMEMBN@?WN0kL#Qt?W8#mqm8XXY-dO^)Q8_U9veH$-Lcz*G|PoItX?;jIS zh89=#dZ}Eq6x)5UPx0IAnhX8PEDlPAYpQ?RY@a4(QTlyhS$ciceihM%5T&b2PFe1C zQ@^%(pXJW->bqx3oZ7be@mpVeT(f`mMVk%s$}&tLar@*?eBaI5dSWx%spA>yCkqWU z{7&C8;XH8jqp10eRlk3BWZw$mJvH-59?$C!TzeR0FAAMl%egqZrKC!%w1<`b;rlfQ zp53Y`kUVPnWzCGXM!UWbvukd;9WdDYKIOsL7iXg-WZX(sH{@M6zg1f;mnrYwnRtOC zv0U%SeM5P}e4gOxoKAd~Yx+3eYA#Xjm)|PTb!EBEF-g8%E~|DXM||aC>z=t+Eg?sT zEy_>k4rhX(;@*T+h05ZGwtds=Eo6EBj!pR3BIZ!vsg66Ct}m*R+Wf|Od(RKa!Wq}x zBMUy>KDgD>{@biAzU}cl7x7uWb}PI4B{$#oU4Hbpc>S86Yj*6=u+{b5JUK~EgiC@) zE#rY=;Gx?AD?@I5UO2%;?2y0RzaOD~eDAcSzUd#DwB@zNA)iRI#oq$XXDzH-b^5r1 z{*B_&91*wU1-G5NQcwMR@umF2zQWlng^%yZz4*K*YhixoY@?s68okFQ8VP$ewg*^#jEpk zm#gdF&Af3{qqf9aQ246mYvXCD2}P;39KusnmtQ{_n$#o0-l}obs?f-wwQJ6*FNIbC z8l{%YlXodDJ!!yaDH`@m;*(;bnGk#7u~nW=6+caqK5|j}Ve;QQy;n_~&H2J+&Ed3k zwv({rv(#S{*H-i8^km0rY;C6n4qHxsHE*S|VX5wy>{XMwrt?qP6QQraGtu|!>6qoG z*;_-jJu4sP2F?u*|Dp7JYJi5wLSw04$1BP0yPtBxqC;8&GjRmHC{(5ijA;$peOkIb9L3?Db|pOn3`;AT(Nb-wSOnN@i! z%=Y`e%?+IyUT|Ia!s*7qJTDJ{EP9GnwX z7O<}}HY#k|{Q2(g+v6m6Y)?G)eDTzyZF8zOZFk%um7zN6Xpn{oznqQ28u=|brbeZn@FYJLz@Azar(JvlpZv^SCKBU*wvq?!10)f#vJo(?2}c z>KjhYt6UHp`f{m}QPAnos>k9No+c+$e~sbw$;r;uH(meTw}n;J)a+Z(=3mD)pU@Ay zG2zhx0h>M-S@y#(OcM7wu4=lz#6rU*;zN`tpW>%Y*B0k7p8Xt5y;@yPJPTR$P?OZJMYFX19?)d93o-d6rKP)hDUroYH@2PDobKa_$Z2jMT zkx?<-+gS8k!yLn1RxYc0lOvqkE=~|?&8@v#XveyAPg98G?4v?lx<`^aTU%M%54V0> zujy{mVR1{{#DFCu@{qfVQq)by@Kses$Cf6p7GBOYEx`R#OWunk8&Bk>bgf&ceZHu1 z=j847J0dPwUsAQz{cg(O7x8NQ=Q8nX7oXS4qCfeg@7!1Y_*t@fdSj<}%KUAwAF%R0 zi9LB{>BYHw{~TC)y;dpal3&~jrUS(nx0TlQ%>Jyl#w+-9-sTVOrT@;{p6?qmv#b98 z+%tEs@P3hC-B*3})912C^Gy;9qz}An=9AZSw);Nk*`Jg%xB52Q)O~kfuKri#luN(d zk`U#C3HRM@`Tsreg6Bgp zx5Mm*zwAz&(H3Q@-mq?Z>W_&^d9@-^rxVEXV6tkaq0Z>zo1&!=Ck=JM~Y?-m}k`RGr;EO;$HdB)51P!q};BuKeo0~IBZfh zdt1%7#%+5`R=m5^93voUutt7IZItv2zP;*By2xJjP1fskdSdQ<@|B;Ton1X$ zU$TU4^2sY!GA-@*Cu|Rlj^?gkyK<%CF1hA|1?A=KdLD&^l8GB-Rd$JOI(EzPc;D0M zuOfvOi$&jG=j6R8zt_9>#Kb!TL*^EZLTuX}g8M87zF!Rfq{(45@2 zzEM#b;UDj8Emc3}m|c7F_14`d4zLS6on^QBW68}UidPuLx_W$$oH^_4ROOi6Y7l+# zZCK#t{)`uU?ewOf4qq2j`RGXJ{!MmTb2S$lz5DT3bM^AKlYE&KRO{|6nDJt6tbV=0 z|5-V9zrH>^$6o&AU9+8p=?mthk2a;R4Nbx{zR%fVUi$UR{FKWdLw2lw_(uN1tzO0N z3=YO6J6TwE?KBiAs8MQLbV>4PrTnJ$x6}BUBcGZd_!M{DuYJo)^Pie#lK*}z`5<1f zXV&BE{11ZrT`V@q-|<Fntlk$lV-l^b1BWbrCHqU$Mve5S4){*WvI~gc3Ul=n(2Oh?XFt$A5{-eTs)oP zF3Nh|yP?}Mpjyv#s>%89*H2cto_%99DS{>7>I_R^#eK^Db9eswSiLw+-kLGae%JiB zX$M1|uU)fb=brs>*Nn5;-fJw$_nLa`dPAsX>9ap;z8|YC`m$rwgNuj%m@$=ViT`)l zqnn`+Dl45YyK4_G?~+WXfY%p9mwdalxYm80@Bbb5|5&p7=O6G7zhJe#r&n6#NPY9y zwLZ6N-K~!3{pIYzaaDF?B|vvC13mc zp>y>~o^`R?y=S_-UD_o-c7!e3b?LfZ@U-4_RtCyNH;<}$@AA#ii1&~2^%7O{*io?j zC8yJIzlqQ8R8Oci-&%I=tFXM-ySWA#S95)%Q|9i8)vpwBI<2(5HBshpu*hxw{~{@| zmGAGI|M>g*Toa3PmNjo~q;K5VxvZSOmR(1}E-7F?-=0ISA6NP9yX@2Hu~dlv`?U=A z)`K5D<-NXn?DEN*Gj}BBEn+@Y@FM+yO3oaPh(*lod}rp_{ytxMpiQYuBfNQ0+Jv=h zeedskn6&Z6ty8zo-Me?{l$V0Qrie9e+x@njSIJ&1Ygbe8^V8EKmOuA*F+Dqy+n3j^ z|6*qIr|9BpU%v%$PWcrJ?w0=ieeRWV=BeY=_I>|8J-ffQqxk#Xp9`4%mj+yj)JZ+K z_2%AXF*VmC&qVF4KJxqReEB&>Raf6`_jqSt{eRlUZT;(xte^Qi_Eog#fr}UKZB6Cg zlAi+9itXQzb>*8+J z{Szk2?pgbUwSQ}N$bY-6#}D&zb2;sA+_^zWetmuY{maYCr`!tovRtsW(MizYt=^AcWqD6uaoy$C_SV+U&YsBeOY+EC;mv73 zC7(WhI=}8$rk@|5YG~Iz%e|+nYV-|1CVtvnUnqO}{+@{*E*J7wtXb1g+tn;w7qDfb zcEXX1yt(yHigwD$$sO;L{Vn{VO=D3oS#`5Pzv&P|IcS|Hcz*7xD-20y>r zWs|iQZ46N{Iq_?Pnb}Fr$YowHuT|%`q|e!W^o;0Ni#c*V%R5)*_aEk58*%*rgSNK! zMwg`Ageb9YC`^ef6bBN za;=`LH}=Ey#|QT%JLONle$7)Q>Br7hn{y-y{ee=?_>V4otgW?>^i^7 zCb7hwut_=C8TvT-()%-SgyuHHN9`6hk62Ktu3%bs=YYiD=7)R5W&T&KneDZ-X>wcY z&E;<2{_2RfSH@Ufl3o$g5GZZ1`SEkNgr!XT|9<_Q(DIf+?3{(U>YvFjMOwQ~)rYA& z8)$9T^Im_nPh|1#>XHpV4);2<=lOHqse0BPcWyEFV8HR$r#qXMCSi`pCdB+emwZ!`)S$gQ+m(d878?X9dr2^xhY}| z&+acRuDtUkK6J$G-V}c~>QAP(?piBR`wO8nCx33cfAG_-@ao|IL5maCv^;eF@aE<^~bMEine^~jycwbKE$*sxF zudc8Ek$kP@8RHYTWBaRY+}I|X`kpXZfA-F=li}xghRNimUVHCmqV@36w4ddd{o_s~ zx#U*w(8$S=hzQ!9_wd9v{zvIOeVzUq+Ism#npX29(-9_ zH~4G6xpKyDe(aBE3D$|V?E3SK4(`rd&-TgbQpUUP)sNJcT6w!o{QG)o*R8!bEepKL*5_O6AjM>Tw-Wm_wrc!eDPHb_YcnM zX54qSLGZ2P$;p!?4(;8eUENfm&o8)R`how4dBsgCdafQ5;d5>X&gsuv_@a1L)vaYm z&+qAboZhBuQS$Kl)%bV&TLq-@kGNKwtQE?9{y14tR_BZCi^JM?HfBtoXpz58XXXRZ zz51*h&Y0@*#PYFqw?ADj*I{4qs&AJ|V~WhVT}M9u*zJ?BrQdkL)Mu&9o`JSA^7S0- z58Iy+Uvl@_4t0+6!LwK8s;h^JRegAVx>I98Yy1BtFXYykb6$}Cz^%Ic(o}v)UZD{C zJrx^s-A(7Ow+s2q_%!@u)Dos;x7=Ii%zVo7Trc95u28yo@Cp^LFAT|oYF0>t60Ieb^XL|?kG>+6RL zmGLhV7AduyZ{KgfWAkN=u;*_Ne~p;C!%fw8*JXpSboRaP`_5;_WE=jtZW+FJ-GRuG z)1j?`jbZBQO3It;S1%1xXJMFstiV{{&~l^f{nyTO%&!0N=ik-W-|woFl&*;ipDVFz zeR=!Y9}j=M_vbir@y5=^#L3TH%bzj(2(3KWY|1}Z!1!{1_r++pnvF$Qn>^;6UnD!7 zvorSI=8hR3CPt_KU&MG@@6L__El0K8^4sfP^WL2NdbgTj>mAQaamvOEZ~mS*=ezKX z747QPFQyBevMjk2BlG;4QPE4GMJ;SMRy{1dE-w?kl#ToA{EwgK-nMoQh`+b|?dd$< z*EZ`^l5$GgO^^!vozCb?yK8htCJ@47BHdS$N2twSfgp1+yTDROhJ%2~z5`wwmV zpq?4~X{~dMiP+mK)Bnghee(1#IQd&TN_Q>m1=lZEb@?0R)?|M7T&Q>KN5#530BbnM6G^vLs@HgSFWe1DJQh4n030-U*}TedGevU1xtvAVl^DnG9c zj^Fk26#K0L*1W@s9a5>=MWg$yAElg*pYJ8x9(;Gp!^s;yKiRj~@$X(|x4&1n9bIb6 z-54h2ASD@m|J|)m8CzYooo~L~Q6<^*OU`}U=elL4!dtHkDQBE-|8m>AEPCzC6;r={ zHriBt;6m;CiidsPyQ0|7{H`thb}m@SKx}&FJXOUW8#|sCCu+X`cRjNFTG{+>YwzFB z2|avfh1aD0d+XL_30^t8Nb9}t(i4%Vf=+6`bQXM4s=a1>`nYVt4aqpg43#`6eeJN7e{&04_?C&axdjVe-N-NI)Vk_@#w}AHvv$Nzk zJLY?vC+FU(Smbr5^2?3~%dWRvt33H^V;+Cmx%){u`V8K-<)6$7L@sQt2#MGkl={x1 z@a%Sb*{QL&;`3z$`Ihh56?gah-PX0%_J?*p`L#}W<$9V_))C8WHQx|Qs$2Iri((ug!NxOEoMrex!hdOi2@7io%}Wq+8cwZ1?Wgvdnwd^LA&+z8U8~zPfXF{Z@$!DzQz?)!%rs-XDGWNa}|6 z0nVM1Vt0LibMvY%%b{s=`naCVi!x3+^lI}Tzl-k4PFvT0esmywL#d7`Q=?1Ld$0N# zjiv9d?=*P2bxCabp-oq`vQFGu?d~Kde)6Vi_Tx*ntW5qI&wmNkZPA^sC-8CSy?wTY zbD}5advF9EYRR@=7g4)m#?j4z+pphz?f>-M#Klep*}oG**md3>3r!KWT5{BJ_6F&S zz6i7Jp6A%koaTS3dTi-M(PysmZ9f!d8<>ebf1D>~BlzmPZ|}c74UtNcT?>wP1byXt z^&pq!_}52Y<-^x>>L+q;(b!~>mSe$veMR)qn9dgEgn})XG=!?Y%F7FF`wOFzAi2zA|f=Dvz9}6 zLdC6I5vC-$WvzR!?s}|oBd(?9#!L@8bFL}R&RA`JaMYk>W?j+0ic*fiXIFO2-0&_f zPWeMf_tw8(s_J-~Z*IAo#dEW==>EanLybaW@!j{OxBVyyVPM~O^hc*{cGfv zPFmU&KVUz-@AmHv8-%`I&fGBn*rRDK3W|x!(zn(=on04dc>CMe|F`oOOlWD)*uG%S z(}xQFR(01G#TP74`Tgf|!upRXcf23{&m9c zbl?0^DfxL%p7wp7+4SRrf;@YGFZ-%1sR!kcBp=vU|Nr6K-HaEGM1N|u-Yz=eA@DA9i0etGevQ^zA$oE%|d}KAZ@m+M5bHO*Zh#Q~dpY_JpRxR1X zy13!Ec!7@2g4v3KT)H>js3mTHrJI?u+%9HUqVwF+l675T2BzNvb{p^B?=oYB!pEAL zMK?Pt165l5Up(C(AuAx;-Y6!|^NPb^|Acv8Bj&D`zNGP&tH`QogSoi(a(U(lGc33s zmq@ADvfXz5>2rtmUsO#g|GqbcA_?m^y?v-*#9m{}U~=@L!;wYJQL-)mA`_%8XEUu^ zJuxa)wK~~&(XUUd^7=ZXrgHuA309gjA%EEyd;8}{9(syyuI|02f)BsmQ&haF=6Ayx+xd5M ze%Jn9b9lA>kGHc9Zglf3{c>T(28jl?r#51zcB<++dslDVH$Q+~4n}^Y8AHv1g5`v@|}k=+A*?vU?BtAKs_KIiu>reBT=_Z1KOY zMY5=UT6JO3<5!8Vx>Wc|_2)fZk|r3`q#ikMbyShj4} zi-WUz_lNIfvb%rk)TT#gXRkTKqc@%Xx8}y)OBWXMCM7!mPO#iKS?N(hRJo*-<|XIj ztQ`8{D*f_XInwU(eRGsrJ6$|3tv;lj@!qLd7Rs+DR?K$sDfVgobBMZ=T;eD;xN88Q+Wx{&HJ8r!afZ-eoeM9&;^tu2kAmxi_ehA;!4$^Qu{QvqLWXSFrrt zcIDgm#m)<^mGaJb{FC7MEOkWpW{X7uN=#Tjg(jeRZd7 zeDMBh)(q1ZMVT)g)vWf%e*5GW#K+_puusj8O*Hj{T>4U5%gQg$l{sh5wYsrtlibRW z60$qh^s?W_*N({&nFjMeDO(q|54?iTQlEggiZLkWMz9{ zTFo1MozA~Gxyj!0CJT1&>sUJPchDy(PEEuMQ(WM#SD9Gl97n^UevHavWDX{TE# zyThrz^ZrifGe7IUJg}_wVA9vK>iVJUYTI^*#Yt_^x_B^Zh1RJW=HQD#<%>f61GKWm zlfCaW^X18_``njZ;MUwyGiB{Bp3KMs!H*jSS9EO>+Pd|^E~!&dCnWXHPtLD9$#6~g z&k5&xXJrkxYTsx6^Xtuuo2JJfQLkA4;9|D+J6RiE;iq?OPbUtmYQ*4b87-{p}0%C*qXIAOuJUa8f=t&_@M zB`iPXvup81jnu=sUTMum%Q9s)MlJ3xIS|A0>Yk0tG*wD3dbMYO?g(aKjoDf}kamOSUKCO#Z zFBD4u%<{i}By85>3yMB`(+ZzENDBKFu9{^s`-nlRW#l=b>}{_?h2osN_bqGjV=@c4 z#A;I8dyy^S`?UGz4_NWXZLg_em{yy2GxyQ*MPH74M$Nu(WZvr&?w156L<@ZKtaJHb zS!Kxm%0GU-|0DgqMK9UDsu%v{h+g3KD3wF{Gyh3p&5XrUBt5^rSl?o_+T_xTtBX#b zGM%KpWr@u<+!_^`)+@&DzH$BZ z@p)?xsk&`@`*z@D9!lUP$Z)+CbI;SjqxFk)GD@dQ= z>)Un47d1{zu~j-*kZm#L;nC^33wTc6T9jh)-Dbk%2G>0OMehQPjXTTsPhkA~>b3Fg z3uj7?3tbniBbiJ9*uIYH^m|Tl=GAP2oLWU8O&JV|Z=zndhIH z`eg2|Pd`+@m=qNS$0^+L=AN)A_1>P!jpp1prak)Y|LKKpvs&ejqi>umdbE<$O>Laq z`+DEB*rh%>$+&FIs=A56Og|O=_?&nirs%EZ^x$63m9@v#MqKU;{rr3CGP}bDJEpT& ze0&|Qx$KdGjoUoQ1%`rhi`hSL%rvOX@iz%@IsYLcu{F}OO2y;JzD z`0Anox88l33lbYxHi*UlZ?f2L&R6&O&z5>^*KdnmE^|x0iewcj`Pw{rxlrEZ_9&iN zChF?$>gnlv?cN8DaI-Lpb?5#n)0PbA{lTCcd*;$-%ZBUQ_AbA_;eWK{^ldrE6yn#f zFKRfjym@;SqwuxHEj%1ABzl)r?>}9%(9PFPs&#`^s2YFHEbc4E+&`|l<|B~A7rpiM z`DaNBYD!mE+|`xpeK_T>c2wJpkD}>e*LMXasBsv*7JM3G#O+)E^yn?eb3PXyxGZ>g zsafX0J1d>0JMIQz^DkUIm-FkB_0yWq*-?NR>H?9Sc)r<1wo26A3>UN_yin8Eqc({{Z;Vbzw64>gkfoKj*p{oZc1 z{DkAZFW$c|G$t+5XI`X#zomBOjcK3$e7dmp^AERb=awao(<>fTy0&aPaqa2hDGEM! zrxrV&ac}weVWC@Q$_hVG$y*otEIygNl#<=8e>!zX+3Y9xtkV7;J6GegHgFf4q}RNM z|Mt0kDydn;%-TOuwLhyX(>vn8v@VX_8$YxQANTQ)^ZY8hW~F&f`FFdC3w2A^$m%nz9j&Q8@tL8lIBP^JDuhv+8+qu8$J4>!B*jzRDSe149{my?6u6{1$ z_C521gW*x3c363mX8rye-?hmS$1c2(xF`1hVXk59Ww8LMoehd#L%bIs?T(3Q(|olp z!P8YrlJ8wpwzu_K9?78mMaNgBcD$)cemm8BnvLPBizaVb-EA{&hShXsng-7mpLlBh zzH;eYM$t2~Lzc0F9Rb#a7 zsXF(C^;094hp%498}o-LdbjZt7QW@h0be#v^cH(OJyv`3xxCoYXx6;r-*=nN(b%k& zd)({MqqfOn&PKe<>eJS9@c&V)nC4@~y`o58H@+f}Q%|nq|Fe#t;U7a@T8Bwk?l|Rc zcDC%7|MF#zmu|xQ#1S*I?5Zm*9&ta&2rPbe3H>#8f5aw2<|qLB`_W+_%2+Bz2pZkG7%0(~CS-g^U%jEs@ zW?wD;qwe0nnoHjP%yW*2Wo4`pcHOa|@~M}W?zHc{xXm|AGmd-mNSAM(z!u>O^lZr2;nudIivzTUO1PTl_b^>TUFhK;N4yxzQAo-JWQ9P^5-#L8~N zrCjEBv=)RsniQ-&Ju5J!xAg6=N?{+LDF)AO=!xniZd<-qc}w#4snvb=FF&}mEX!-f znx?N#KUQyu6Tf(I_1x`t@8nX-jLXbFU7hz&Vz2QAIqvTV&)qNlVfK95S{>PliQIp~ z*XJ=GE?iGr!);U`iE_Disty9Q{*h z=ey|oy;iH=YXr$0`eeO(+qR~+`wrB9l}diwcQxa8Ul7~dnwovj_Hg%o?EX;g{%+o0 ztrc&r7U@p041d008$(N4)@|9$?sFWUHYiHoQ+{YR-^YRDOdaFeEoJ)}zgexjYPe`` z8Oyc)sttRER^Mg!m$9u_6c=~=!%}ERDUUB@^%*$;sUKy@bG}pMkqxj?3-i`IfG3v@) z9R>QwH$J{r*I%IT9i04FU)ukrv{+*F?4nPTmaUX>FD&`a{rbY8M&7RE$FJ{SQTSjy zf8L%MZQl-`TgSc2c+-2ijNSiQmb2ceWiR=#Wkpr#SCN-`JLLG5$7lQ(E9g?Im#Kdg zx3{CMe{*{H-7ec1UaO>>dQ=`dyYb1ZUt6o`b#&#ft-ljCuew(M!(yVIys~fG^yg`B z4sNNEIVTo8t#?(|d`Zd6JkPHkzPq+NUwmcAs~0bxym*n3o0}_@=(xLd(Ox_DmnSEm zdH?;*3hjEwAhyRdR;X#1NF9Gw)40JZf6ku`3H?&5H)|f5XUW}A^E2(!*-ruY{s@`L{>(q|&CH;?9KKfkTi#w;muGgh{QO(%9rd-P^EbcVeOFR&A3L+Z?>w)DzfKb- zEZE=kR9@=X`if}|Obu6+StM@DbV^>mw`^j1hQ@gV}*C`qioWk{2i3 zn@sOLT*fQEM(6)o$^zv z9n%*F&2FF1d8Kgaiin@;sdoov-7`1;&cU(C#JO&Hw|95h+nSi@t(!J&O51#s_ieS% zU9qxUrZ1xQUvl^5-+y^|`F{K2XXcl8HE#ElT{*QkqHfXM@ap#ClG)!ksHR_Mzbh%% z_ogN)`H@lI(wL7ix66AnygQm3u6bysY;+7;{I>Pi%h_vK=6*ABs5Z-4KOw+T^~~w4 z+cVc&XWiyr@NJf;o$bbzrn$mWFWI=}Wt_Uh@o3}B`v-nHxAXSBIHA4AY~S-KE+4)t zDM!7qS1)khQ-Rg8vV%m50%Qeo2=>l%N=O(N9&#U?U?X7)8@6O-v>n_Y&y(;j+ z%>UYJ&TU^jQ@c*;=K8~*n}f@W!UA{Q>L`4<=}X$1j_Jq6cw$Q)>Ff8%{dzqoE?DTF z>!N1`H|*Zt+7#h)L;d#eE#E)oy?*nC=l6QfJK>9-AL5YVYiFnpT^X|2t#?<=&rkBX z-_LpH9qTo@_-=2wN{y(;*SY0B|BCDG8J+rd@#zoK&-?uUN=G&C56`^w$N7jW=h@kl z1Ha^*xW0XJ`fRgl)28+Lo$KrC`@lT?v?=d>uL$k8lh}Ab+u>G)uD<74`Nzq z&+W4^V&Cdt3;oWpWHqn8cfgl&<^2-`W%sQ8zfI~Z`^kIv)|G0PSU9K%{oay)e_5~k z9NiB;ZG>YZ@)Mcs_LaWAc449O>eZ_?t^F_Vzj<}Ri}gy`+Nwa3UM0lY)M+Pa%G@~$kL@t+5Fc8 zxlGi|x_-@D$L)AX^p=vZA3qkB=CZ2u8ZC@jEJe%%*gY%xNkX$R(({G zE=?&}Gn?Dm=;OKdi8YTh10U6B__&^te0FB$=hy4^i;0N^eOdxqNK!TZ$%_{aeho!C z#gqj9oPPfK;h$v}+f6#|3cp=DIlk`a)Bg9L{*`N}sHo`ZT)A)WpdysXzgs~5!5<+% zx7gU&=H}+?>}=x#FE6hqp}K#6ELE+#q!yhzwd#%d`k3flS5}2wxGmtlgsE}D*|dq< zEqM3xe##Y*ID7Ks%gg@uu^SQ?RsFl}Db5U5`q3{ebK}<5T<+ypg1o(>qocL8vlj*& zNHFj{FgN2b&mpse0v4?Oot+D(napwuxb*mVzr0CC!s%)2Y~-d_+zaHlShlZz)@y*{wF6Zow~Z#ycWTvw!U{@TMTrKP3fdNB*0cnUtv3i!g;aWZAw z`wMT64_1z-prXCEKT?JR)2qUQ`j%MxTr{ki&ZtE>jaB!pxJEQ2cHGMNcA3j ze$c)K)Te8dvCU`xbp*7V_4Mh*P)8hBzuC7odaF=phbpi1Mwdfr#XkC(8Gm_{qH=TJ z?y3CzV1_&AWfRWUL;oiJ%~`XyvZk@MmG#f5hbtW47{snJR&Z`-HVfNd_xINJ{P>`t zNmHk~c1~9^3Jnd5jEcN;_N?~3Jr9d^URdAy-)QCu|Z}Acwwl+Vq`{iuEy}$qeneWS&olc8yEm|+_C@%HB+4q&T zxYTu@yLbGhu7)Nn`c7Q6NOM=J%P%^mT=3W~R7J64kTgyCe{_NGsZPU(rXjKLuU$(9{ z@`PdUv#TuHiHG{G&f4M;n7=yNG5@OmENd?Fjp0(d3-u)LIPBb*9v(AOb;TMc8$At+ zP5iGGn6;c|taSf4Vg932OBXcBEI%mFbA0L3)jy9+i@d~fj!n@-DOASt`{L@40zs=5 zTRmO*Jb3=}$b%F2Ry{qb?&MKpGKbSnV&3mK)ASjuq^_F$pOF_QbNJ5Il^o}0Y!lNc z=d1|kWr@+)xOYj2M8C7~8rFmDF_)XzRNeFx&s8pGd_K4E>9kqfE}WcuL~_}w>Z2pray~7#P<_AVZRK8Bs^8Yt$#qPYgKfk`+N>(sz7BiW$aM`<>qPtsb z`ra95T(0fiva-=m`l?m)o`y!Zmsh7;*i~CqdS3au)3-NIH?I-tbYW`M5#Xq>(fioO zsCcD~#m{cLr<;TK+icvOYeq{w!e$w&Sm|~sBYZF|87nG+?us=k5;l=*d}wh`1*;P5xbjzg+$r0 z&2o4ZZ>6~5%rCR9HM(DOZ)M0|$x=HLtIM0)f7*W0b?ywetcBreDu?&--e9SXHC;5* z%B*<)tw|lPR_W;Gc6EK?=H`yyTctYH>t~H!vtzqmp7W_?rMa9}A8j}@|3r|H{2kMI z)8~CPjtjn9*Y$l$+nN=A|8KRMBrbpGkuqbt`~szr{gbsQtgf5&A61chkI_%U(D+{FD3Kp)`m+4mtTCgi#_M|#l2j`$j(gi z)J_L~JGNWh(f{_c9cJIU;q!eJvF@vz-OZz;qpPdgr;F*z$jZ7Z8O}ay^fyi1#NpQO z?-Q=Ai``xP+|O&qGEOg3l^x4_*UJ8Tw0m=N^WxUlUq{O?S3l?7S>>W_@LMjchK}Vs^8@E^U7B1M~eB5tduFcywZ!2x~aVCg7T3KW^+jovitCy&l z*t98ATsS8yy;{TOn(w?edbgF8Rmah!KleIyzZhG{n8_UVi7B{h%{yz(oIh8?<3mG3 z0}q+_u3M*@`!=VQsd4F2QITyPI*NXoCa2FE+=;try_Zq)*RNk}tgNCUA}J{W{&vAE zB3)813_n!Fv^qJui^sFt*vZ$YEuQ#!;jP09FHGFJWs6PO8wph($l_Sx>8C$_`Xb=H zWLj9*HnVME*REaQ5xoA;$7khMwvHX{+Y=AB-LL;YS7=#g)3IHx-J4G^SxE@JNRPOE zgM-DXX7Q;v{To#0%U!jS+0dIHCMYOaR#w(8Zx338`s9DS+6oD-olaV!hx4?jpJuJO zahg?zPn=z5!A!efYu~=n)6+B0zqjPx>ZLFECrPR{{Z}~1=$Vmt@NrS=2Yc>EUz3W3 zcV|}BvHhv~|L?DH`niBfIa63_;6=DO%egE ztUaqN)}5K3emHI8LlO30k~aGmTs+RQb-5#_{o-ZI(yp(IeR0jswRfVx-PeguoW&pA zcXxEF=Wi@cN(xb^mfn!rQM@=WFE4s~-rWs}&1=`{Ugi3qdg`>cf?WK`vuDqqKCP{- zy>{I+^N(6wf@`b4zq7Nmo1&t*D2BIdmZQ={52dMx3i)+2Ia+Pxu79z){o#>kQj*eF zvy5O4s{*El4Svg=0THrk5#T$1ZbtTh2`<&rO;~o))w)+08wdusMRo?a%GGY`MQav3>l;_VXuic=+|X z*5!3SpH5#JwRKU{ll`9h@z1VYQMj+9Z?3Md|NiT1p`CkXRoE<6>}`@`3sHY7E$!US zS6WiCM8)&s?en|u@lKyGaq=IX_p0{4PrrU_p5qn1J1H{k<$U#n7bZ@w`M+eBvt|8@ z?8^C5rq@6DF>&JET_u_4_4m#Xy<^e7uK8HhrpDG2hi)A^cJ7*=*3_b%chX{QEUUl0 zSr@z8C*`5MVQ$Kf(`S#U|DRze@ax=`>-tHrPVCb&&tLsoZ)(TdH9D0x^R{l?+Pik{ z)TyGg&;Fc$j*nM=xxmezKYo09adGjkUB5m)K0f8@@AZOK2M;fZj^J3BcOXtjfQyx5 zQg8CFl|`R8bvs=q&71e{!9ixP86tZphxUGO{yu-s|0;=(OTRb8r+BhE&pM#0l5$CX zvh#nwuaXw2*QR`r`ZLqAjm7_8%BlGw-yb~i+`PQyW#8-MMT^w@W}8)i`|)5|K}Mo_ zV{x`!yuu~{$L`B7jGt63H+i7*eEIx3qq(k{1rm0-N0+{x{7dOT5^@Huu~Q;XgbU>n6xcT-D3pl6SZ2@2{`7x8)WW6)obqU*B6) zRCJYFx^m~wpOx$5_fI>$dUk12@|znQofb}*q~iMi$W@DKZRd9a0f%HLSL>g-~h6_DN75dY1l_3T5Z z$&GmnKK%H>dVSfvOARHjuB>$Lmz#M`_34%WtUY(*a;|4@I&Qz1KY=Z%HrvZ~uSLQe zvxx7WavoJYR?KT>IfyrNs-FE(%;%HgpFhDoxZ||u1_ov}o`znFq$3}m+DXMvo>UFo)^G&?lr!40EOaJEjhcb`zmQ*y}K6l@u{!^1rnSI{h zYtlwHx5mmJy5MT9FPx*d+LHOdr?mc^N*3p~?MdO+XS^(mdv(v@=}STFb9XA8HgwIE z=5Rig_NU-+xyYm`QzWd-6%x*!-@Z=%#yRT-+$k>^1dNQ0({Dg%{r)m~o^> zplfoB{PFs4bu+GSt96NMSASS}@KelwedSZa=H>$NVGWhBs;4Cx#Q%h-_a2Fi{hr-E zeb>Y%#?{|)ij9r!`qL8=8`m$`G<)lkz|hdIYt|iodPJqShDmx$aJe~8uf%5Eqc8ev zzs1y7l!PwX^)T&E>>P%C~5U@L9@7FWvX><^PN4%k$py99&u${;lPT*u%o<^{%&O zw=jLz{lxxaPV>|0zfE;Jyh|_g*~(tNcrT##?b`g*H}BjczQ5JnvAXfx?L~(dmi(za z|ICj67vFUA6U)tWa&q?ld^WpR+PtcwB0%iJerMKJ*P@*=btlfB*FK@Ip{+gjw5ZyJ zD_;Tv6HZ)N8LVj-^d&E*cZ$6Jb0){_-=hr{HLZ1gxAd&$mxZ&#dfrUf_dNOii--r7 zNjGCsLT<)PhcC)H<8`R*v(vup`E}o3&NiF3La1EMSkEHon$DM%*^-8zj^xg;j+Ey@dqZ>Nj$kDS12d#eYxP8>cR^_k1llmG+=&xXT5h~ z*2*oh{fXXw?yLoz=WLExUa?6z30|+Y{8@i|#bSq(2}xfTN{9EonXoNgOvm_<&G{Dv z_8-6OI(TW$Vq)~+olx2yKCd5fN|2p6l9T>tqLBcJA@uVZa?ep*uD^nY7`ow5C` zY0l5Rf85y~w6pkn&?;Lc_s9E|J#P<`-LOTP^S#^5^G@eL%e68sp1CyxO@z;iNP|oF zqFcVbvz+aF?cR&K8(4XxB~SGpOb}StX8EsS2WRI0_0!F_{MJ13iH%3zDCNYxz18YI zGaT;f{OA`5Y1p%eDP^Mw*Na>caq;lbP^Yg3wH8x8n01uLFflRx`TG}CHi)G#Y-cOG zQ)ic+Fx~TW)HcRe&fA6;ZlC6L6Z+|E_u{yql8QgONo!it&HXiIWnWi5oKYV4E?a6& z`0AkKCUx*~qbD2AIo{2R(zu*t-(Aac;LYM@c~@4pt4D252R0s9xv~A$+?#)&PBO7b z{q8d7Xoqn)gTcltf(;>mKh13Ju`SNu_IF|JwZ^N@|CZGr;rx=jaMklUBBD1;o9=mg zc*~g=J(Oj*HT9SU)0*kicUvA%sS7SR=b%z%@I=NSy+K$v|Lg)+&I@b(_wqWYy}fa8 z^)5@btWYhE`RkZ;8W^Q?628qkuyLbAhGk)a`(mXQ}eW-~vB}GaXg^!9Q=mSaEfQ%~q2w z_s$-9dWU=Z=Z1fWt;?Ao2)z?Ouqi3!TvAB+5y@wAg13Sly#Iaap38LJ%;Jvt7n2ql zzV<%-_p?7adwNSL)dtUp^> ze_p$G&4MkudH0H_aAu*02L1B(|GvGwJw-+H*W-0;J1SIbAKW;RsQW_l_{HK0Cyrd~ zGMX$OYRIa2vh%!N8smkDf#H?!A87vY{v*W_dZ(H*_T!^0o32+kZ(ZE;;aTtlo~hvr zXMTJ9KQ-s=>&Y9x++Hbo(D{1V>)Xo9{zu0AG`=z?-+up;%nYr>pCP7cK77+E&G*f@ z%H41(>W-s&@w*%M!e&;!s)TGv((cZm(^(Kd!2%Uf`Yr(afCs^Kh znlpX=c?rve54)Z|Wqfc{|8!pShJqNWP41yQbzYxjovL4M75&aPugzX2qIZjVj^U(N zj#J!chw-I(tny2dJ)Amaqv;*>+LzN-3MvLvAFkGsE)e7Wm-W_ns;bmBqkWBs4ybzG zd60R}H2lua10COYO!2Z<>!QcB@yrs|y~;Jy-EL;BUz!oi`$NC+8k^;pmzS3ZFZYu+ z%jxLuUcGYV!kkC@XRKPa$}4XAt(&((!b2VN4{y5>rz0l3eUa3qMNzzh>#_m@1il2U zEI*}L#lG%X>yO#0$#+%KQuoWc8$T1bRAneW610Er_T4v>ld|N!4GjZ~Sgana9eZ?` zKRJBOyCXq!b{E-dFPI?r?;g*0-{>s+S8sjK@7MV(zir3<({In)OKsut@tJTo_xinJ z_cTrhsdE!A|MGBYd%WY_A0FSAaZAN7{oZGOIr(zh)shoCAAFj8U%RN?y=?ZIhiUsu ziq+#{vw9_UjM>_`d7s~NvuM73Jb#+Mly%zkJEw*BnQ+TqomaNnV*i|bJ8v6&pIw*z z+?shp%xAWz#}z_1EmUmOJ@9(pGGXt^cc*%D4mvD2Ynv1$zjET8_-9TlS3Tb0?!!C1 zE0C?E$8A-)r=#WK;_naNZU1vk@4)F`&&8JwY}OYV=$oDL&gIK65u3mG*_`$zUaQZ? z*2GVH{P_V(`X?N1L(3$QzUH~-h8PZO`22qrz=e)o3WW$vgw zzpIXXI??D*n)%kvcgFMS?Da1eSO|-4UBzf;p1l3;74DmB<(&%pBv?Yk3(t8}HwsVN zi_zeEIA_H>aP!x;osx@>7dZ_y43*=e0L%nsTU2|HOHHEv+rv zwmtm#gZH6O##Yzg8gu5(jdgK3^8J3jzvrYyX%jb!-aV7d|M{%L$-Revlo&rf{zBH= z+v(Y2=VJHkXSqs}URE<^yi!lU&EF^}##1&`Hu~?$#yxj8hu=N1adw@Ln)T0#vG2C( zFOz4x_O99PM$7y~zpwaBEPC~0>2iCw_j|rZovnO(X5BfNWINLptVbO}yVI8+3R$(} z=IV9(x6CaQDVmo!z4~u=Ki}LxU%mP+{hYk`c)R8D`_*x|=hif*-uoGC*lBz_!u0x@ zuD#h0{~s)rNdNrk;@z0-ayx&`db#z@jdcZ%LQj;7N}LYw_gebVa6{B$rI1sRWzC(t z)a9c&U-uR5UwN|j?iq*VuT@=3qGWoGTedAZbu2uhpv z_X#|@&ADiv{f?zP=es-BhFplb7q7qjcd^EkJ+jZ@gw~wB+gbYS%v0-rZiyVR{^QQO z)qiY`UFL4Lw_818ZA{^_Guz$QO)=Q};gibU^V6dLG^*ET@xR>_o5UA)|4-)jZ-xTT zr>$N4#@bcqPjdCa37^*{8K0;$KPQ>bz4qI=H?NKuuG;Iuea>BXN7lE-KX*5WXO*6@ zd;hEJWqYQXT(kPBt=IRdy*0UV?`@!U{yx5IFC?-Ylix}GO1QS?^8ypzt5+Svo#W!- z!a^cGyt=x2&6+b`zHGU2WlB%am*?l_KY#jk>Xbd}R;^mIa;0Hm_QitA!vdDAH+uN_ z`R!|de3+scyg=SL@>sq0)cuvgVR3zSQ>HuTKQ8q&yd`b=bB_4WYuX{F@9nKFwvh3f zBx2eqnNKa81P^eJhTrr*58iFpx?IuFaNKAM_L zaZkGKViZ(vy#L;YI8Ak*r+rJZ!qbiXq&1xGep;|+!x5LukDPYiz9LlGe)+!M+}gKq z*36kZH+pN<+b3_7CVFs`9B*s0vZ%eNx8d;m`St&PHZrsSYp9u}c0{th-{<+-kME?r z_a>i9$uya=lU?s>h^_46iKSb6<5x7VyS6g==SxoIzf7}|@9W7fG`V}%cF*3ud-vS( zT6#(Cmt;%l`c5+#C}f6B8Bt;sSZ=lMExBxVcwexpeAMkkZtsh>i*ymg}AR z`4?tAx{?v=Sz^eh{Gt-UU zwQJY5P20-_I9Sx~Rb1$EIC5k1+_|<%M>s65{LL5L_<2%v;o?pGb!KlqPyWxhadK?$ zwtKm@d-q6}nsV?rd=P!WvuV>NBYS&&W!t~+?(Y8i^JkY7>nHXPpCxs~qICqLqa$zM zx_P*esYr~Yr9da+*VL%Da*~CgnhPwpqqQ4|}98OGo6xA3w-?{pM^Xmc&D=R)pBbGW}Pfx|T z`b979JDPee4bf`TiV9vV;Pg5{@lgKWS+_z|tEGche);$J_Z7}0&b&Zmhbz4w0Y_ql;54{zMR z=Z|k>q~#f=Pc4gG3j-(a*%h@iWYKZ?g@+efUiy9QwDc{;wv#E}UR+%4+|IXi=gylq zZ-#9CXU$<|a>a0C1dC|T(WK5JLXUnXT;84kOseT(h0VQ<$;W+c%)A6$eG5%*x$yD7 zywEjw&ZO)gv*TI%)Lz|o45;dN5I*|Rb@yR`f3K^34~o}Xf0769G5_iBlKWTLBrmbY z{`bwjJ|R(?1!})sf2Oo)Qc!98N|scsmB;jYJ|^4l?)N@svqkQ&XjDts+NiFhN#5Go z*4EW8iXEDhn9fbyQ_W<5;Ae@~!R+Pc<(*LhU-lQ9Zt3=9apc}t`1shDFD1dkm!(nz z3p%FB_NvLqA&E*9iDHGD&-Q6uXHMO-Dt9S+mpE&X6TK%ze)|-^GlkNH= zh0BYkPF%i&S*g(E;>!6oiz-)09~b}2&}JeSAL1<+n9cWh&$0EH6WM)cS-!Lte=HY# z;!m*o{8R6a{Zsw0N$z4c|J(SttA($n7kv5PsHoeizff_q-8I+xul+q)VoIy~<|M8v zOgV7(gW|=*?JcW5b2+|P|7wqm68E1w7VYPqk31}x%_O~c?#+}mv8s}Y8^1xNEX0ak5dbA8F5*e(?0`y+z)y z;<6fQexH4^Vf%y`VdrM>^}UXq5gwmh>A6(MZ1&lwg_Sjo{mbhVuN(lt zTidO3G=IhKmbxV#^|>%B$?1iUP35FXv!*fHGXF5uH~)T8Sn|*8Y14jvI@7h1zd-;hYzft}kuz5)l{OTNleTmtS~-hQnt+ z%ZFJ9GXDPlzWj*C#pqp93lnXRD15&ixO$@AvU^@0XBar1ewxJgv}mH*BIAGOG$J*> zI`asaHdfjTO?tJQF>&(q-mjtzvzGk7v{XBM-5iluOeGhMPOexYbtNoWIrZmMRpC90 zzAt55wv#hD>)v~ATbc0Oy?RG=SriI>w@Qoqsh&vro_xKwTGoBy+r1Aiw9XG-f4|(= z(lWApN!Nui(--RtiUaky}{C6{p6&&|F(t4mq)z`p30?o|CREl zSEAE<*k4~uu#Gvv|GV|vz4x*^s&gE%j*d>+WdHBoM zv`@)TKFzvy@#5kVi`PmYAE|zc+4_Ew+&xX#{F|azmum}zhJ^{`H=E7<^y$;&Nt3v_ zx<7Dcr)Fh!=~({EJat*;?$h377BW?*rK1eUAvlbd)wOCv!zwty6zpj`k`oY!>M#ll~nHNA}g=ni&cI7 zi({C2y&W%0ZqIlk@asaaw%a!U-r1dtw<$ddVo>|HscyrQs}pB3s~^d^`+38PQ>(rC z?}sThbna$h|NiFY*1hKK9sJaTX9M+4!K&KE%~i%&!)@Kn!d z{3|oBZtu&KtrCfKt1iaNA3x{vVttL_{MT1^TCZVk>kQDXV*OdMQFz_o9iTm*-TAr~ z-kjCud=hQz6831%yj^ZA*H%mMZ{uB6-F!KIlHrb$MEuJN&e_PuBX~ zy}j0IYR4{Jnv}J#UgKbz?os~e6Hh-)nk4k1|J2i~7bY4k6iTrX$%tm-k#OjoxM|+qT+(F!%UKiX{{JS2 zXX)1k=YaB zrhRX@{^A{Hr6+USoBwsE*YCf^J3spT&hXjSvP`1t%^KaJzdx$%6JqfTUi@`g(BGH+ zmD0ZU`!kz9eda!O`jqTk8IF*(U$&V1*t%xTnS&pDdwbWqD5)O!)**A-l_)ylw z;2A#8wq#ze`u1jL+1p#7X;0lB{!5zvI7w$~-&nBTyURO%|GG76l>gNuY-Q3MjBw{~4TE@2Zs*Sy~+SaG5iY9#sU$L}imz6oY9QTSD zHO%UKtIu~XJfZfZVq2Ms_KAu`Z+Dp#{S;u!3<{g&qr8!AmE+~-_CdlmRTCHFD^ruw5QBq3V{ur)$-UHB-JXoH9j3Ts$;n%412lEwdVV-QADd)&820rINM% z>JFK@#Vy++D{?gdnH{*jI6JCH@%qdEV%E$TQYZSC-?(#Xwx?vy!p@&z%bE?_=ZU2SU8RoS8_WkJiS!&(Vrwn})S6egmDIcr2oxaiA zRpe6-&%2{fi>#HiUhi7G`xmER_?n}K8(v=#%wn3A?8B)3TujU%nqBNNzs9zAx%~az zk1eu14;L=oDF2<;KS9-Vs`}68x6VHLQ?%~x15H1<+vnG8Vl2^JHapJyw5$8W#{NUc z9V6{yTyrE1l!C$ytA}(y6*o&^4BG^UWeSiviqf}Oq}=mBX!cvu8VXh=P(xV z^@z&e+_kASHE4SdS6^6O?X3rTGiY2{c)g?!emCz-lm@~ z6%L*8_lb5b369@8W4EMfTgN}H{zrHADxGd+{}{+)H1WE>>AK#G5b2y>t6#iP+aZ^> z++bp8T=K_W$t7n!7kYVSF$S+%_-wW5jABEX|HkKQ9&JkX-YL_!ZJXIEhs@`9gnyhq z+AThF!HO+h#>tEOD^Gvl&~eu2YQ`~Z)$%Les#7FY4J{1~cM9?U)6mgzd9L*>FexZ0 z&CTjhR9qaNY%|w}^v@sMvJ-Bsi`^|}Rg!UenXj3d*^+1Rs;dJ-&dm9HDd>fL_v+QF zU%g7va#-)n*1l`!PRI40t0u1KoxUQh?)xmGqiyRnZ6vkwZDvgjxoT`QW5vxG?6=QW z_bAWR-_`Sco5`9zMzIIOa?iQEefD^<^tBncZUrt}+uUUFblZbvUsrs(7G{_9c4;p2 z;$=VN7CO`@Rjc}DuI^gAqC)1J)jGA=d4Bb|3y)n{ba9)a-u0#X+Zz|ITQ_%ZZMge# zz1Ur4udaBqo|@`;n^ipF*Ms2T;J<(VM0va2doyR(j_PPLwFN?oCkwL~EG)~jg}1Z$ zGj3_#z`>khTlVJ0rqt8(9-jM9X``*}t*y=dY;~unx^}ioaWS{Dva(H;v)uO}`K!x( zbXL1;HOv#8H4}7M@s*XqPoyeBuRP`rcXnp3cvtoP-R0Hc`PS9d3j?-qopUJXg0{_j zS6A2I<$k@Lor+gIt}w24Y*~Bk*y;G{*mp1Ye!O}sx6xsF{`|PPRx_vJFa1bfH#fI7zHen8J~7PT&CX2C%uQwff5_W4 z{=UP`Qq#L^0ZaN*?z9=Lwwj#&?NBRseBIB~yga>~LUDC7XV0{H0V*IJl^|*vs2H zD{GbHgf6Sa<})I!cH6hktxmqQ#B<@og^!Q*HqZAwyZ?!n_WFbj>(mcQ8oCEFV_)5R z;~W^L{`dFy@WxOjC8e;%ycazuo?168+{3M{%|>@#AKw;9rXS(n-K&*quByys^Ye8} zTKGTGbLpljQ?~5*apaVjN!8*NFF0q-5t5!gW5$Gu69Xe6A_4>BqN7ju+zYr|V36lL z^CfqeXMApM?%wkE_tx+GwaR*n8w*!Iv*ze$>n}+a%>=H-EjA$~~3E$M#l#zvAEN`{h-extyI)YUUGgSko80F$A$ftrn%2v9r$_g z+xeuwcbUR+@9ix9y~}@@we8nkHuoy)yZZlrUg6uX>A(9KLr8L&|7Nz@T3bH%$tPDV zT)g=3;KSZV*2*u;u||Yed5Zo>v|mcj#uQKhkv@- z@+n)j_gu8uy25BrVt)Sqzf*?x=l(nH8pjWrj2h~w!_aKKPFuETHG@QqX<=LA$az(?#5WZ@1Tmx7f~3o_3`xb<*=o#VRYO+T5L$ z*lQaqrjsH54?ti;iVKR$1sUcLm#@S<|MuRr$x69~669SmoxKnVHUR9UFUh z(xgXSU0s(h1^p=MR$o3tQc5b}{Hde4ox66PnZ3j~U2SgvGskC*G6i1$u zxvcY!U6MDqs$SD(&=9cxUUFn{NAYaKyI&6e{e6*LBqrc|>T%_~xi`w+uq|ttSI7VS zi_4X3DHd`z6_)bQ>!9-D3=DwKU#m8^uuU}-^ z*|+Xv#>aq%+YX7gL>QW}_%l+%si`=&TQVrX$wwQGHJ$lx;*ZrxxVSJ^C z@AW$Yr#J;8`b?*EO^~-%J9|vqb90we^5+EU7dy=T4A)%Go85o1-_}fNhoxtzhDg!Q zC>z}r(+@c&^Q@Rnrxg4D`}aG)$a~K`Ep6@oN{v$|P8^clxn!o~%MU`$;c;GGMP+4X zeEA{XDwoO@-ny~ae9B7Khwt|FED%bR2ftaMiTx|S^={VCgwH?Qm+KHR>xa&xmD*Y98RIlp}S$+R)9{`M>L z?9Z-__a)N>UW-nf5IXCeO?mxJZqcooe`cLF|DOD4#fHgE+*(gQedVdljo zFLwNEH;Iv)^lHw`a&KZ<+P2!? z-)et<`}*o?_mw}Vlg%G$I=%1t;4^)?WAVzQ9d4gB*B{9eSShgltSZ}1OAq0?xJJ$u z`~AMmd}x|5fn{S{xJ*~${y8&6jPIW2ZV56{;JL9&XiCg{%K}C(>CTSDSFVU&-YS(4 z`+--@_{8P^2E1>c`@P{l@ZzEKmlZc=)~$Z{$@Uae^qDl7ua}z^+OOTMFC}hO{-TZL zi}wR@zD-MB~YmHN-EnqSvda;RMj>D|`Kv2n|sC9fJiSAA%n zXu2ZvRH1Ct;R|8+lcyOPY+-sTqzQ?_1gI`fOf zb$woTYirIvjR`p=Jbjk&LjDD|)B3iu?u=fb-h6ekihSqFge_VT>-GF*%~(>!b+M39 zZKd70iGlODCS?VA2l8^MHb45jwY1=UXVm2w$?X$o&YU@Aic22nrF%z0RikFizIjWj zd;ZLsjmJ3;iQg?M=H?a_7LJWI+0Pjl&EoAs~?6R(`m}gt#mZ|(%-s3*fXJw{onke*FN4_53YpXv#ey?dM(;6vrx76_l9k$YlFp)zxg_O zio4;}s9l^JC-$#j!l>V8@!9Hd{M)3Z6XgZjHT-w@6umhtwZ$jIDrTAen$}M;QFU)V z?60kwc`|6d+sW%|bh{51n0iHONlks_&K%kL=!W3gsf`cJc6Vl;UG`p}V+q%HgLyZr zPE8H84Zc>pJ>koTlhN#bQhVyoELWFm3tMn;fknN1k<^OsF43k*Ydzg~dx}(*oP7P# z!p!9MCgvwBhz|=33k(bl3*)kNPhGlo=FFLmjSC$X98T%Vx&DHe?b=bbi_sAgYhrho zy|}ROLw-$-&B{OZ;Y*jM9y{jt;f=vz(<4b6`}!7a{W#Cpt!>t8Ys`vsALy zi5<_%;Lu^;U9D`%*uc3W-!LWo{kvJMnjbSy`dj#&(dVw+m7Szwb(V3e`*e1@74P?H zX;t+6Iq96ZYh~Z3iOf5=!khjd4v2nkZMn|+mv6k|UY|?1n7a>^x&Kqu-P!Qk!pn13 z>+i!$W?j4#S~};uYe6*gbL&!Gn_b*_-dYQdilqWme)4#R9*lpxT=(zuTfA-CxFVKB z@?_?3N&o)nlf@^~_wTe9yjGE#xj{r%eSzGrx#x||j<_}SCb0{46rWZ)d#ZB7hGQDO ztor8K{1Zb&OYYR{DE(e;cYlk_ns^(*$sw(_)rO1nV#EGd{Cjio{I1N;54Agr7O?$U zk>q1>HR6N#rD~@mVX3KC54$hga{MJvo}INecmKT(Uq8Q7=T7NpX*F?g>2^8qr+Z56 z;^BHJqZE&fj2BI;++V(Y@i_axTT4?j^^o_}sZ&KQcDKFCm~6Cx(f&ZOd&4J}SJAv1 zB?@Z8|Ni)#x5PL54!+e*fn5gPpm*if7w! z1>HSRB(s; z&E!kP|LvL9ysfmZOIGPfQDw;?|9|XCUQqpr-R1tHC+pRSTv!6)y5TO4t2($Zl?K9`yPDw5+V`hyNe6uUd6#)v2yov$BqHud-X%bNj*PpGUF;8m}?4 zWv#TlxixuB__jTN#U-BKtDR7(?zrtu*o!}hls6yC?|bv%--?A|9c!k{KA*wrS$gD_ zcQm_;uk6*9$6cAL#lGrX$|>GiQOz9{Q7paGq4-h`cbfz6q*a@LbGT3VwZb7QJ2^Ks z_wADxPoCU4d+eB7bhJC`Se9{3N({jv=jCjxzrVb_)LR_XpS#TEFIjx|(Ebl9ZLO^nw`_3H?OOb-DDdIK z+<%wizE)=6n{!Y8#zi!WMy*lB9~1Lt|cvsq@9NnGDN zJu|W}cTMC`z1D3P?PKM?hClv##I^OfX{4IstMw_qXYjcc{ZqYxBFyfl%?UG zY4G#J!{4eq7QSG@`hziwFF4rP+1a_#fumN) zWS#8ky$e$gJH6kObhJy+xou7S{&^}>sy}LJ>$`_FFVoi6UcKrG=be!B>j8Y%H*DM1 z_Rd&cy*)%ZkbUj3&lkck-^r`^{k80E$mIV97EfO7j}uQkIA52$HZ=Icf$P3$OXTLa zTLo0ulwMRnW7IEa8?^lR+!v)`p`lwf^bQ_6G>0?)$&(ait8huLZ>foynMp~P)_rIz zD&neEYA)KbV)pE4504Z7|9#&tU;jt2N-F55zR!h31Nl{}S8D~zd#&A97n}Xyn%Yg% z1y^5OTPwX$%0++r)rKw}dpXH}o360Vl@R=QYMzJOta7FKb%(A$d)y->rB%Zgt*WZ} zO~Dp+1<>95|f$;{l?_`pNnJBHswR=O@MDJhwz zA8(g&VS#S+wmbW3XNUajo*1IFdetf+4weg%hxkoRO+PHj$SMk9H=8k8LxgMYoH=^& z`+QbST+zvK^Q*m5u57N%?F*NlDX%~HwCL*mXIes?9(F}aUqfSKWwpEfy}T0Jf}cEn zw&Ee=iIalbma?cek)M#0GWyp3U7V~+XE zG)m1mE_^p2@BKdU5B0iH?2QiXow*qcIoH=*eIeYy{!4TD&SOW9PLwbWte!f1`hN|x zbqf{T(GEjKf49)mQc*7t{lG%Dn~}F3#9LdtTmp@8w1GN-yOej`?|IYJvDnM) z^@qgI_HiGY-c`;IUG7qJ^iO5M&*EELNqhIDevjcll6CvAo9R^;YxipNREb%-dhRcAd9rM(w(Fw!8ah?|qz8Q{k8Z}JOQa_~TOqrt5)!W)D0UAC4Rp))KqE%J0e1 zc`Zq)si_$m9@Lla_da|RnbFty~_wJgKYd372e6nYIvR~$zwTJ)tX}l@?@k-wM z`rBPn%?3-3U#nQu)Lp-)(!OuuHaWLcce%#X8b4Mazt(fR`l;UyyZWQv{~x|M!F(@- zn^$?k(xVJ5Z#XzS8ExBp7|v#_=9yT!yXi#N_x8O$3xb&^eys{#r{kRR_KrhJs>dpx ziCaBa{^U}6?W#KQ>*T`U>+a=RbRB)6F{@o?Pc55t2-!js$xrx-t2g^BQNQa&Kmid|JW<)la&3=mQPwg|M0_%%)+e#S45AR-1511R8Dx- z?AhLH*e(WhNj3fWapcI7DX(5h{V=t+*VprFam!axOG{n&fvs&)xyqi4DqA)F+`W4B z>yb|3#>U2J)21zXHorX~H2mS`h-mJ$Zl=u@p%YJdOI~HD*fC@0PRo_fi?%J6@_qDf zdj7vHh8itrGgyUY9!Pw0JM5%&xf0W>FOi2Cq^4!q7p?Mt_Hn&l>h;+YA5GeFd7>;L z#H9D6eB2k)w~kTEJM(Z-ow8A1?bmR#+@uhxBGvmv5B?mj5NA@`-MGd2VF|amQBM3* zaZA=$DMFU!Ukx5D3(~85J>A;S<=XbCF4rOt-^dB&+8o*%HRHrB)!OH~7PA(udn4YV zJ-g`P<(V^1oSG~gDcrA<*s-SIY=_%vEz`1R25l#@X4F=l{BiU3|L>=p)ic%go=5V{ z+Ak3vbwH&;qZ5RZpLbAL)8j^f}-T@3z2`o}L>QxqmDyym0#2)2Gv>OgT`tn)xB` zv4RbUr9Zs-`=FV>?%&Vn7ZyI7!D`~N2TjN@;>4rv|mYv$^yK~b$=c#M1&s+LB=fyIYFlJ@# zfNLv4A88m;X~>$DJSsJI+6; ze)*0`CnkMt6j>WOzcD+Ri#K~s#mAoQETP+%pXcym+1H)Yz^>aU)@@>)_eLb*eE5Q; zCvF%iDD054IPf=cNm2d=sfu;lY`a#O%viI9Ju)(qWtHcbH6g*lv!_f63W|C3AYu91 zwXqQa0gaRMLqeuRM?`=|!Q<~Ycy_Hyd&k@G^4lAq_<#@PzP@MY*;c>1x3~Jmg@w`E z^K^A|RHpvt360iH%aZ%WlVP#o{^1pxTZJkuEiDgz_6}kaTDeW?#jeac$IM0YqH9dL zw9oB0CJ?YYDqG}UAG3q|X2WRH53;h6-<;=o@18t?`Gc!^!|6LmPtTd~IXwAWT!f5C z+PCksdn{GM?fJ9+b~gWCR4Mw^W{+^|%8mR_U9O#8nV_&eY^Qyg6surC{T>0~&@UTi zX{&F#^fxmgeB$9}r@k3YUmAD#6jm^1l1CD0;EES!b5R>V=CJJFj62T>Sm^ zv{|KneOG6DZPNa{m?uC+ zuv-jKIxAC}gnfUker{(wOYN=En(hDQ3Rg$p_gpu1_w8zF=VQ08-rZSYq`X`rppDlh zOj!AgN{~S0?@vql*WH~I94#!NmZf<927`Rq;stN_?ug;*{u-rz(IGoeVUt*fp-i~n z;u~I1es&Zk7`{EA-p623{o61&<^18r6G|m-d9UBPn1g?JAWx3HDkFSQ&RFnc4ejI<#{VDtC+j)&OG#G z`IW?*w{OeaR2XPzoVays)|EfTo1|83=V~_>Xygss{mN70%?h{c>teTV-Rda|O1>Am zi)zFFEl}8PWNfDq**oWAmm9msQGI@8jV`G4kgZ0{fKQ9~?-o5nBpZEjoezeU0^ZkG9k|k@a zZhrXi&nKy4&7#e-?d&Fs^G^>Hirk)n5F;bx~;I)oJ}~omWh? zjtWHb+B}=roPBR^*{uh9Zx(ahy!t8dLisk9eO2-{^BMqWUI`^ z!(Bh$viRA>#qOXTTdV%gbTOT=f#pv?a4_@#YuB%Dtt^vpoS&GQ>iTNJiona4FE;7< zz1yXrwTd@qWxt-Z!>vin=63&ddVWe=+0N>!UH6ekbNeEyGjAVQv2x%33krRAb2hD9 zyY^k;={4ayo@r}EKghF7p7Y{Qgw1r8tY0^0oNo=k_N%5O=xJQFFK5A%>tgOLF&U}T zr38~|_wCq`8?a^md%+7cOm4gU`c-9nui)y{t8ZVucyj41>pxQylZ>;u8cp&xZF#J< zZTl2q9 zo01TrHqr7ASAC1`-Szwb?aIBq?aP;vB0;;}U8TiFZ&R53&q~`?eS3BF_Pu+K((3Os z3lk&$e~6bfWBRiv<>aKt$NNDQ)ea}CC<8siRcBKl9X=fLXZ8Duv*W*;USepyp1$pJ zdc(0j!LzzM)^sk=d>_KQEvu%zb4_BA((4n-=KB--lES3zm|vB7Y{;78tn8%I%JBZf zj$01um1RDS4C3(c8>{Ltbcr89urvcVOIZtQ>E8Sh3((L_oS(L;FvjLsRz}f|9okEM%WR@Qe*E}EPNB+hlE;#jnf=~gUNTm_3^27;+srMPLhFmvz zujrE{Y;%8V*hi_u?^ri)+^8t(@nup3uYlB_x5knDb47mYPhxTAe_!R79X8qI^y9^x zhB12WGudyXi9}hdiP%Y<_#(VWe9fdwo4RJWZ!>= z?9C0wq>8sfU&JdkG~BhO9yo6_GsLu{*Y^I@k_7@QQ%&dGIcAw{!_`}Jas8fm$!WZ0 zLS8CK7njyP!^YjjDgc;uyx8AexjZb1%zr6jv{QLXt|9m+7 z@9%HVv#YaBj|jcE$so6`@$;5NChKRdeR?h9jTsLw@7J$iPoFyFVJft8lhoyFdG+qv z7FWt2bKjHhzj!%)$LtRkdqldQ6sX=^t6SMOak|%556<|@S@B()|6lXXzn=d&TK22F zRlQF?XUzNIrt0@4-X4d<1{hx?FIg#_cmIxUSYoO}Ke` zYk2s>`qzIxR%o0!GqL|lMziet66rJSlP1l1ks450>FVQ?D1W)v7k#*xdoSJQ86utD6;E_CjG}J=Dl;Rf~R-JWv^cN)kj}&`F4BTf{JeIv_=0UMUNW<8ou6Y`B(Im z*ycl0Weiih@-&`q{`BPPW$%ysc`Pcvz6-3JWO!SxWuw}ZkoP}NGyi(ccq`-0uF~0N zxmD+n%js>d`Y)QcHJoq#vDTXYn7_&FN#~Cx-gEA)mTI~Q8Y%!ykd zt9jDc*tqkmLX{-T`oqUxN-o;*<5JKUxtORZA$fWAuG%RR1m@5Cw`0KqhUH>w*RGy? z@Y$NZDpjdjfoeCW@7o93NxA>`J8LJ_?BK0QDW(CZOjuv|fr>4m$mnR}+TAWLYomCd zovQq`HJdNK;)Bzdn{PMEY<=y0;LiQ+{$}TF4;uvj*IbhnvFwt2N9wG@f>NhWZVY*x zdpKxvPjOwU*IoS;Oir=3Kczd@EnK*5-n0!r<+L?cwo9&CGcjQK?%M+2*Re53e3LiJ zIWd88Z_L)(YyY0TSKYCp^wpZP;;n!GoM)*zEc&7JO|4*c+3$GE5_RR7A(u<MC?_)fz^P>KpL-WOZ z{-|ww$#uuQ-X{Ou5yx|Cte)4)>V6!&XYgR>n?1ZIIHmTxopg!)beYky^him4TdLRA ziqI+@*=**b=40j)LTdMAyx6pMv4-!?g9~m&j`E6MeUe5I7Pp{x*P?+?nxx_MeYjs>+*oC6?=kGrIvmx!; z@!fU&9=pnt{_nf{{QcgT=luK4GcvLaUJ99-m|XoRc_!TGZ_A5R;V+CcBX6oMP5t(5 zn_C;31gG}=IYE(`y~X(wT&+y5?|RF6?llAnCCwD{`}XY{sF2x~d;39r&}UtD)2!^7 z%N)35XS>`|JKGm~d#+V!(|MJkb{DO+Y}LO?UTr=6fAuxytx2KCq-|($ZEFI%wEIh+8p(4a>zXP^^LaD zO6ljDe!XD+U0+%jXS;0j;^PAE+4bjMb=c|1C?($Y*<`zASiEIGv*c>WJcdQn1Ex-$ zsuZ|qY3t6lYfW?3ZQ8s^LdbR&Z+2p4PST>)tCz1m`@CR>?7TUL_7rflG<|)2{qXnq zXJ?x``#WdtTX|K$TVjpgE2qHS%&nDIq$MO)%&YKsS;IEL|MgG4f_KGfwdoODC*%c! z7^W=k;yz{io3ACi?Ebb>)0j32ZF#nOrKQ8=WxLsT#MmVD#1=&rHC|isKl;s|x8<8$ z?e1Fs41ZdAwo>QTs_%bv=kGJW=cdrNwazJ_3Oz9UZtf`l47SC^Lh3x zkNf#{y}19IhgQ!|*!Bi~PVe>PzEz=d>p=0l$hJ>rA`< z-`4B0Ytz`YGFre>bh_1VS)HptKlRRL-Ez3<;>_(lo4py1GWM7*NJ%;~uh-5_ra0BR z;_ky)?i_-uR~Z&BUFv@BuJ*QH4;FZoyt}=#*@sW}ZjJHnq=%9dHA*H{p8ML%?QhCA z)8S{`hkLib*xR2idi(X9_e*1jc_D4*7O}C;ZEI6=pSwir)D5KGDTD9uN zjU7|2m~52T_wRzG<;^osraXD_WX+m0ix#PehEDZ2u4*_v!_*QvM&6)`Qg74q1Ek1Sl*1g8*A$MbUOG-=6 zoH?_+xbWr0#ml#D?d@6^@j;dO-hUgpLpu&Ge>*#WpJ!XPjlJNe*Tz!<6gF(!`0C2Z zmW^k`o{3%iuzM(;FP z_xD#u_Ge$;v-cX#PoK9}M|W+MbR(m9+f|PBiEJ`+XUzf~{&{khZ2hpyfT@ILKgb}ufZ;)izazb6S=B3Ca2^d8B%R2>u* z<+VbQzEQlLPC!_Uh&wD=IG5(z@`Xx9d|8x3_n4vT$v!?Tr&FjjI-WrgwdM z*Pxs6|KH#6^>Kess?VPg?Hn0yG$o<4Uud4f)s@DVXZ&Q~oilNw;7Vtu(6Htgp%dAf zTo~S%T*&A(`@B$tmwk(r#8nTMFIg-0?X%O@m%r70j_;eBTievBQ#(07R&2@8(()fL&s`wcp?1h#6FKDRv|BfG*VdD;7F z@3b9TL$da5|J!Xjsln{qhsqVVr)Vy|>wf;%lgUTDr=5|1_a)@@Ckf{3n_1Q!zrFHm z?$#7j6A5`n`AI%ey=HgWKF{pAs!+8wG&Xkfgc&mPCxmnxM?HJ~ywhdlhk8%X&YL%H z9zE)Mp~*uf=vxEN)x2iKS_9!A9UYypwNb8Gk{VV4395?o1H-SUrE1+}+ft>brnZEs zGisYu$bR38i>jq-XIXW2{tH&;DbFa?JzQh=FX8Nzw54i4{Aa#+`@xCtNcp5wwl#9U z41PpBP+u${|Ws zy-%6EElv8LT(A^8Q?7_4WG3 z1?&4<7X+E}|F&j+x{YtcwGGb>gtpzP`pV&)%bI*$uKU>jJ2rdIab67VGrc9hT+ltw z&SG zc$540ex#SwWQW{-;BWIWsO-is(^|DdxmWFOe2C2^63qG7Y z+`h5$C+mk|SJz6X8kxS_6cKT8$J>gNPu}9m(YV`Yw8608frGgC^y_<)GFipvxozy- zRknA&z#XZHS*tI;NZM6X{Qua32}$z~`1r-K?uxoq)n?09TDhnA?nNfs>4wJb53>WK zGOa$p`TKO8)J5szwQSzConD+%m$t;%1!o-xEnfpI4!bPz?dW#z+Dc9FuyawekxOzj zmc(u8eHQgq>U;gPLhJH5>&;%7*FH0Ny3I;++tbb8woArYiEs0nD_atH;rjoa1?K6W z&h^&qoy1pv!&YHN(MRr>cS}xRcKm(WlJ}i|tSUbYC$4XfTEsZV?-zV|eB1x2zU4-bPHXO7l+f0it#RSHsoADCXKE)f z{px@BUuEHy54{KTo|Gw8b%tt-sjI1}t1b0dxRaISm`I#tV5(G}sCX*S30v!}+BO)5d6R};)5zg|pKY=1w+Ba&C)EMv$s zvGWak)y@CS4eU-%*}}uYylq{{nq6k6lh3h6XuVoL;lYa_$pzA<3KLf<`2Vj}H^1k# zzHR;c#qIo87bi{sxt6cjYI>N`#Sr1>^N$%KAMH}y{QX_@*L1E8Z_PVyhIMXPI8pA& zGX-CpznLEnpE&G&Ugd<$-aT!*EDq^PRqm<(^!Z@bhvtc*x8x@XJ`vr(FYC(t=lb6N zzZcKCoc`^%!{@jB?60QA-`Km~&e%5Gt+H02ChLCm&gp$BC%-4$`c)Yl?3ZKfV_uYg zN?G?&(FNi<_8VC(|d$M?$+hIU3jWp7+NZF zc2&iyz_0%I4eo1xJ!1BA+m?vq^SIvp;>}7@xRSWwM0v#Ia}GSWnYSPMzvs^emdypq zVrMwG_Uo*gvT*K$tV=81!|tqG@Zw5v^r2$Sh1)D$--$1p9$Q)Yv+yJ5)~#DNB>MRJ zo;`J{=F^f5yLPQQdw?yVWUDN6d}HbA zlNb0Fg*z@?nyR_7e_^;lclPGZM%-LnT3T8kYF2Ms%O-py;L)?#*jVe*S6`~!O`phW zeEm_+Fo92GQF^jzLh(|~EmfEAN_!f6jIC{~aN&ZTCyr}4! zIhu^omA;DI4Ch0qIbDCVcZW^hbjSCW)@*Wrm(8Cr%`58m$-L}uZS!n@%v^lP^}>vO zR>hB})zzGA&ffl{+9U9kt&g|X6N|lDZ%8)ial4m1cd(u`GnglX+3MkMQSC66|FH+m z4HMQ(*i@Mw^|G`*?_`c!fBDrtH6`qSUVS_#K6_g80axKWG5gOgZMCi58SvL^-}|N2 zslR`B_Ld9g&0YOspQm@-q0(RbRWn|9yOmtm@#*ZgDc{W$;dgug9nR0G%YImhh=&y9 zuDo;&PR`GXsNhtdJbR(C)jiGk#vP+ocTb)@ z-s!blpmoyspKJE+$W8bXa$i}b!#`waU3q?f?5a7vy;lq5KW>YRb$apiNZFe-^YVP{ zr&Y^XSZw(C!q_$XxAC2lTAV6)b=o=c*uJDq0=p`zxkEl=KHPSxsrlxa$ci_&FK+zr z)NGOV;Kb}^_5=IBedD`(zhbd_f84TV%hs;-4Gs?GjD1pI(JiiTSNbYsvT|tuChsNF zIBtH8zb>7>LrPLAA|m43i<_&fzrTC-Ozc&UTthkg{PXS4ne=$hAN}?9b$q%?mxIEK z>)XX^ZogpDe=KJk6BEPB8-14X)RU;xdBz*0HgDQ==gx_YBBh$>zumXr{k^tl=U)3s zokwNl{KG1e-#!bA{&3{Q2Dah`sZ+O91nxikH9I)^_2PeAx!?1Sxwo3S;CGn?mkPCw(x#t-1lVbhU&y8eG0$cuUNK=O+xB~aqKqB z+C?9|cNQ77Ha0TuNsYU$V)DjC%3>YkmG#a-R~4!>*BrYJUxOC?LF2~}QB&_$_Vtlc zzn*-xiB3E?zqV%IhnZ`<&d%KE;#>B!Uc(npppTin0Mi}#?Ug&dyuIU}w=DFT^*Cne;>LW-zI#&@r~6fV~t%q^!KzHzc5P8nm$2T z{DiOT7o!umZk;-I?AVbdlP6A`xNehnlr`X5YR^=0Rs+D>FqRsdD z=6{YpDy96&`eJ?8w0B#dCzxKCRk`bWT*p<1H<5eRK2I{uFx~Xp=INC3@}rVIxi9zB zOVs2v2D5->Q<}eg{aW??RVG_%R$5NZqUFo4s}=fY8qGMz^sH{>iWMi$ovWLhJ?YYd zDT2JbU0K(cxL#^>y0Yr(f?w-@Wi51%J(C!|U*Xir;vJ6M%>w1R5(f=DDkqhF*}o#v z>;9(g+3Sm9yYA-2$$a0#vGKp)w;cAi_)>*c8>zw7Mm^q*%_IafPa?&<}HCmE$y0XMiO ztY8Z~+sr;@E>`BRdT-t*Y=7f> zrNoCw&i>lXb9PsA7nU=Aur2!9FPpu8?=Ob6KPA>(HSJ2?Ulg&g^qb_7=KWoANpsoV`&MX1jtyc?5O&CM_A4f2+Gi}Sgv#DUi6Tzgq zX9X>7pT6AoU1#B=clK}T$qE;}zsompakTs@@|ieq<3rWsa>e6uIn@{L~~+ zd0}7n{)6vgc^Psq)Zf^k=*<4@-MYgCsofP$!K&e5ekoInQ;(mOIwz3yQ&Ze-?oO>u z5eXSb@*i5XpOw6On#VZm`CFSJL+%Fc?R+^rR)J@tiYtCRd|y^4y5-w#_s}Y)y4X*P zInG&g$*uXX_`oRjFqit*tWfUF>5rejxq0)j-s0T3I!PA`-Pim*Ti@_t``Y02e783@ zjk&(%JesI_m$|9&^pyio`>JLvu-;HCWpha#v`6RqU7t0jQg7QMzs<0nUDJImUEt>S zU*A~Ge%;87z0q}Jvy;!hqv-{c3eU|v`Z#_4|NHv?MZz}U+5VH@N;MQ+51)LCNF$|7o|I89w@1Q^;6Ye({?At8d&5(bpxmi5b>Sb`C!m zB^$Wp@Epfn+20dEYsJ7z+OpQ1ebet!xAnm5fcWb-1U9F?tjkyawkDAO(7f8aSC{+0 z|M~vx`}fb-WZP!WoY~pgxo_XTZQIP+4~NdLKGP%DY6m*W``OvqrKP3o%R`v2&Tdod z%5vDf%+JF)@@h(i#>Akr&0TZUj&vV2zISQmzQ6101B5=rYAlX=^YD9&*}1k;ca8pS zE{L!&6x!QRw=jlX*SW7PEUx?1iepLt1DjrTyfkhSx;U#*>{W_nb>_>T@z2BcWUYKB zZZXnRiAsLeC28}`E_kM69AkTCf_=J^yo0inPRHDr+oi-_Mha!zy(D)n-Da9`RP~>q zpTBL*2uQvXuNWv5Jk38`O4#bxoqHJurMF%AFW)+CU3-0gdmF>&1l#-eFArX4K5*ay zmt5R!e{Eg972Z+iIo~{`BKl;Fm%d-{>uUU=T;Ev3Snt9&%y-``$1~=+~wYfCpPV^uA5(eBmdg(2VTb}HU4^fy!`$0oy`|& zdy`#rmE>+1^6#>E7`)|c|9PJpi@T>!7th?ydxBSL|Fcbxc z8=JeEZ@#&?uq)a9%}tFib_3UMhe96AnjUPFv8h={QzF0i<$B@04>$Hd&rauZ(UiOCmUe5?n|2G{Z5t;zdrNPP4mq4I^&x8C z1C|=T75SM46Bla67(1Jr3KlVJPRov!TQT{C*}f|2(rX9)pVFEV6WPGIanqLU8?!2Q zM!h}}b!KU&#M+au_eC32{dkhg?7nwr-J9hS^DZrsK9T(LW9i~t7e#Ne{}Fso&R&CW zG75Yde(B1};91W)jMvR~Y297A^_s>G+3QKM!BhU&rSvr=Z4>>yAu;;zO`VuM&vr}y z^O|W@cW7Jh)3}mj@1>Ov9$*Ywurjh=AaILJ>ittYbW{0UeqIZ-kW^Khbi&{u-~V%b z>>DH3e|WRy+nIc@Y>D|fu5lb(Wo_N!*C;paS{D8J=u=i}gPP@Qm zrXmfiv>qA9*=J^DeS3Aa_>}egh=?es@Pmh&!koRkkEe)*7x!r&xT!ovk#~jt|3918 zta-C_eH`zyNr|?H>|cFfaKK$?qm&D;dHCe_(+{r`XP)hPT;gBT^zGHtAN?t^Z2s~l z>&LE0<&^=)w5IS}I#Im+bmP%4%=0x)F8$#4^k&r_<~io`Bi}Q;hzeMzb2M;@R_21) z>ozf(Y<`xVxw9ep$ty;U;}er>WM%{fg=xAzalIFF*#7(DPZoU4_lnD6%D>Fs*Ys=G zw6?js_J97l>}kT^N1YuPxk{?POzOXI#9i^d)P2L18S;NCYn(RGQTytR+_U{1wzn_rKa~Dsb@Z=KOSt}JEl&3LuDjG?JNsfrbgRt{ z-5Y<38Gm~$yk_*~=DRtoXV|W8{P?cpUC$={>#OBf9W0Zc)fQ`C^0Z-HcTJ2bw?Vbo ze8(g6N~QGD&llygAKtwA?-?(#YBAZ?N!Pk9w^xO4tG}RerJ2d0WB2Xp`hVHwtxbe& zrd7J!i9H_Z{p9#LU7ybV>ZhJs@yvPuM4}>x-KII{sAS6K^zJFw6?a8Btlcp!kF8g^ z>TXI_mR0hxo_@PuCyreUQxJHe`119uS1(_@(0DBA(0gacsfsqEB@-u1DERcmGw5&( zpZIKp9J2}c7hK`VymIyG)hkyfaH(Y7%(`;_rqB-cN!N?#d3y(y=5>xYMr{aEm zULP~_?(y_VVo|u*!1D|;!itgUCQ#R6gm9MijzTLm!ECPy9e*? z?zW%(Ot!ybgX-ZYHaGa$Z)9x`>MfIt>#)_{E;T7?-cgq`@o#mkc6%O-&viL&yQSpw z+8pjS+w6J8wU3?JY**j8CZr#2Sv@W6NYRYsX>+Y40+%p${r@*J@qAIh>hmt98N1^C zCN5M>I{15elFM`P$Y*!|2yIUPDCzR%=H~l`Z*IOmYEyEr_G{9+WrsiKDX%vyJRDf_ z|7}XI+MMW>e{O{Pl^nQpw?-y4^Gk)(liM<<`9<#B<>mJO`|WwWrP1!C>F0encpOjP zu&>hngxu4si@ra|bL(yFow$ZC;aiSv-0ms0p#ppPq$~;^Y)U=t*7M=v=bucC6DB$= zIQ;zcju_o%qH}`sFSTs?&Z1%Q$^P$`;LJ?Tl_`Alb}sHb>KM9eVOr|7YuCiY#V2#A zOp2FS`{$i$Y8P*8aD~y7%t^NsCTPXK+k4!iscFZD6DdE#^An?&M#XKm)`|QW;pmX- z+#xW#`ultyOT}*|C*FK)?!IkDb&gxM^{W$S)3;RC*1UMSw=Ea%IhL>HIHmZr(n1YSq@B#~+@h z-&lC&c3euzlkLC12ZvhrYTrLv?Gyg>d;<5IoB9_v{_f36IKNHJ?B}$zKlX}R?f-CM zP1v~w-P`*=geIOB+VuMKzk;cM5}!b(@~bGg{a>d#`5RsH>4 z>-(G~e4P%jZ#w0-x7?oWlV zu<#4r4;y%L?`%65{;uue{I|2Fob0PPu$y_;hx~m%+kWu4#r%1-sIfZ0LdI8ga=;YR z^EDH^ma43Byt3?S#ndlXxBR=_{`>2@dn?WUCl;KzT3=g#h`)ZD&Xx~Hb5`$LCnwF9 zVf^aq@f7AMeu4X$Blp}2iTIE%`{3On~gjBTl1b>Qu!dwXAr#x*Z{eYG>oK~hS}j(7DJU-0LV zu}C=7!s+Jbb|xlFuKzsCtC^N+vfODK@_B!3U$!jm@v+{{&dw!=riLEj;XcZ2DzSRu z#bu?*ENj_1vjqNLUvn&5d*@Y$&HfkUMICv|-g6#M=A7pq(%kW4=IY|-=aP^0yt}?$ zetP#I$)58Gti~p@qS?RtvL!6Nd3SUA`LD09d$w*qs#5a2VBuwlAbUg0&MbkAt_q*d zd)o!4vHHkf`&Xowyv%2&(XxE&wQO4?Jw7-~2eMDQec|fW+I6N6{+;{%zT)=()7Q7( z-u<3+kMFu;;UOPPtG>LrC|~!im zS6wvqvydJ4yanp}?`Zk!6zW%+KdN1?9=)rdZ<+eMUE5E-na})l@ADm>q^JJc^8HDA z6XVy&%A)IM-u+mtWBcerbn(7p^LM}9SyZ;d?ZywqZsF)#>3hEB-9MbVVgskMxc%iB zE3bdA|6_25?Yu%0y@AcMv=4_lYfZg+GG&w1GXB=Qw}lH#B+sx12VZ_(mD^jNzp>iq&q;B| zv$>&%-Ov91are`l2lqJ&zD=DxckbNz_piLWyIZ?S^41xhYkcg+v#Rqlj21ZR>*@V_ zHd{7)U5sMsJ(sAc7m966QYUUK+_%cCw(V24t1D~b0s-6Jt2=g-{!F^d)w}&#o%N*Z z#FvvUA6WLz$TpFALR^G>(bHOH^TWGVcrYCD^AkBc_w(N;n;x~U`!h$jc)Pts9se|` zuSfmj*WM4%y!|Wvy6JjmheNyG37brli!;xEx6yR_y}L4uR{k$C!}wRsTWov4eBv3q z;QZQ+*-NgqwyiCfyMKDkyh-|>&wNXJbL&82*;4zna+{pDeLD7VX0|#1?`>|<0iCa7 zj$hZ~y=Qekf0_S<=ZOvbe$U+hI=$9BF2>wbTJ_DF?iss`RD-VvtUWmOLVUtu#mT2G z%#N(Bjh)>ezVzXSty^o?U7xljOi48O|0hy4SpM~@zTdt;-rqGDr6b@4$j_rs<;WOOq=?#PYcy-+bD*VB`8=27P* zA?{WIiw+$=y!fBiv}=qvCx1BNF-MAVTU_bU|4%M=at3~y!V@pQXGXGBiSq@Q&pr3c z-zL3;=zY1ncE9?Sn_r8ZGqsp$d7INxB-vBx(nD=RBI`)Ja~qut{6|Nj&}GL91NKi~fK%)H@e`eftQW8pJ-KDgJ{K6`WXzMc$s(eeGVQB?-MZj7BT zev67nES(pwmYMpTq2_S=|Bqi^Mg4q`k-_xVq$1++TJt+vi}&mbJ1Vn(0>d0O{@OC@ zM^7^r1_mq0^M^*p95sBI!?C(O`Txg%kGF5**X_Qud7&putK07-AHwmm59G=9z1|Y`bOJ z!*h3ko?hznwah2^2IORr_z27Fuex)-PyT%FoNwLU$$bh|dQXi?ZEsz>bAOw^i^$Ew z4(2}#HvIY-dtW5fIXj}dtZq;8-HT4P*A3tEJ@>h{@#6aMPZRq;{QGe*`G4WTeL8X9 zMeE<${&?y*c^(bF0%7Mv+-OcJZ@2(@iqZ z-1=GLpvG*~Giz2>hUu!+tLuKfT%LP-o2j?1^O3Hs4;MGLcF$q^_1`Sh=+tK>-B>p_ zw!{SjnqNbV175iGs)hzlnjgFP;M#M^$Cv{D?v_xF=uDN*7m&JEV0h`gXf)$lUL(iu zJ8xFB+vnd*xKw}W5#wjg4gQXj$#1_d`nN6QOxuF5YJZRGOBuv7zgb=Hr`EC2aaK&O zU#@EEt;cH_p3iT(`94r&vwzHmI=#&K`_6T){JNFFW5LA<4yyyhum@P z{xV~MOsvnX6?|t>Q>}B(zQMx8;XlzBBjSXB%J5gk3g|q%O4Ye!6o< zYpT_f+nzhW{`Kjdq3@L3xJ6^@lufLcp1i%h%$4!}eHZKdb1iiuET057mI$goZDzct zC(@DEfA;|=@0J}e{!RBfawE&5FpJk$G>|tnhuO|iPW||C`>vWAOV)uuSji&|nYH+eNU0m$mFJsAM%`@eHaP;h% zr+@jlrCo9UuPfHQQFMApXz1U6zuzk=s;^$X+Vkx8zZHp#q)uckxG1F+)Y^2+(=^2> zGAvBYS6E7EVvN7#&8fAjg*>+ROTM?gde5@o=brUG?$XNZM>y^OI^XpBleetUo9(IO zHgy^8^6jj%{ra}A-d$~&vgN(>f)B^|54zV|is-Cb^ovLG>W3$RHB#1Gx}Wzyh_ACO zi3suhnj7&f^Q(s0jBSxO4qSP=>fE+X#aTahb(o)aG5t`$yX&mE&9U5!q801+{nD~n zG$B9f1WV10KcW0$+~({rzP)+6>fFDCQ|}J^^owQgfBQ~-$x0_YS*59 z?%`EB?>goB?9G~+&VQGB&a_MM8{4LU3uha`1WJCYZTR*q?uNk{qoV&eBTkiHz4%k4 zQfH6F*EcsmU-l30k^8&NLC?h}Il|!7L`m7Vh6^9=-Ws9PxUNZZ&c_cA7xzk=|NZk> z@saVB>gL53vt%0DTC)=O@wk6=;Qf}_WXivmZKd;~u*FizOm;<=)`x%D@Ug+=%Z_6c zzjliWbeFyV%e*zWx3_J^vmfjJ92Boz^Y`oFeapJ-9eN#((yHeQ+UZ zS;+1yCG|%(zTE29_vY`!BS#fC?EL&{KL5e;-&1B+|0%yYZ`NsVTj5RB=Ce|RE>u3* zCCJ>~Ja_uVYg4~>tzRx||1|ulQLNj#&lB|*M7Lb!<^zJ0f0}mYzHH zdePL3Ms{|&H+F(ser`DZtHCneHRCO(qPNqbOY`o3-o(jnQFp)R@4WD5>-H?XF~45N z$$rz?jtHaQuL~x;D#`zRygv8t^UafNq~>k!>Fuqpt*x!uQ(0tqkSC6PLZ&X8@sgmK zEZnm`Y}&Nx^K<9(^X>h8+^n6XY;=8ndG*>4vzT5vbN}cHp6)A(g4#zec*Onw_h;Mo z#-d{?>{ITEU))nsP%L9FkL-5CjoUcce;jrDe8+uHZrJi!*M3h?N(mSJ^x=bqby?5a zwYqN0PFDNPNUr}iQS!sos8e62KhQh6yZrsZUn-Yqf@6(`_JLnS@Ked zGp$5r)xqZrSFpXaZLFJc_+p6RIlg)Ns-0|F#>SIF6ee=5cKq^+(=Jr>?xmzZEmK$4 zJx^YKt)Q?Fw5h9Uo~exA{e88|{pKcRWu3agz3jM)clYhYf7O!{+7=ymImKcO+8}$VKGIfQRU0SG%X+zRJ zZDn?L_8%sh#vjE6F9x4Fbm-ClfA7~S=I=ZCut@YEkDXl3kDg}95BYI%_gcBdot&LL zxmGS0jF&zu^t=AsI_3o@A9u$qaC-zh~A5V+Q?}MhX?(LPf ze{`u~$?t!93+nE3KE9gJVQ6~KY}Kk&N^x8n=^^2vha+XL?BR{w=B&f>s*E=|IXOE! zJB{nmh3usd9-P}-{k?6HTbr)keTMr+=kk=&+tw^|+i1*eH{YtX>ij(0@9*!Y-}tB1 z@<%d8@6YMbH;Xc_c!s}HK3v}xcj-!kWqCh`k>06O9mj9~jrqH~a=S>ls7=T6xBrUY zTHV_PAji=W~ zs7zmX__mq$Zn1I=U)?A1lX~4w`rl7XYZDEB%(v|F)903@<^0^=!>1d{ToRF~zRdBF z{oDEV^1)JrX7v6Xws?kNoibbLEp)=a&_yUAdxhKJMxB z=lOSceZ8_W_>AgQ-v^f-eBN-r(_1XS!fHL&)d<_h$@AB&(P?YvS;^TcR=w@@8)k1e z>rIoF{c@Z1w)SEC+a9@xoqW8TQmdD3wSKs}-gU`lAGPGoHz%pHw}1U1(B{P_j~5G9`_&8UP5<)c zMQU1DQbNWJDS4-j+w(IsGHxs=^|Wqbns4lv|4sgj=IQcd2fsd+tX*X1$Jc7DwcXh-VwQUs>CzmfqBjH7*VD5JN8|uceztvu%2J% z;gd@iD)wu>eLjDrPhfHKbr}Wk-uC#MyXmFdnbGD{Zf-I z7h&FaLZUNxezMN}qvA-}F?DoZAcuYa4g-j473cn0+PYX;-n^i2foV8s4HmEhc&)njHT%Z01uwNIb^yutH#f8&uOp_`X~{rKtA zr?{%NbZIF`uHdusH?F;SV8YMe&)eGeZeL>89kJv6`F;QNYmWx$b+qU&vqMP+C`)du)C1@-zQztgL>0R=quG<+aSdb;q@ieqvTV z_(5P&OK)qN+`q(QkIo_L--w%>C{3)jzy)9>8alcTgoL&x9l_SX0i@rd%{r-B!6 z_%ox@{m?G$;9mEyhgPPY>nT`cCAzdLnJsv0$a4wr0~aUT{wTe5<>qE_r+OcQa zSaq@PPTv0oRMo@%JbeAC~(heG{x zlS5aB>BsMzv(b3ggcHwrwq%M&cl7Sr-+jc>-@o1W@P`SCvCG&rY%S}zxF6YOav)jw zq?GtayY)JSE+tM5E9Tq0buzNl=y)F^b@3Qq!=gLt4s}247!!Wi8fe$F&DUK0Nz?AI zghl%Q17SxqcTW8kb8xkY;4|X`oKFuwTqK#CEgyZex!FF3#lGeVyZx=*`|e-6sql9F z(+vriZXD)cvLJSS;D$4IF17G468_`-$KlsewLPVaORb|bj~$c`&Hw-Y{3EA-En5r~ z%a}Krty;C@(({IOg2ByeHcNEO+8iOP$p8M|RvXSw1*adf8-?wT3sm?!e}{yJ_2<8A z72Kc9&;90X-nzlE?bDqtJ9g}7KACyyT4v~+dErN&EeM+yzb~A_VxNaljj!X+%ey_y zxHjhS%zmlPChGtGANwE43#&AA*H7|&^5NdTQbYBJ|MMQ#oN>JR^+=G4eS5*(Wd8I8 zyZRS-%TBweaAdyoeXSIqW1n7{UcB8o|J(KQ8OiQO0UjdPcE+r8jLo~ncVfOY|LuK0 z|Hj8vF@5`f;_Zt4r>6?(owoRrEcD}}vdZnUb^lfzPhC+pXKuIsRc;TN8{D_Hgnv0D ze|%g0FO%iBHib8&d+%#(oH$X@%&2EdoXOwtJq#h7Gu__wtXk~e@3i^*jg84YTKQ2* z4%s$x)6YLHo_O;k({cYxmoCjP)oGiToOR-I|FL)$U6x-C8@sq>&6Ya()#hBx-oL-Q z&aN~Ue*WFL@$3$waGd>Rc1gAL z@*CsxPu_%o$~sUpC)lj6?wMplvryCQs9Ck=b5Fg?EAu}Wqy6w!M5^7|V&0jrdel-D z%UC+xZ@7HtiolENLq`8M28BLbwm?B$d#};a+s5Z(^dD}`_!)m&YV$N#tMGaKs`4FT z)4Z~!ift_`A4qkbIeYo?{A;^P=Du>OI5BNAugHPDI`@BSE6-h@KWi_S6z|eWQQO|S z-(UAHIsR3r{o>du`TjS*{CxSxs@7FI|99V{mfH9~4XMp7IzLXlKDe*a{@?9oY?BU8 z@!fo0>1W`{g>lneH(tK|bl%^ur<13@w_RKM&Z_mwUB;_(7q6J^^eSQ1X9K<|hBE40 zpW2fZcF*Tt%D4QN)+NT)f~TpbTYu>ubNctj^-m$g^?&>#4!`WX{^_aTwLNjuYdwqC zk0-Hr-xw$Uf3&@zXnT^TQ$hdZ+q-rI?_HqUbvXOsn?%;?r++8hw0@&vZftD))xwSK z#!SZrk)6hmLwk4{-tStsa$*AG`ZepO*;Gu}So5=7J8VtD97$h$trssP6Mj_eX%&y^ z{PXyE?vGXDQEP>W<8st<|L_|OiR3u8Erac|7U0W@dd*Exoy5bxY*wP$~^ac zzWedHJM*u7{Jd4Tg@NbKig<0$b8C-_R;{h7H@YWUQ(w_kd3NjHnY(5?7V0e`G)|OAqdB2_s-k*P5u3Mkk z*2dp(svjR`Z>^p`ahLN?$5QtD@-q|k9D|-G97;6j z=Hq_->1=-W!k)x`GoFRKIC=Av>xATIUqXsb%xB=|@BcSn;NKaU+u#1X@p@<`D2YYu z>8||pGtuZx{O9x26fY#2d9yk13vW^AJ$P{MgLcn%<;j8i4MMEJsn_?JpYo21j7(2R zX!v-))y<8mXi@0PGZjDQO8!t-eP|}*(ccdaHgk*VSX6)0S$r^_z0g8NS=qTL+~%Hr zi&(JK<4X-J(OTx_(;q52_Zpirbk7pG?vc%?o%?uC1;e{FHZ}88Uot%Zn0fLzpIlG3 z-2Nww3Abi=E<@ zRoJd+xvDY0x4UVrrN#UW$7gN|yUV`)jJL#&CrRAefw>2pmpI3>R`2wmYjt(;+3HLo z1x>vb6R#aK%0G}A_wl-I!p%$TGjEjYnFe#+e>Y*eMZ!r}Y3_+{ZZ`ifiPm`HFZ$&C zm(b5|qazNV54~}1!8@L-xw#tec%FVx@0a}a@1VY@&6leG>snMbwOTITQL7h92-@=V zbH3@HIQug*%AF5oz58aDml}S@Do6UxDdqI~C%mc)qbvATIL`^rcT>1&;IxU+dETd( z#dh64zW@CEvMqnt4S}DMcSU*bY_;>6@y-3hhxsCxpEk#rEqk)u%|9q4Ju@Vdd%~52 zA!c)r)%|`tgKz8U;Y1si(I>}uZxWiIKc2>pWdS)%M;?QcO+{z zg+?C#D7>I=>$Is;LqkH2e3-EC`E03k3=&)y>?3JMwb|0xwd5nH8{5w=}2vF~bs z-jtReg^W2>vAbq61cb#gR^%{veQbODC8@->%<)Kd?%tXj(D@p7*6))Se<~>OGsr#Q zpWMxpv!87K%6LxQ;M1YroF7M@z71}8JjX!%!;dN>hIjw;6ciN|OU|83xI8P^+H8W+ z_d}`kuAcY&^ujGT_xcXk>T3J&Pv8De5c%`*`*(fQEe>(Lt6rVbYDr%C_*}rQ@a7rH z8+ZH3r&kKdmCfF~x_jo6kUMM=b{Z0&zUyb5JiPSvijRSFA2z=}adMqaW!*8)uVH;H zYyV6+JxyEXVcbNP*K$*H?i}9qQT{`_TDzd=X7`<+H=FC;>ZM|K+H_Pj-3 zJ5JwT)(}>_u*H7YJfD<*m$sceAlSCyh2o)W@g)K&ceS?(zr3n3SCT0sZG!OHlJsM% z-<(mnux9DfrR{vOzaDk#PntAIqU6(cuQoQe5Bl*BuQ;eBKQ@e&x34=B(a3XE{p?x0 zHQ&0EPByw(M$DKLHF4j~_5WY&xcB@pr_i!D|BfBCzg=o0V*6*c{>Q}YpV-~&V<(l| z`Tpba!HLDeLH5m-*X;Uk3a&Pqu#jcnt!)9V{`?xBEI)i*B!0s+tTtWnOw@F9 zlXHuY+R>_=L0W4Yr4}omVcHeWJZbszoJn_qv? zj6O$yZ6iM2$fAk&PU-B)G=KQvqq_5A4bP6dg0lm1K38-YxhzwY{{PCwSF>Gdi^+|e zOY-dM4?pZK3}&DIW@lNb{9mb<@6H$J%QAd@z4Ur2k7{y@ebvFm*Vn!Dp1$kC&8$B^ z-)@(-;o1Jpt=jmOeqX1o$FJ%VudK>nY5)IqSFx?-4g03A@$jU>rOl7?4|>h~pLXw~ zO2FOChoj~PKL7t>Ug#H-_QS?1;%N_d&#Sm`s6zFG$)ht3hjb=-e3&b_>B^NWcXyXN zD>nz;Tpz0vp)=8g$Co(pryWIi< z1ONZ~n>%Mu?wXyg*OU0o)|`+1^XvDH*&%6jd;BYI6hvMqjYz6{`g6wIQ*RUBB|85- z%JyY~dH0r6{b_Ud9agA+QRsBIE!zC~1?QN*>=nB^S8eh?E`R#Rez&r<`VUteZ)6fm zN=do0K0d<3Lt~0U(|^AOkvDUS(vPivwEuJp%UKsE0haRj_lkdfczEcLlUw|MZkFf^ zw|8%yxpHQ6b949V)srW8FI~EnFPr(8`uEOB+55!wVs<1RW^3!^*}G)r!3)xU0WY^_ zzGV#Ew{m9W?QM3sw<=8Y``$I?ow(9a)fm;$dMfG0hD1(IP9EvmTU_rs2~=uW=HA-E z$Irig`*!so?{8el@cL6e)2EG>r{#a$_qef(g^^G?|jxT9Fn-)C1JTxrKZ;r*sCnqQKNK0N)U}Ju&yKt6NrmL&!7P(ccR%xBm zK2gSda*{EkrBWY4bG^ zadCOOnw0D7Vy|Ak%JclcuMh{zjRyt>CI%))q)iJ>zuIKCaWvRhPO!sKh9ON zkX^H4jft`G+Er`TG}up_8np5XL!$AkTk9M-`h@H1>IyzI6nnN!=E+?8?d@%T34;Zx z-mS*W>t}qJ&Glb4o?(^3OrNU1zj|e@%kJ!{oSgW(J|UpXrK?w}t?k0SgvHq@(xv_y zOU|6}$;dUZNdXN_r8PZcZR}saLZf}Z#G}xA7b+`GT~UbRt*@`Qn4Rdu+x9AWbK2QM zhYmGa?>`@Sp!0L5@nTPf%df1BzrDHn`+9u6p?UQG^kr=uIc804Yio0J1KG3r=J~yQ zx;L4=zqj|a!34!)S1Mln_G+zIS81bHlszTfL*?p`T@#>MF|HD%nzU5E! zjmcnaRap3QFfullwy7vcXt0+lpVIF0Y=jch_=Rr z1w!l%>yx8A%X3)R*^O;dI5b(!Zr{IOe`3NxF)^_i7n_wnyk_2n{+~a8Mn*FY| zvmGxl+_Q#fmQ=whj#4*gy?{qo7syEKMsF)AEcEpDPQLL&Z}Qr;x$p1owJLjY;GkPu z(eLzNE8{8F#!D zS^3c~ATo2NPZ)Rl{HISZ+|XFP?%LMa<`s3PRx`Fwxo{!i*p-TOPCf}mMMc}{Zy9;1 zu4N66xE(6jpPV^yMn%p0dwcoi?NTiMw@ui%vE%sTNwHEFt~I<}&-}|J`76t|_dh>B zmy|O)GDGTp+seQ=KK0&$oQ5*C!khy;lase)J2YLqSO5R7Y4$aPoEr9%$Bw1l*iew4 zpP!RluyU>>i+-kZ&kA76 z2n`iY&N2X5!{zvT;gT&pt2$4e>bi7EC@Jg3zSw3X(+8U;PoBJVscJLhUq8VuT2^Im zEHW-Q2q!1^6&-E4^S?v?SygCyn~&PzZZ)BdG!K=l&(F=hzo)V|E>7<7PxGz>XJ>9^ zv%P|Gb_bG&D3Yv-26`)VQBGxbSHMBXdnnjm3pi2hQ>EtiNhN|Q?e$*3~e){dTwbAS2Y>%p`$vl-5=9ziySlKb{xHGPEB(Jb8 z*re?K@80h6d_O@>+H2(q&17 zk&%&}o}QMs_9{Lus^sP6OyO##J%|GsKBUL|ehoPWOEtt~*Im^2{a6m#3$t8Reva zLQ_{uOQ&raTgdmNOI0sCXz-Fh7hWP$xpcns$1h*LeEeux^n~N^vF(#8Y~t3(?XCLq zLQkl3N6gVK&PJbXt#r17_3GD)W$kKGo}Zh0M(dxn--UZ7rlOBepXgF&W5I$2i{1N;!e#f= zK6&=csw87acenBEvkyO?j11G;W*qY4{R7dmG>z@`i;~s&sCr3s|=+bike5RADTGCqG*p_>KxW90z*Br?Y z@s*W7FE0N7=FZN|TeeJj_~$=sp+ZfjA^L4J|_PnJI%FKSnlH3087ns5(ES&7j{N$2AXG>dKTTaHX z=(&s5)h@3W$vVpz!%(lCzjo&KXSzESzaG|?Y5#4zVjbJ^I%e&uVT&9TBup|Aj`zv3 za#(R&8XK5se=oH#UJ$!G`}(`X?flcHOxcqZtMuIM^Q3 zA6V)*IHl9l0_t?%1=v~^^7H45ikDC5DmHx=U?sNUghJS%XY+;r%d?z5b4EmWo<`q1 zfezEy)#_3QK2Fz*UDcL!T)^4Nvp?}*w5KS?-K|0kHm|>MN#oe_fUJ@kYEsVws=mMD zRX5MqF3!3A_0{FQ>z7a7J9+Zr$&1%=%1FEE-TwMK=)bsWWP#TH`lV+SSO4Lf-z3O8 zn}yl^{P@q$&*$gc&*yr1Yu&!y(^qvL-L9JR-q1p+CZOYRy{g>9&*k?# z{=R&CFg9j3cjVjW^F4iIf4&vJc=7(*-8=K=td2U9X?S~4`q$RNbIb0j6@I&ahyU>m zlX5OT>HS&pug<9+zW3){Lf*Ze`~&TW6h*pvdV1#Vu5!A+A}}JN;@g`@xBEs%DopPM zPV!JuUAolG?ZvGNiyl4NwCU3Gbqg=}@_Kup){EVB9 zWLw_rhp}2A+`o74Z$DoD?4#69y{aAQx8g4{+x0rnpPP52rn>0vv&jr+tR`A*iw~Lp z^>d%L+a0~r_MfJ{pJ^sIh40Q9$#k#dUlp=0F1*<+wx+tI;?FJf^7CB*8U|vVyu3WF zP7?!GMA&9NIUD=oF{rijpaRsio4ah%q#$i??iC_k-3vB0UJH0|CG5Bq*WFtU7u|ZL zzFwOpWy*1MlGHt?*%J>*hP^qKw9AEjMr8T)0`a>+Sp+z3G=-CS-0E zFL#Cp=1YeATznS%LqqSbp^42Z=YAYBEk- zQ#haRlPII5wN8~|INzg(&1T;9GS35}gNsv7Z`pW%@oEdE^nX7;D_rY6er@ipS&f%& z+q?3{)r+(A{LcLNBOqJ3cIKKtQD?TCc&~3VF@>ep@~v&=F|*dWjmIw4zJ8bZ{`8J* zVheuxJSxqbfAh|Tvy)d@1hCqiJ=x;y6j&%2=`7fN)au;A13!#>axB(gyw1}FRd{fO{U+P_L_USGB{lDh*b;kU7`Hf${pEEnV^xt;Ju^q@F%KP{VWUnU?5Q>7jwGzZb91PMd^)?pVuX52CTWyxr0q9__^O3 zZ+qPzzYn*{f9Za;>ErzGbu%wImnHvyBd`A@df$;#R~DT7XUhbTbvp3{(z7<41H~nG}ownt)_3z8#$3r;x#}%ercr_u8QDNu3*jZ5~ zYh}L57WwR*`1f_{?>?t|hr@>U_SX*_V94bNT{EvhYIBv7UZu0$+OAtCPI%m{>bc?_ zem>V|Zo{L9*(>zqFR%K!S^C<{U0bU5hUgm}GtHA(bA02ks?gIXBId9Dddq2c+m#i& zr_D0+T5Y~2Q`*3^sjdD~W%XmLr?KB;0*aoBeaOp>QD6LMdfZ;sK+ezw+or z;Hue0`trh-Q~UQk(ein^c-rT!vrBU`3N3!b#z|S;U-LOHJ1Bbfg-i?io!k36&wZK_ zvvZ|b`<~O@x}rJ{i=F4q=a-%mvo~_R%`8Q!KP$iM?VNK~%k|GkvulBuf4z4q49X~N zH$K-bel9FDOiWB{nv#u3Y_^7!!+JKhKmF=HC-gNc8h1^P3(nUMO50ktUfezU?rD?9 zC%o4!$vAZ*bZz0DmzSbvm016)*tG4SjM3ChY+*hx%1fR#+R9Ho&+|{A^M~cWqBhyX zSLzS>)iVn+Bn8jjb)0{5szS!2XLHy7zxU_w9}|X4$J%A*Zmd7QgG)}( zmtuJ8r6ix-xZ$Y6-==Cw`+62XhJr&c<6i9h{{LmM)+LUd$=TcetjgXP6eLuf6Aqro z7+yJJ>is7_-UqD=QJbu$s(Sp`u~*0H`OCsT7@WHwz|p|@=%Mn7!v{JIci)m}wDDnA zsAYQg@JE;AL3xeYFa2UR)%{p5|LID}mB&jRCvGfyV33wz&G4(OL~LWwqPFv`p0`AF zH{>3gIepGywyma9Up23OKj-mk_S1Q5UK{1@HG0$B`gqR!|D)$GB1ZC z?C8OtQ?EH>KH=KB!+*iDuc6l`Nd1*f;9aTs@Re2Y#qt-wKJ5J4y-rmxZr_&r`*P0C z$|av%R1S&%-OKQzmziJey;-I*MI+9WvC`{h$j&(PEEAIqxjWajYyeJfL0c#3(!%vX#T zKCP>=3_tneYm?>m(92F7^{Y~sl?Lrx)$;v{H-}f=%IhLi**^xXdHmKQeL-aRZw;5V zx+bTCn|63TJ@ZuJ#p{=jw->IE_$TtPSflCrJZHr|-jvD{Pp_|wJ?wEmMm2op_Q|_e ze`GJ@30b|>dJ4`7l z(abE>(&|;)Y^2$*oCtXK_LkXnTZ_)GQ4@CeHhw9a94VzE$Up1hC8Mev2j;$Z@4Qt1 zUGkr>s7c~uliOXBnHOu`+2OeRntSJ^{~6|g+;#66FSxo%Kj`|F2=9!E1-qsNyx^T{ zHTlbwS5m@f>lQ9k+<0x3;Y#cBk2dXxTdf>bgdQ4u707*J+M)h(<@LOKD=+D6p0!L> zDmqyG4!cz9wF@&{k}n4>{HV0F&hG24>aJriE;!tM{c(d|u=MIo72U6^rW;?2iuir? z`uSBBMT`DQUAwWRDs$WPko3w|y@y&>UwxIl?it5w*W~NcYfpHDtlzup>anIalib70 z+U{)GxpeEwd8dvUp3`5oaZ6z9hQ>lYo{eGLC$-mY4Dz2EuCZ~8*=3H68_X_;FV#99 ze%igSNbd^I$>4hNbIaMD>x4g3KBYS?%FO)g>Z>311kbg{$<6WFE4Fji%AR7=SE}L< zg@OuSO%KSPnW(kW%_DB3TgSBR&#$kpuA6w|keev`(-@VjPi$xomERLB4R@*`Q2 zVaM6%?{n>+A9}u6+`jUom6cf9`G1FdPmZ~Nocq7#p83{|-`ktxH_PtJ znEdgp)){d=YXgIf4-XvA&N4l0ZG3`tfp6RYbtP#EpuxV_2XB| zG3V*~gsW%F{K5Zs)Bf5|;=ycsEXn;#&t*M+%UJegUV}}_?cK@ezHjyJKF%JK9jPN{ z@^6LC&7xhB#ipj}HftVRh^x0r=+T>aEtl!2+jTR zD_N`kfMwvjKW|LE%YL=DIAn_+^W3%ihgQx4`Tnn8@|vcVU%kBL)h+*+G1trpI!3;R-T>3ezA)59yxqY4Ag&Dv$Y{$9tl=oJf( zzuMY5ZPu)WbE~sYRHdE^zI>x7xA4{ToH^@N<$H||hs?UQK5kXflvO)5y|JZ&kgr8M%Y5KzjH#fx^$ED`3zqP9@$E^K$ z@D0f;j@QDE)L$=1OG!Mi)YNN{HmEP z?M7!R4>_NxOv<_vvf)m3{q#$fPeS$!?x;*DirRft-p*>P`<0$r_9d0(>!0u9-0{SF z_W_0U^le9aSucrhe9O!V-ezu>8CJGVYLtNwRgN3nU{s{O5D z_wt%nEt%UdKFf9H%%4BDeE;%g%a$#VKL6x>DPkerc6e%IBV!M9y5-WPOaK1}rgg5aH@_kF@f6$9LZ?`UthsHQ`J?Lp^!H5@o&Nu)ao+7u zKdNq99#&SCKXydr<+`o^8*Vzc@x6MTJfplSlq_76lD~8+Z(tu{m?eKD>JD@{I_V`M0)x{rD{}JO6%= zhKSh~OOa#h*TaL$ZEHWDHMjr&=kx6&lN)9lu2#CG&^|9leoE|&tCcm6vMahzT`4I1 znsfKo;l*3?f|-ltie^VhOU!MF4G#YNdj0-&vAe~jYD!B>H=N|*<+U!a+wVVr-`UyG z4~G=V?mOZA<9eR+BL#trVp;(nRwI>))=HqDM+?ppU>{_w&2U4Ji0 zJ+oShGgQ?I36n zn@97+rAvpd9_6&VaqHI4E!odsy-G{F#*@XnHmlVq{zYGJPfyRiz17Aqvh{PbEUb5L z$-BJFa2Z?Rix{7jV09jSEiErUzqb0`-rl=+?j*FVTBSA9M{WA)uZ9y3pY(0|@3(Mf zNLbiB+iE>EwPgzyJm7t@w*LCVT-&p&i}QozG~41j{?y#QdGq$o8(Rtr3L1+0)6Skr zEN^F8;cTQiovr5Hj>5-}j&@6$8C|JJTKA#q_sS(pSo-8_^u+n3Su$ZL^QE^5XCJs{3y+ zE(u&9=q$^yaNA4MiN?%7jTaQ|tp5IPvbz7ijXJ(we~dLJPFyoxW#f$_ckbLd;gQgD zf`#h_cP>Y3+Kbsb(%>}opVw2x^ykm>Q8yyO!@_K|E5d?ec$Qz^W!`?tf3K6Maq6il zbFItwwa#|_FFGmtPE4h8-dCkL;Sw4*t|;{JCRGM}_FnYs=_|{9vy2zJRWh#7vHSO+ zk(s@yxOiq;b@a+q?`me|eE}LRZEQOgLylkKT#(D5x~cr>si~)@>l^2!ylD0KA79yB zT~U$Xb?SB0)-Ug^vnnFgU`f-I^QOYmRbX-O?yz7P0<- zS(&Tr(Tp(Oh+}GM0Y@dIq#TW%+Upc&weEQFP)5Vl^y|5~*8kH|WB)igTm7_(l3bFS zvfuFUQQfR}Yc4uh{iu$5GH3tF-K+}LYuBz-Xm3>#Oj*#{$~wo+?3luWb)S`v$FKCh zx+2>AMEt3lAB!erIyC-|3yzJ|bqx9Z;9#?;c9@)1$%;LD{*-=MuQuWTLSgGD@g+7I zVcePjbX1vJUC#D?dv3qS>Gw7}*K@sm5A64>F+L~lx2|^i`MEYb%Fo-`R=0hv+5fb; z<%!!i&fVKP_ieX(^Xr_NU(&`Khb~<@wQA?gNMns@RzAF&7Ojd|;@ropA(wk=YvJR2 zp1Y#CB$8GXE=essXZq-N?Cp4o^^+7#vV2W-({4A-tc|yN{(KqN8}p(kCpOC0+aytP>Jaa0XY5vbF|7M7ciNZGD_cB&UasKc`8{Du!Lt?X^n=#(+yBa#G?y@XEBq^^H#H@9%G~JUTtT?&sT6GgjB@mj~7w|BT3b zweQ7*>C>jMMW_G%JTZ3qk>h9kUR>N&>ac#p1+nwnB?NRNB`;209wA*CZ&~_ehK%`C zti|PHolKch{D0E%sg>wsww8Zm)ge z=ACR8-j^m6N^F?psk88@Vf5+x6)s}a+@m7&G`GzNe=CyZ>rnTw#La;Zr$3&sJMUXT_Q|3enu9J!Mz=cz@hk<~#esg$wn* zdcytdXW4G;pFVy1_e;h$w=bLs$l5SJq4%HuRb5?utz?P#D=#g-*IAu=d5ueE&NV%g zEyV#JUOdkeZBS#}BKDw}Cx7FCJ9#<=qED}`2vz5`e*Bc@5C% zJAZoqjSY-aGWxglU%l)NTXbDh)O3>6%qqz&l}S;qC+;)b*i@afUUzTV+AFueWYqJQ zSIznFp0v?GuW&wN?cu6#vUcX74Jo#(bx-`h)puEDMqTe?i|9>f=WjUMC}*~HhqABb zS>yTV7*yYXZWY(z<>Bq^otS<3ghxYvsQIh5fTTVdo01jf{hjOA=1 z);b*8{mV0N&Hqml9J1ddU8)(ojOQN-d^X3csIN@TGC%lPjo~)!P`Ly*{r<4%_+-tD zcW$nB>f6pJEB>k#ll9!?%am-#>oj%lrf+9LMT#D$8F4oL+_3dv$@*W*>c95#c12B? zr8mR>>XcPSU*6@OvejcrmS9u1;8XUqJi&LjUU>ic?8GN*-V&=d7Rp9@ud)tVb>XJ9 z|C@P@`#FF8J@Pd7Gn0pwe|$ZoxMugCKQILr@V1?|e@f|;aArGcNl9MmZzr!! zcCVZD|8%GHi`d(ume*Ii#+%xe&))p{#(eMnx69fKSs`pzIANJL7$~}Cc7;3ua!p!=69(xPFW?gb~mA|;i z+$lY0|HP`ludY7vJ!SDqbx!xDxf}l;nkoBwimt`Iuf8ESi#nzBHpZ;F@bJ>ze%0-< zUq6bsJ>)9QxFLId<+Wy}Bkw!-7SH6k@Q-ItS5{I+#(}irdB#o`$}$~7H{{+nTa+_% zb2rc4Nh=>-{8#%w?3jbzx3{;J7C-O1C&$LJ(6IKk$@vo!5A1Y)1*h+QU|73X_xyje z6Ni)EoR98LI~20dU@9j=(*1-vr-B(xTR-y4ua#;1z#k~1ZfKHJvwML>t}X8k=fHE{ zx79q7WGv?U|I1i>uU_)+ZK2QhJk6i6+1l~$l-UnLWcS$o;JtO<?v=bJaZmE)t6%JPTz0d1*%x`)y=kYv{^8oI*FDXz%72=Wap|XBGPTMZ7dTev zgm7QxN!7jQ{D*N_UF@zypSFB83HgwI+T?u4*{XMk_y3!64HvoV?|OOd@LAi^R?_Oc^w;a%ifK1@PhF|i7?7f)pu904Crcxw z@08N!G`_SIJ0E&Xo<2Q1A|fI((oxJ^Dl@mGZQE9p(szb?Za;o|U;gZ>?6g%|b&vhq zS~DTCuj_n~+@gVw*OzV;L?`A>?b(SZ~gf0{_dY|=hs^WWM2Bme6&c^J4|(Xo%er!`ldtaW4k#EgI6x-`I%_hvQ}8e zXY#!pnYoLSre3m+(%dUQ@!H2PuYFQ@wr9HQ=dOMHTHuB%2V?ckpJlIP?p!>|vLU2K zZ05{EFBeX1NLCQq{_??ukHufU)hu+s&wqci*F~f55YCWq@`rLKiyA&UqtLB(ef|B2 zJryUPoqhB6{ulA|w{34(pFWSOV-*PaD%5e5&1s#WYC+M`E1JLjUQJsWd@c3yzUD7% zZ|*v%K3o_t+w;QV*Mq?dbUZwx&B?y%GRKb}w8m%GY8oU=6G+442VEu~+T&fK5m z#{chc^L+QSwzJi*KEL*|eD43#B_c-EB3y~ZPdn4i^rChxZqVKk@GXfoYJJdchrJUU z9=*|da?qlyuEk3trQ*fyhY{W`4!Vj@q`G`=mo(|_NQjBnv6T4D#m(Ouj(XYe z5Iz5Q9ZS4lnnXl!t+2cq+AfmwJCu%9;iJf=-X+@2?Ed``)*H zj-X9bnW@|%`zAanvv@kh_P;YTcYei+GN1HQ=4GuJ zP3H?(`pRs+tD@VLOHvYS+cu}hpPu4$bmIK!zu!deYi(WXppdfpYw7%|)?}5NB5DF3 zX1{J!w@!D{yKB$0<=k1lOKH=-Zf>oSTkxp(MUB}C-|lxtY0G6I+P_NQ+9&*4hb!_z zstMOic4sT50-1(l5jCxavG!+oW@cW~dviGPeeJfqL;o%{3hSy&H=nnKB-OD95yX3#iq0ws4)$EpwpiQ*MBY$d75sY}>9fCw&i7_`hli+rI_zo07g3 z?beRFIdkEm`sr7%ZQOKTH*(XeJ$q~lo+Tv5vTnB2geZ<51xm}dt#0`GrtZ~QuRgAY8{4n%WnHcI<*ijpLmliX zt3Ew2W;p-u?ykV2qW3&^{xJC1$aJvi>+!_cHof;NTo_wRr@vgqI#2b)OJUn!?ubLu zKaO}CE1R{7pJB>+#V9&$eV&rWe$ywL8EfTo^%6uyMQ6{PIc?gsXHTD*ZO`IUH@A`7 zzA$*bgY0WjEm>{ne?MQp=sFAV^A@oiSAtYO8>DMa z*q(hm=GOxjv-qYvYkzKCsnhaiR-sUP$%l-EPGwiaXTM>VzT^pMJ-$>l=8&(W`XaU8LA>}afytqmrnNN955^8XE?AkI>N)d<${L! zwEMAtZ>G;bI_Lc3nVrmSbvu6qZzwpWVBasl=_yl75$E!y{F@TA&NCb+dM79L>OfZi z2Y%uGzb$-qpUWID{OVAcaE@=Le|O^@mL(JCe6CF6urL0oGvl+vjAA~4%F1euQ_aB- zKbdT)p2NCz<~|`_BW2tE$9J;3v>Dc_m3~fne$RjJhW9a=8UGF*i#*4$qeRxuWJzjb zoaOC(!8^PUe6N0fgQ>FA*V5Gasm9$6Yrb`>vvKyvMa)t*ICCn@;ltBs zPoLRWhlPc)sqbPi*grdrvrGH{>l+W8DK26@WTJUG&9`jjh_E~=y8Eo%KzMi?F>b~W|b&N*uo^GC7 z?Hl^-;Gf?|7ECEF^^@W%_7>eMbjpVNRL#+;Q*zcNFaNmi+{N2r+r$s7JWE?pL<;0vFsX z%Vc#{yqR$5oWtw5yGyp7cSu|lcv0-{F0YLbY8TvJ8o4^}+p%L#jak#%E*8g1Nv&2d zd|swu&Uac;yLqA7hpdD>UZU5O+;%QeHtF+Sq-=6+$^TU@8GDQhC0l!MYNvG6{dyl< zmhr5n@{o{J-Ln(Ejaq-sWY1ow8fwWeW1aLMV$$bWsk&vWYz{1&-(5I2X_w0Lrdd~} zzUDi;d{)+jd%t&IdC;+P-(mCfF}F6J{p494C=~ha<;%%shj(}<*@(II-JRc6v|rjh z^~Ai%4;^b4fB&m@c3;uYiMvC&En;2yQdY9u_!>7)%BE=5{SOECABf7CwI;Cp2J`ge z`ZK?<_u6M|-7%{tz(MohlC?M8Keoqp|63KsAU9#jnwaf9QwrvU1_c{Lk`{$aPdhqGUGR8(fmeV3Lr+%NV*H`#I>g4k+J65h< zwW{(g`_g56O|Bj{H&^`XTfT5};)w@Wt{j}8tywL8{)S^-_onaaKQ}nclDSdZ)gfp1 z-}{a4$`e1HUsqi?^m|*j4#+<7Ce5djCG0Txsim=0-V#$h|#(PI#_y zC}Z8^<;uDI2cLh)qjy116=!S=ikfqFM~jzkAzK#bUd!Z0AGVHucfX&4_iZLIIan@A z(W%t^YwbPnbn~RW3#xosO$xPT?zYBu_uP)Oei9}5VsWfglJG_cg(n{?^q*Whv8t-* zjr6OwfN3Fo6=xotyl{Hf@vIR3r<H(A@z_hhwc4Shmq8?3$wVu-)!i-a$PpFu zDaA9nj&6)Q$D3fU6%@I~{*!m~;|qtvBTp-*OmKPbuPb}dNMT89L+GN3JB_CP+;w>WkB+U^7R7Novq-JE;HDvZ zV)xn{{n)QY`DxGI^?kb*9Tf!{@P76zFE4K)^XsV$#SV8<5)vE|4hRVe9Xfn?CCAr~ z#)*thfx3Cl|4L@pf4R-)dAK@{^?_L;A5Y{xL(M(M#l&_vmsjol(Y~vRhim5L{n`7c zojtPPRa(p+QCZXV{m)mrR!Mj2du=^8F}_AhH92qL!b8ctr}?*NDXjKAswTsC{Pym( z<K`hPoLPdE|wXxAd8-<;g`6@fkRZ4$xF3(LEA#Pls+zB@pn;ntGe==o-G z_r85A_#)!=<9x^WI*A1;-W5~*Bd|p5li1|F zbJy;*wc2%Q)l^}VH*@C39!(Oit^M}8Am_q|`zMdan|gYltpD@TJuOX5`CC3O>$#p- z$%|6E7vKCesdzrCJ^PI?4Uw`p0vV~PsmYfQ?MwB}&X(3_++h8BL-|S5gCaYk>gxXO zD100gPft#!pP$#Nc)m8)>5aJYqpJal|8LslA8Sm1&#~Rx+xz6Q zTTDJ-VW|a9nF$xZhzkp(w|$z?X`-)RetzEGc0SppKAt_PB@d5t?3a%}a%1au*WV7V zO2QjEJyeWLT5R_Qviq-yl@iyF^YQd-hL zN3ZKKmb-!Gv)F2v&)B-P)XmK;E9=$g_^=5xCoZj9v(doY_{m$qzk2m5 zlX9cszVi)-A6_~yVAg5OEWg|}L+!#ni_%wLW|?MZ{LYl9azA;?MjI4;L$jFF@4i_c4{`H5?sMgNe zWc=XxBw&5vJ}?R#f!wj@ZC_4A9zkBw7K2v}6t`A#kU`2O0qr8`zVaQySR{OG^z zCt{ZBo92q{esS{aTl<{c6z-I?)Y;J{k3Uzmva!e+5zmD#=Yii?>&;C{ttGvzGOw{#U z?=#iE`|KWGoUPEbt~R{}w18ZuL}K-)YqKh|rLu&JKd1He=_c+Mn?0-R=raAP4=p8? zQS9ZjcfCk9Z;a{kJK!O&x+X&Oe~YA}WR^;1;o`kAMJr#QNabBROKh`k)iNRBuji*b zm0g|L#wc-Tix1v%gn0y#JV+Saz6d}kjVC@^;xW^C+EJj z#ot=L1qEE66B6#NrLBGXw6>Pksnx5rjE#-=|9gw><8;lu_{cxRRQ2487g}5`@ zwZ@7y7ybXn??3nIR_dKEoC|M772I6CKX&%Emv-PK-99k|{sbY!yljinP6`t@(l;wlzf z-#q`wx3zPkEiJc}WHEDJQ0{OnOMP*5j}%AqmfVxwN+wDv*S9VGy8gN1j1|?(d|9~G z9K9sI_q*`JgH=;sIF-%4kjq+dzqFQr{j;feE^4c_tYgUAo%iPHRc753*40^!ryj?C zI%T>+s(OPF!ziIP)v+bLl`g)gJ`WLU6Woq31Sxzr}dUEp{ zTa`ZElFAiRuTIenw)^|#vfA|1M~;MU*1y|rKkcC8&Ue4|Tv!oc5P$6A^wc#oKORdC%kuGF!1zOwGErPp@}=6X$tUH+@4?oI3J$)8Qab<7%zy)(|-_4a>UU=gt1 z`LwT!(Xr`fuU<#^C~o60{A!@pJ7tdkK{feX>{Y+M%zS%$ySSK`nbV;_|C_ask5-*J z#d$YO>&f%V6YJtso35|l{6r{nt51-Bw&LASukw%o*s}E1t@j!A{Qc&hnaU~Gch-uC zuamBQnaAWX&HMq+wyi&2b>6)G;3h{#LBy5{7N2fi)@4k>h9;&*+}xU;S6wuDcd5bW zUg+=YwCJ4&)z2+kd^tO9{{Iq}{G{uNsizfo8-3x5kOkVeE*L)`7sR_DThJjO8%)Tu$W5sR`wN+BD(mI$*g_9S#y>=_x z`gnqL)l`%G%bb(We!Q_$rKNASl=s7BaR((PnNON>V%@hJKQ7J5SQmF?{;F1{`C-gI z!`6!Bb%&llL^N%?NQQocMLZ|1!DvuDqyO+k03w+F4zII@w^ zSxHIh&!0agS&r^yymOliVnk1@OHWpgbzH%AZMD$NuiuT!uTF^VPfQ8dw`Sd>eW^}n z-b5SoT=$qe2UA+F?>PKEJ>b~*g`sY}b3Dt%h)v}Wl^|Js!6n@vt0sd5%>tej_+r^Rsh<%xB-wTkq0-bMBNRw@>=-UDg9sN=Wo5M z!zY`c3wn6)T(J8Z-WfmD4>jK{<9dBK_HmrKTn_K8)`dphORJU`F5NvpC{8-zu#&$HZd;=<}# zQeHekO&vEFAFfx*IkSyr=N37$XE)-v{cYZ0SZgip;>((~nw|IN)|-n%S%gIs?UmNJ zHqBq@ayO@YVyyY=N}j_rR&W@9W8xLQdU^fk`HKx(C2t#S(l!(j;W8=tw{T)38~b!# z>8(%l9e;Q1y%=lA^eSQV8{1&^o<28@X;ZyQPTkO)eEsPLR*^g{ZiZfKUgmT;4zp^H z)vQh%a_+0{C^m3nOy&RS+2}7V>3mhmr}a(M7sF%ARsT4y6!^4u;kHNpf3trkTz+#m zn7!wq#O$fRxZd2nu`>AD^9`+PO>7?$rt>SUTy#BW=d}2PLL9xVE`pstXL~eK!dKY6 zI5FqGU!8xIcG~xKx1U|RX7J?Y<>eP{H7JY8Tus@;w)a;Ghf21_ky{CyZ^qYt6+Jj( z*;MwAk&PzZg)zTx+;Oy6m(=sdD{=3m3H(#@DkHZp*|lm?(qEgL)^qQ&!wbHB4=r!p zv&C)M{iHXWuGYWtwf&gB<&#>`&NaK()FxkEI{nbyuK^3#onPk4N*-R-@7;5;*>-Bh zhOTQDyWZT=>QLBy>vvg`rS;(#ZcY=em{v__pAc(pmG-Bl(DAo>Y3PGHNqKAT6y7+t zrc1r$5OY@-*ZX@rYk!wzRYl!;?9N|YR5Z`_w7#C6magv6G!~^F47&R-T@vy++VbG| zr67@q4-dD$zMlW%<8k@(^OwIflc)~(sHeht{j z3k9+>KRKIq1bo_@bLn@`4C8m!Y8*F16(33nMm4^%+SGjUV1A(dksT{1Nb7Lj{5oG} zXX{EayUT$S>u*+xyk#{A((Y%N=B{L1^yc2}XY+#Ub}8vz^lClp9W`P7H@$sA#?!v2 zMWi{i9xwW)G`HcGpXwUdhRK~=^RG>wUy=6M-1{+CrJI-&7yq{lClo^Txi*HKFmpIfIaJ+3h!w*8Kbb*j#Gm!r&~!NDp0sO{?8>kA6d_VO1SBh=ri-{jwk5aIc?2&!I1Re%)f0qEf>4ID;TGLD39V~ z>`!9|^k+2wb+b{XYSo4HA@{Fk$r%RK7^kNAA3pV2SxI2k+e4^h}6N&E#&+h?9e~X?EM^HelS^-|1P<-#L)JTczspM zi|^tlL4j+76`FQ!)+b=O3#rFnHBGp}Q#W?&AG+-4R6@Gwv9xN1yKEzsOJ$l2X0Wt&*Yp_%!FA zFKw#S4}7}3?s1pgtham(vTqFfr)X^Q-`u_6OtMOPm-LEv0b$cGMzQC-3-`Z$r_=iq z_x!Jn{wLf0{zYtGQ005y{KvC)N7(~~d<^~5*%p@NTc#~IpB;8n$JIRKBM;a7uc@}v z_A%YOdTCQ`w@$ILGGmm5WBcmX8aw~*r9ZyLO1byT?TsxxA5nUC-@aoJ2k%@vbV0k) zRN*E^g~KVam2F}UAHt0<^PTv+m$QHM9XT^iwq5W3^e=Y}v>OU!e>xmn zx_+wP4U4PWK0WcV+N9kRd|Gg0#-meJW&BU)NbUdbKjrh@tG0WV9hW`7>AlI5+k3^Q z^KWM1YH@q_IV|z1RIIz7;%={rFCBOUdGCa*6q*}!;@XQdI=xY6F0E+oS-fvu{|0B{ zcaH!5?6iK!_=JDW(Y_X+-+j*0-up-O{cPS5wVFGNYihu{wu@O=2dAgrUlO3F$?Os5 z?{D(pm1D=^kdj|(u3WhkFsqa~`NYi1ZC^JDDH@(Qefnr$Z~D}!Q(4~q*?C&SKiu4 zjQNM5@n_GnvNAtEzqq)#x;ni%F=8SjBBEkWmzQYhe}8eYzQ`wr=X74C?P)D_iM1x2 z(>0?cPx&{m%pES#~ym__WA>+&v#p!u=^SeKW?~iHu5YC?XB&bnnr%C$*4WT{3 zJ)K%s|L(e&rd(&2xO>IFasJGi!Alz7yy`ES=I-xyV%<%zE51z^JQUr`LWC_gr)b9> zk<6@=nSPJ!j2nOLiXMZ!Ridr4rQ}`(%vkQS{Eqtt&C?$GlTJO&k=pe7xZ|--sjUIm zrX*}p`lqqc*?j)_$L7i>)@ePtZPsGH;$2dgeblqFzt2x+%#LtMZ`#=D?Gd22|F*UC zw16PzybTWTf>yO~c!uVEWppe%TCu^Q^UTha``0CAZtgiI&oxsx@fcs}xBqqTWB7%I z`Mp~cCr+Ko$!=-Ub1-ni8|jRUnnit!Cdjh!@$qpl^M78nQ~Y~!N_eVnLgj={hfb`U z*gb9AbMN(YEt-oS2&P<5eOqCA-EZE(ox7BKuK9irIk9es-mlo*GZ_Nn;vPyFRn>%~ zo9uD%DSdi!zO4%L)Zcryek@4|S4qy=_T=fawbSOao7NQuPTZpOzEE;`s`uf```6t0_k6yQZC}~`)Bm^w z>fCY`cw0Dmwyy1Y%C7O0{lt|Cjrvngimr^Anz3s`9E;?QiC0$7yRvX!@_)H$XDlV^ zx5jLaS4g>Tv#of&rXI&l(<8z1(kvb7Hgjj^3%+}&6Z-nVKIXHGQbC3?PrNVwVvKj0 zJpb~S?aZQm+6!iXYpr~`axm0xvVYRZfi9#cjBBmQCkycbG16{DN#Bmy?5vN(#(MGPbW-JHt)N$tF(JY zY1RMa_dX1ZR(-RtV@tcAe#1p9+~EMLxj;GVc9!WTuFk%vpJs-A(^@+(yKUzBt82DQ z-^uSNEd+#o6YktLO6~J&heyh@Sw@)XRo>bRvo>y1*=5ovasHw*`7+%k} zHa>djn2d<+CDpgDCCgH-8(+S++3u60wwl)e6IWmAlolVCl;aP(P~qY2+uOKvvFfu` z-SZVUt!DV_C;4fK=uOk-9PVYYCjVIb5-cA*KfG8uS$xx-ko@?1hDiZigWetz)N!vd z3YxI*)-?a!b+=z?dS|7#tEq=Z+*tT*)fWATO|LWMtVJr0vt^yNS@!hkQ|}FP*59#M%t-xNWncBi;yYYtdSZ9v_8PLwTH2gR zKfN-f*DW?+0>6B9g{NbyglCZZVYZD@cY^Gh-TK~qf4zQpnc?-r%DclnIFE-mSgxD> z&gJ~N31(?^o;RB!)-O3a`+UaJ$+6zX-)kmLcw(M@Q2X)heNDzYO^TmSV!88(_m7fN zG#iJu#5$eMX_=hYVv@Aq=`CXSmpVKt_VT`jmj_pr6r?PBD6v^-_o7QbTXU6@xBNeG z@s433cTk-gONdLE>yz+xrp&hU9olm9a=iAqc^u8Jt>s92JWpS(Zr9^&F&DRlN^3^F z-MnhimXJ4(lnTFp`*JNy%JkEQ#rsP zf3;OJ)yY#eCE<|6z8l*AmYz!%GJgBbs^wCuyuFO&&!c`me-4~b`S|$kgxKwcDxovl z52xwA-1q(O%jm#qNt?9yu(#i~QBOX;_sDMUBMY=tJw+`3{M>kW{`M*7>MHy1Tok*c zvq!GDl=V25-%YN^&-oN`;_lrnSGi@!8UDfZT;z{gf~`BQD#hJOeEEU%%nOT(oJ|Yo zq-s9iwY2(nYD+}+nV)~BzMLKV%!h@oxnV&V>wym|UguP(Ek58>W*Tu~UDVoTxwE$w zwKC1(*&BEMZ2qdyEs|us>Rv(vnytIuF~0gY@?WLu=(4F?l)g6*8O^#EGHbw(KRWJFGJ#{ zXu>0n&s+WSUS*tFzIN`LtcRBu{rPAXdvBlp+@Iecd{}X8>+}BUrCI`)C;77OJS6h% zMBmSuWt%31%=Mi9cVeRIRVx#TFmtX}C7m_31s)lXkJ))G-PHG8vHH>LsoLR5NlBkR zeY)}5ab?H6?dg%*Cog8tF=#%mQvB=e?ay}qSZ_>-wRUIU8FRO=$-S)fa?>epnVY5? zK3~|7;CpoKVHS?Oo8ARir@gsl?iCsq|HZ1yP-dptmjsdI85XZJ_~$ZhL^hzDIc<2hL^ zG$h2rWQWbB)erw{*Y97R60VhHx5^neE&6 zPoJ9jn1AuCck4Bg^1Zu5IKelpdA4NlvCPZMKIX@1t!h`j_1NtwN0`Zn^?u8b8vFQo zwF+?=-^gNZUbxljOj=#Jeu?zLg$s9=zt_{(Pd7WYzw+y}uUp)zuW5^lUj55;Z{fs= zg8%C3qSl@}eEIU>!_7Z<(%qVig0DT)zr8*G{*FTBmFz24thlGq%dTle>`h zqQq)vjGjnW1@~*q50WWU*v!{ho12$^d~|es{{3Y?J->SJe4Jl2&Hc2?)(?L2J#Su3 zX!x~!>7kWV?uj3sc6R=&DfeGJtd!zulQz%a%H}rww!x}E`c95W zMNOW}?;9JF{pZ>Ie7pU=oktS0wR^ki<=c~DnSb^6UlF^r>(`8e_1~S#O5GkmKQnz! z%;yz17d|wc5gQYGQ^8I9-fP7>@%*NuezE>{cb6Di$;t1Lg~9e5vib6f81rQXwD@%@{AZ?4=D zgTzhQrPuyFJ-t16llE2Sh~BWr)AZzWqNKh*JIQvJ;qkP6zo%rrlwhykyXD>QOvmF7 zouzV(Z~UpdGiOPg{LjCJ`Pa6EPoI(g`0!m-A^4_e)>0uKqcTi9eC`teJ&iwKwcfKEo!K0Jwy7S)1 z*goL>ks@RI{Wxo~Q{zRBmSY{$t^OPr{Kn&&f7tu@$-P2lIa1dS&6pdzi0AW_w3t?~=mb`i@8>lBw?^@!_XZ@-r>PuQg0X*Ip--DUPPaqGEU(U;a-W9+Xw zzrm_=&5R14qQhD1e`|2-t`oiz_A&VU&G*r1n;EaD>=!kDw#4DWcK`PiE(lb#zxsM2 zU1O@3&D%ZyT1_krUH8;f)_HC;XW03k;jv|>L%MbscbuUC5Fn9H8v-Fs&!#EE#%Si!S+>f-%wk+L&WkA0f4 zLdRH4cBblXzjagJyh=}=mGh$eKwkpqnw=|O$GvXao|WX>q5A91+#6bEqK~asH5^#$ zw<+7eUNn$Lf4YCqn$|Z~KV66`_1M1x235d=KtxU7|Tts z>-Sr~oAAaCpG527pc3lc5~nSe7<>U zkJ~>atbNqJbjhI~FCT4SD{v|M`*d;Te1Ti9%K1*Lo4ER$?A`6ghN@4`>`I+4@4K_) z$?TI`WBKPFICDiPt(M2Ttk-R4)w_QCNnx9JW(l|FT=~gaslb${Z+HA^SIC(U)51T# z>h<7$JF{2*bYWcafo9u=V&$Z3K8 z;^=dBKjw4gaeSYH`>`1J9pYA-W=@FRy>0c>H(8?JJKjjGys_1UFIe^QcAXBTBZ21A zEUK;@+8fipW4g_z)y-{TE@gZFY0mEYASRV?P3T+lZ2?Wi-9~RNOt{D$sHIkv67IBb zYk~gEE!Jwg-$j`@wM(r1!S(r6gqZ4{L!m#oMEioePt3`)jE|nXoVdYkJYX|Qk zx6DfqSJu7#V|ZM2a_m>x<2NRN$W1BX&a6(mqgFlZU7nz7qkhf)|BG4YgBrKT=@sPi zuKrQO4wyosW#*}ciV+k+!$Z>e9FPke`KK-uu@wch- zt>kWQW!G`c-n80lefWx_UQ;Y^w)h~+@6%n zww;H(Pi}NBKUO|bxNOCy#}-HUL=($0x?i_QO23{V>viHlOYEM5LJu`t_Me*A$a-Mb z8?MEE=iOq9;w-FT_FnTJ87w7Ebg?1lBlKy?FQ5w1+{!_`l{L*le{s@5C) z{puRibaKY_Kli@8^V$25>$2YSOMdV2zP;JtGj*Pq9eUv(JCWse`qW1^)xzZEO6QXF16s!R*s2 z!6`pOLijHX+AOndWf{#@1FMj!9*EjD)kb?ds|`OIt6 z1fS3A?dh2zdQN$P&?fCi%ldlbC!L!Ro4uIRcK3tUX*2E5#N@k{J^h&Zob}P4ncFmD zPCey!F3bJSLSnuxNWy^0{9{FK@n|e(lPP&6_rrM9uYDI_>0zBjFKq zuNr1FC*1h)TBiTi#Ul|_AJ^Koypig*Smz#7x#s$fbgMGul zJ-x?MuCKk`Z!K)P-xU6n1yTI38=e{%`%)Q)c1j`?u>SedU>XEP>PP$j67a zrj@Z;eMP382hN8oxY;~xtyRlQ;yA4GYE56V*R9=}ol{yv{~3H2pS`-H%jZ?E6l3xG z8^`!9e{bGnv~|O>dO5+~QziSC`gm@!&~99?WXGYs-aCR;9`P|X&oJXq+m|<=QARMv zd`C@Q+{Cv=Ggp4i;%ZpA=vc_PyBFWEH+QSP)^wit>R_}fLz0Tpq*bBwwflQdPKu3B zd(o}4Q)IHJ>mTzMneqFd#Mk|}&;9LlpN^??i`Ieu$GasppPaB4c%^o@H08v)-Wjh~ zPVRhV@P}2WcH=FLga$^Y=)6^mzim$MeNq^_miPCS_34K~B0gqLogu6BKvMX~a@+Qk z+h@pn{n+w5-}J5Br@y*9)>pz+O{H5`S*@3k2zK}ySM*rdsjPIfVsTM;_cx>2s(rW1 zp9n3Kv~W7Vc*}jO^Fewu>o+Q1%c_ZTDgWdq84>EbEAZ22ZY^!?Id9w^-ZHylw9x6* zx7kt54hE+mii8@j33qvR=JcL7A2K@L?0U@ZQzmMfd5cqyhvU+}@89?s^y+v0=K7E& z_AWy|#A;8*!Sx@?Im^p`PkUc??8}434!JqK$vwKVF8pFwWs{rwG?rUzTFoG6_w#4Z z<$Rr;t{n5(+GMphJbw4+$Hw0Dg{799IzA!abnZ;dX4$$`XJ(_UFOyQJI(7DA8b`hc(&o`i4^HGE>GQew7!YTRjEGJx@=Rh&8=0Nf;ObZ1#!&2ZWVs=@Wj*Mflqt?-)`YNEW>~8;SHI8aS|`H zo__ioC+4IxeRba>_XOYIryG~;eAXzn%}096q}H1?e=6Ee9d9?d`ayuV)kSIL?9!yi z#wYZvzrXvNcP4cP`>TpOO^OVxoC^x7LO*8T(R)+ul(mT8dsTamDPQbqMkm?+m?(xb zQpVnTsW)dZImMqbT+OlbO4oj=t3DSBKVI<&we`7jo0TEMQR{fm)q~3VX*>HY9nKmA zuHUrg+<{#u)|q{ARa~gQZARbAZp{vhEH{zk3~kjnMJ{U!nope&Yxz#KrnuQQSStRAzqIt96HeGK-y&xW~D)NpZJQ+`85K_%^-%xb}ZIla%osPp4;l z4o`^vzx%82p+!%EP8ph=jBAngs+hOo(1awT=euW|i99*M((~VklXGTd?QRXo^=9<` z!kfC@z}R;E`wokhf~nql@8+&qv*z~;H^pW%6|MW*@7Mj_dDPp=gQs5R*WBd2LPpQ! z+3Sz*-d2@;wNJNZllD2)>2`lj4#Y$S{X6-N`+$r^#vbWApROwEu39(WKk56U$+3Z3 zc0?^Q*Pb12bzHK_KvUN4=G4wJRwvh`-Cmz|yT+}1dDM*848_6SXL^s-pJ-H8u#d9h;IhjlHP^=$#Ug8JL1c0=&P!^)zj2nyMWh7NgNBo~V_4?~lvF16#M> z*}7d@{IlLeBUPo{ahf-|W%j)d2)ygh&XsU-sm$$y8%;mf@0O{Umz-QzYqrwp!l7ep z{8E3e?&vu2(U0A=x5W4Vv1y%MFS={gvi6wXH2s;9`rz{U{=}2(c#N-gM9iJ`dSlX} zSw}lEJ5Q|BsoZpZ$IQ8gwHwd=mZ>cib1vJOl+*X%#gv<2cf8vKZfncQr5{mOj=dCq z`*WtHoAx<*?XrwduQrFhx$x@C`R#HKE}eVx^)btZiVo44n_oTp6#9PeZoQV|oMm~l zEGMM~3e~B3mu+40<>-^MfdZrfPhYf++Ney*$KWQ>`9taijIU8^Fo{xg=J|9-7rwQAMt>+3R2q>PTpK0fHOb)%@vx-B0MaqEkSKAr#T-P=fe zg-xqlHpB_eG)@##D`t8ie{pGQ!-h!)QL{gsSeF|9y>4E?AqKyks#iBOCY?8x{2%>C zuwMUAv+Bj7Sx*^mPv=wH%~o_LmV0`|VY9wBT|0K0Ep0xzZby?@(PYtY|LdkaF;-l# z>rhSG)Y9IGxp_|K(%~Gy^7h0qA@aV)9Q>q1d-u>2DIm5KpSaJ6!=cCj7qeBCNnSCD2yXmm$ zA_Gssb>*EpD|awFHNISwb<{lV$zR{9$O5f%8!|rg3*?*nL;0^B<^$W~6<@i!;8SCN4yg!!9#GRiTIpa+h z+r8BSH@BYYdegNo%twA+2yfupi;{w(Yjt*>G8BqE^qcqFs*O+A+wpADUY7Ui{(v*hXVYkyA&l{f}e?00Zf+dloUgz}dMr>!mC<*n|}kY9RO!a4K%2G!kS zYG-9$OpvRozZ1g#^Nq!Utkgwrw~q6Bv+*7Cx!cXFvip`>Y{{0Qc-xP`);F(O)y?s9 zmHobH^2!am<@*w@?7jatWsa=>4NFVcmUWNcOuMt;F{icu&KNo2&r|yQ`AsC_;(Bdt zZ5RHY?v+{^(DmcHvbmt_t1BymFNf{T%Lrk0Sedwa^I!81@3I$~ii(-c-BsXYsk%GJ zR%ErKtE-9-=k0BoYXcUzJrmQ7+Lm{BS>)$ud3oru_W+`uhHFPnXSmWj*DM*VpCON*ZH-y?S@;V$YWr z?KQEx@9nMD3e_qv=g%;?bLWl-*HYun(L2?6Kiy0*(v8_s@cG$U6O|SJd;;%Ch5lW& zW>wR&kkwab_%1tj$_sS5&Pi3F%)O>_|E>=8@bJhCd)0rtZt+g9ughP}lTG}we(|%j zv%kK(?7jHfi_)s{^72g#J0o-oi#ph@monAg+*$nm)Ku;4tgH-|0FY;ntX#4rWMzoM zWX82^CwUg!oNzi-sB=coje=vj6Hf6luUFo@d9!}p9*^RwU8~}L{`$ouWpd%}S>NT? zckZr!@wKY8NpkMnCjkNLUOzcCRXcz0*RaAu!?U5Q_AkAfVVV_k1TX;QlVYr5#mQbh5g)EPyMtp|x?rYuEju++bESP?8Z*}~x5>4gB z^X#UqxN&jr;aO68%QlDK)hfI4V1wA9?vz&m^0=P|9!^!BfFxoJCQd|UBY)xbt--d@S~ZyM(=Uc9S3>z%Im=`(dgUIrS^ zrdnQ}FK1Km;XtD^+m{dL@6^9KpB0^L`uXlo;WnN(_5}%74(wZdWcuVF`Q=AT3~rig z)V-z*#%_QXqh{^&D1=*Y~c8QTbTE&}#nL zR<(V0r`pY>?Z3O1on0~i&8-Jji}`rx+8EpXyrgE5yY>Hv!mmL=zwK@7rYxD4%f{0$ zuNr78kQ;g-^WXc|Zm(~yUpYIC&t2HCDO~2prQ@mhH^k{LTWIQLUT=K!P?YuV#7CQ} z+f>%dZ&@xTQMAEz zotbH!`eMq=x#uTs+7R?*PVW4^?E*90c`KBepZd??n;7+A?r)|&#rwUs>bB)6?^ zEq<8&e7t&0>r_+bl%q?WTUomHW zTSVPkcHVdI-97d!*y5ocD)&|6^5)kcmQHU}JkiH#|9#rGLQUB+?gMwaE@WKG>iV#$ zGGq3WAc62@c5g%XJeR9j-DA7XrS#5b7j1@=smI>GZ#t~>_4%x%qC3)|3;xT_t=~LN z_exsDy#vqg&Fr6j!s_@q$T*q`j( z^JIAvx98E?r~IC+pALF;8|a#=|JTX&@S3^zmGbUG+B|FfZL5EOlkIhT`}AdCU|^xC zaj;^z$C4nM>*tofV?AxT{a|Qo)!w?JU83jhey=$^Po((c&eHd?QCr^$F#NZh@#)V6 z&RSF7@3!|vrloFzy8hJl`c1}Uj1aUpXhSK zEM~s0P}jTl8sFr9GF`D^uam@!B&N^`$*_qgJ}o{jYj~D~H3+-9uI*~!ytgUB@#Kk|6uX8a2Ny?a zF<5gQcs=z{fp~DxR86mLt_-^^!cte2N>6_Om0Xz2KKc84^~NLF?q#Y|ysbCAUOC0P z@8@duYwjPvb!}DNUH9#rz#*5TSA0#=7M?>7-cYosVx!Kl#aZV~m!-(ZC1KCe)mM=D*=_$c)#Xth){^san6GGazAWh`fDl z%bCgt%fmnHR}gyUCU^7dss(HNeQs<{OK@GYH8Jqe^@(5E>u3J>l9F#<|KsVqyL-;8 zmNd`5r=xM=IQKN^*Kw{>9t8f#p7#6KuXp#i|Gt0m?9A1+Nr_vUzO3D`jmc5JrLt+& z=FZkc#!XjZz5N%dJ}XO?VwGj{P5AEh^jnhUfo+Cmr@D4$ci!the%+Px$HYkMo2FTh znx+ff+**0Ynv=8G;O5mXi>?#vTCQgLmX&T*+r8+Aqe!GVck`F4@6X3?N}3Smu7B#M z-uk-wHz&TYHv1RHfAi|e9~=7$6#Ln`PaN1>zeR1OkxioXrtB*`w|{Kh@4qudz)rVw ze*g3ODC?V|=8Js(8GL+Fx#Qppu}!D4re{p6IsNQ>1F!p}?P^Diq|g8O_oVac$Mv@^ z7e=e**d&Cy@BL+aZ<*MwS5<2B4IQU1T)XM#ovT_#j8Qpu_CNb9bxn0&a#d#b$w@C{ zXIp%8@ACy3-)>CzUbuCg=EJ?Ax36o5#U!m>-r*u7Y`kM;yTi(mR}%zwh&p$;oLhhG zXztAE)4#tv_(!+>+=s^#)^2=m`6P#Z0^7xt@^2qcZT-8`$FsWp(Xt)sw|_Ag|9h*G z;CJ8Y-JP%x=R`x)-fz!myIuU&&otmy#i_Fn4=qbdW?26J|gqE5C3*BLHc-jug? z;}w=}{s>dfn^)JfUVUNV8LIZ~{`*-6mmQk)ezoaa9h1XqhmOzZ{g!gQ&-N!zkdK~g z&Y3N|#?HsrGaux+IaPUj-JZnrynVeVKWW|G^yg|v40_-T!?vk50>3pU1ayc8p$h!iD1UzRk+J-^H0tnh-0PY}~KBd!2ep zxb0?(jR*EQ?B26$?|N(Jveb3Q*Sx)QeOk?Jsn40>`@~*cs!sB;UjO*o&%@rWs`YEW z{?R*=G1oHZ(jonQf0eJl;wo;@nj4h1(x)QDuWr|*&!-ra5+{|5ZuQd-?-bor<#)jB z(uYguCdGPkCK;uN`#ifNDZet|$0DAY!Y4$}w)J#(7L-ptaq)HbwXd(QuS%+%Ya zj)BI^0j(AbcV5t$VwmrA?9{4NTx|TJr=A&i8tPSDHs2#-#WyileBq^si@vw|@B6EJ zx+h8QVwmU5M>DqX|L1pBxw`zLYkBVSced4Kt|{TF?q#klAv4ZvaVC|PW!Lq72;Ag$t5bj2UM;kgeYZ{7{>t6Q61ghzhl;+bjLr9cS_2eIe+iWc7G=kb5za8 z^Y6!bE)N$f+nNHoeEmeszGc5nU*uG!cD$h=7<*6HwZRCZY9bLaTqG?^K zw9Lbf1>Wlf+;&V-d=YnaOQ_!bvnobAcc0Ig#`h=T^tH9o&%FE<=svEam$`&-+WJ@PADdF;M#(i$DrH3>3-JgqYV z_Wk_xVb}S(_b<%nFTE9a{?irp2a?%tKXm1qI3l|m^Ae(!H=LICIeO5-BTH*7+wIj? z8uwH?={&f#$0W95wMpZd)1b2hE#n-}|`##>MH^uw=v zcKv-W?v?&^lj{Avq#s-CT54_|ZIjJ9+gxg}=+V`M|6Xu$&irhVaAMAJ3!~*brtLMj zd3Dmd7dyj_1h&s;6@ScrO7N;#iw-uz03o@6+x+3wi$&bA();)qK4? zcjNi}F;m+nO`14Uu{l55Xr)KXv34&Np#T`c;3kUu-bK}d-v1R)AxTk#9ia2 zy=tx1*_-mA5VBVK}z?W-61d^R7*5yC+FJE-rt*E#<_z z8M{{>UD~{OdZ%HZ+#c3Y$IQ(z7zm&!`>~2~c}}_V>k!l3W>YQ^M^h>`nP``_4{| zn^QGY7dP1MyP2o|Zl6V8@tL3`wkrkMn)ZzId2(u>_`l6!a4J*P39kDSbN}zLAF9^w zGoACFTS&->U*5i5DyD{y|3^l!#r^Y6(Y0Y`o_$}XU*_K@^Z8Cl!HZ|!cTJAoum836 zr%J+$9XXGDBEyR%etnr|divQSbpkWqNdbM2W5T^1QjbHa#i)z98a$@s1d;>;t-!SMyvES>SoRi=*&mtJ4Ru z0!cl_;Ftqi!mk4>cF$~N<_n(4d1qCj;H>NfiKwr!QHIX*IbwR7%?#zGCu!|EW7GF0 zOL4lK!;?!(qa)4K9))uKTzS;ziu3SA6HxRiyNFR!yA{Yc6{t@6?3Yy$q*& zLa#nQxu$bXTEat(Mfcb~&6)gZ+l9(g7I~|@j%WvF7k2~&7FLMai_UnoV%sVCzM9{M z&-478w&c;wrO}h_$v-{1$%K&dhYpWu3N>LmnZCPjEM-YlA3H;Uh~)U8t<27fw7@eCl)^awKco^ zbCI{VH*ec3E2i6tx7$vpyt=&ne7k%dhc0*i?T7YtrjB#>ZS%g<-jjRl=lr6Z6l3yTUZ5Zk1EFI>-P>ck&6zsyVCl-+KS@BGa2&xdZF zk5h|#1j7IQzPr+Of9fo2zWV=jpYLi|b6-sLW8CZ=FP=+Wyz91S|I~&4!nal}{Ve#m z-mY5geRS}w*myf`$J9%gRvIt!nQ4-Gt$*c$t55XiUHG!U?9GSbg$M4eIDIDUj3MKG zpWKNTw^p{!v#l<9al>)lgly9j=@}+jJ7exGV9ojAY*JK|w>Ez3q$zW+eDmA5=;9(< zmU3ggIj2)N@5$b(mNq_boO&@L>h`OrnV!|B!Fx*f-r!HDh(iy_)()*SN5Ws`{0*7vpOpif=xL>IBgp=otXQwC*;3fm3aJk#O~nVo5Z;sf*7sNP1&t* z_EvlctJ=Z?r^;=<9kr5;=xv@k!{(%skl;>{jI&~9%UWZ)Zp=uNlfEoEIo7Z~^g`js z{Ys|4r~f_O)p^RkD8%?k535!2D$&y7kNeL)IbrE=b(yTx;Z~0sO0@+RH&<`lD3xY6 z@$0LpyB9H>33SQvNz8k;RQPt^)ERr{|Gnk3LFYv3j+Lhc?oN3er{p#5gi~3p&D!p& z|C=)Z>|`@o$}~}WHkVJC=!T!gI^k=syKPwcLgZ8YjIM2oiaxhEubN#rRJWxn-|fv! zxAW`jbT2qP(-HfXyh(eXQ+vvF;oJSfo3a(W*R+xK8&Z!jw;Xcn?9-a#IGtWs^ah1`_8J0{k@&#SE5 zc`+hb|JT%FX_>#JFD@+HU2ng)_HE21PZ`7CI}<#=y(+Kg>38CC-}~&~!$t)|L&K_X z{k3;i)!qMMzbEm-Z0+s&k$=M&#P@b=%v5}F?}5AiGok3CGa|1}>oyFJmAw=D?&6XC z$xD5eZq}F?|I~T3byiZ|s@7}Lq3k!W=7?~#?0Mmua@}Fd=f48NrmZssy|udzmx=q7 zJvFQ|+)yz>$6 zYCCuDv~l^qKy>~$qhQW!nJ>=8oD$sn!cJ8q;omWTYYm?}0Y{{!*iTD;y2sQ#>rZl9 zD;IyxlX>Y(%{QG=R7*t?UD7v~q$ZqgKKdrI?LW`@4}9m+8!rg$&Z*npWO!^b`|O{6 z!ds7g;b*MeU%xZ&@%Go(mQUfb`Xc307tY1FKa}Iyu0zY!JJY`f9ITmT81nqwT&3ME z8c(=*zerY@Z;eu(eDb8x?sGlNTQkp}ICG}v`|W0@txTUY6E*iA3#>1cQJPg~P`y8y zZPPU6ki*tbeZ2ZMRGKf-nUc16@kS{bUJ2nDj-Hv3(=E@p9&d2<+=gWSt&ipBl3ErqC1ayTN-lPoFmJaQum{JHDmXG5XKB z&>Vlp_@na^hXkhi;@tan#g@-ll9)3?du@F6L-$sW7H`+urH2&E>`H|M6ouVS#x&2E z&iFu^HTX-{@}ozWpI&?aqg?qW*&gx46O-?6XgS9EIIR5X=kWg)nXYBN|C^2zkKrfi^y@vAy~A%M})G;j8H@WQD(qhg=jW(o{29cQnMaZ?Q%8 zG5-w<*6dhmukcRQz09_D?!wtj*-1}M^tfDq(qnR(iy}cc@rEWz;%k-NK zUz24yH1eFf&aRHQofelm?{L)4J+t$S9zLJ={fnvf^2z1mGuAaThu6tHj#3ryI_-#67DP;h#LLA8)U(Oc;kC$^=8`><_O+kNhd z(w&5(dfV=3w#1yeubq4O%yRy}^Tf@|98aAOt-Q`%krJ*fU1}_NQ&hH6u{uS+UP6sVZ+y=xy=2W z%dYLd`|VT4>dW;-Gi^`im=yK4`$Wrq={ znY@AhuGhw!cj>06?LM}2$&rUA*If;DxKaOY`rnW1#m#+c)E=@NRuwahd30@U^!GP6 zomU2Bnn=y{WB;!uQnXRxSI@8I+?;D%>vC>xdMdt|`P@3YA2-!PPIVvizjf@2uCcjl zobj6bbyZ$Yx#eD;UTvQLzv{(O#=<2!=TcZRWO}cDcrUiU;LM(#I*mWOTU4IPlsy0U zdiLD^O1W~g)A%+o-lQsfZpAE_l9%NZ-qoGu_>(tRH?mOJ{mM4eoZctwU9vW*IkOFR zM}C~Y-^1dedAVGw>dd%o5Vd!a#F{wqC9y}QNnPmXNB`@yTkl@!`zC~ z!t*xhY-Tzl9-+sux7|Kc*V?A_dvDOxn-jd>o>*5l#i{Rgg!#>>7vg`qKMOX0opS8f z#Mtgh5o)Uz3*VGex6oRqdcxQ9$%%D+FQ&|S<$bht+Lsp%vQgPuG8>#@9Upp5ll79A zv`4$7?@d?byss0~bIS_b{36w73VSXN+@5=TR!iXOu!9E`761M7{aUrxM{V`*&>sK# zrxiIDTF=b22A$#0SKiqr`}VP}p2hAu_VpeD{9-Y8Cr$};e|h6#^XpE-+m|*L1m|91 zc&FE|{^o&RflR{IAcx&`Utb@8yTw%P*+18hhm8VrA03xGreEN|w$8pzX8B&nl# zy<&aqnXA8^GK{_18FlF0-Mz+XeD+LP{N+y?8X6WlCz(cN7?@;m@^1OEL&!h3bZs>! z?`%b>JN@0)@>Y5MwvRhw-RCUbWWFnSkMGLcx^v!Eon{i8@ii)-ve7?bpZ-nv*uSbL zKFoi3bNl>lzmCr0_$wi5oBnk2k$NGrhBMxapua3Tsd|9I{&q)rHkVkPbW8n_9vXno#C@A za&ublogEX?bgtUF_|7(ywfvO1Hf(v|>aA9?e-;F-lzL*^arMErn9XTt+vV##jK6sX z99jL^PWrmri9K6newV*r`TPG8WA}A-A5ztmp0XbMEFCBHKf-g*m8<~U0v=8l-`PKY z{#>Z|imR1rSMPy_1IO(4efY~0Hr;O*@1<>wXSx2w1P2?}|N9fVI?R^QwkIT{KkVSa zwQW3-i>_vcW@N1nTYOP#YR1ctRo8#7Kb!vM_V)aHdn%VMU22lQa-K}!9jU9%0iK>K zLzF@_p0G79T(pPDij9-$c=yQ;vw+iI!j<;TSNN)SN7c$os;ckt@&4I9YP0r+)Q6Y8 zxR7|`f?|}7k#qNwX1l{DRUJ?6zqQ7$?%$uEtlVNxo?~QknjNcFbv-kb(O72d-Ix&WtQ;q^6}+eUUs&Tnf=u1)0uq1e|cHl zwn|0um`H{2)*mUmv(@oLSYC4T!4C)7<=@=c*qo*>x>YLVzes3Em{gD3T)%FH8LX@q zVi&aTJtAb|5)$$L*D15PnoI1ye*F0I=H~REprE)oIgkY_LbR@)n5cYfYp!;&ZnPC^NxVYgqX{Ct* zy|)SuqtFC6T^U2JZHf`F( ziH^lHUg{eaVL5^Eb@?797btzd#z*unsZ?S-$et(`JOWY*!3 zdQQ{)dpdf0=av^HFZEh^j902+qF#k^#|fLOzduV>e}5Odqd;-)99K|cv5#$Sb#+=8 zur}=Kl`A5mqKexarOZ`6tncn#Jvk<4oqB7I&P0!2UtfpE#nrvKqB-kui2shL?RkIC z7@x1Gta_BWHX~?t(8>uOOZZ^j9tSag1_Wb#Yhue1T+?hC^ap@zmmyf0$$(V3nq5NQ{ zu==yJv%@1IJc?&@Me%BBb>E)gq3YGjw6ph7QbeZEky!yA$8tHOo|rN0_Dee6C%e1k zWzoAkmR7p0uRJHaEta%4TbF--pVtec4d)x`pBAy+Prp(vkmqCa-|ffae*3iZ^I`)6 z9E@jz&DLH#VSc>A^phf7J1-_2$dzVV=;0!EdqsJv{=VA`*O*=Z{`r%XlvGq)tRKJ6 zNBwu8ts)l(#|)FqBo7aRu1eKUk`)DP#w)MRJjQb%dUL*Y~;fnS1Gh2B!UB<4a;$Rc&misNBpkLLtgI7F!YZU8Sr@DW(Ke*lY zJ8f2c^lXX6OS2rS;44|B_xIJ>+SokMR+u}}>FaY2x15lW`+dVYdYklz#z3%>e`YIvAnm~BI3C>2Apma zc7C4q+Nbe%*_#`NN=i-Vd=~x^UUD_-c#q`W_3`$iTf|pfc5$@wJ;4!hXU4-RCm-Ch z$+=}*_V(7-bJp(z))<1yk&y3;7cENK-1%_HljqN`OJuV!ZCNG$&Zlr&F7uU3Gao&F zZeH;rA;a{=qD3M7eruyxedkyhnwWfHwDxT%-OqV_-p0z$&r(lMyZF^%<%+8d7VWAR z6`wA#iuXcp!lRnR(o)d_XNB%)1ZLRHDVOF;U-qJ8mvQ>J3o|uC_`?m7et&;&UUo*p zUtiy5@mEJ{-yA991e^7do70YViEfdf01j66(9F!p$Vkf)=?jTdM8v0uPdQvAR=&`n zC{1WhZ8}$YXZf2Opt9!r`uOvwPA%H$`!(Roj>5-XIwHoqrb>zPLN)`%rmWX@~gKzE}8qI+HIlN zN**q*38zyTO6y)nZOOU0Cek?n{V}V#eAga)FuizEbLszTG9YUUh%6DP!}k+Q9@q|9{1nzq{^=>hI5~pK~kdRL6(4TD_Y0D%;|VE3WT881D8$`c>@do6DqG_X!qd&p)hu zW`^Nn|M_YjqpYqC%%4d9k2imuk?;kfvmxBWC+8Z_jvmA^kwc z`BSH&_Edb_S^PXBFZl1>XwwxdI{9 z&ronMG?QG%n{{Tx%}FNd61}D;Po_`TtNs7#>S~k2EC1CkN;X|FPvqgX$4nUntB^^(YQbJo#SMs^rDZ&FQJBPg}XgGv)f%e1cYu+aB)>(0(Lmp4pm zX>UJ%v|If2sZ$x-f(s{|e%j2&JIgFL%fn-Zlj3x*iDw)BAD*kGWW=<^QH}XV=`4v2 zT-@CDe?A<3zyH6S`GdefuqV}5ZQ5kCe}RB`sQ2nstGKwhdN$~p8Rs#7U$VpE{>(%9 zHy)gC6YV}KYhBjU+uOQ)cimsB*t%vetIl(CtsN&{++CjURCnBt`QOxg<^7x+-kPjj zxo(}A6mMo`ruQ@*%c3V7XUo6^v|N9W+vB~}Ki5^faP##&ySMuLg69S^eJidkZ;*ZV z^3k8!OAr4O(dc!%yubc`+1p!Fr%j97S=9RMkA0Y;qGIy#zRvFM;_~w89vhB2$T=VL zOU)|i@9aIVaM{OWxo1++qu=lKPoFrk;HDp_lDzs@0YDCTCix-aZ9GHEs%RMc`d46DQ?AEliv-J1Jc(SJl1g`%0{Ys0uxQoa7 zx#x6R<|`-7@9utkab@s~RWH6=wP!siBWk>>c*66eTeAH_=DGCDx_0*WJJ&ht{>x6C zI@Q(HJylD!X6Kp}D;&IMNb_7UU`UHwy7UoOYmrF)=am`nuTD zXU{GbJ#s&8-aNU-$Nf9{``cUBg=n43lKh~b-&xpwG9x3Ijd9B%hr`Uq6V9JFeL8mA zoBg-9zh9u;81#2>$nCkt%7&?KAD7KMEUt3v@8yR1|9+@MByIW=F!z(&jT3YI=ICVH zxl}&iXs`XVvrF1y7J1LVd3(A~&bwJAn?L_>Y0rFN@&5bQ!m4lCx0cO3EM{?M!~bnl z{8gft^Vhs)`19$~slCF7?*s87ryc80N~`sG{xBAM>vf}gWAUdib?arT4k?G~h?(YJJ9GGOZ^(B$JG+0rvwr>h zRase?X%eMA{pY4io*f&!7YMJ=`RVhI(@u0-?(J_+r^hc_w(QdKL-((wRM>sJvf$s} z->XBig8s4Wb5?51*O9t4De>}*#%qg>Lk{z&pI58@cvO7m%$X*iSN_WsvikG&u59pL zMh!N;+uy(G)aJIWiZCd+r~cPw7nzW-F&NC%B zT(|0f)Cg->70b=Ox6n;?fpO!KTf1)8OG^ozsr^}!wcp=y_55?Wg5ma`O3$>NiM_Df z^Wpz_uYY#lpY{3umwM}k?>B7!b~~r|(cy`T^4q*_{Cu2naoa@Zf0O^EyE>GnF5P(R z>B;_(h}d{PUv0gQ-#&ky*l~1w-d!zSZEaVcsX_Vgk5%oR?X~pK*}Ln`>D(lyypAr zCp&(7B*vg>$ISL>TkdW1ygMF-YeTMN8N4z|zx_e1_2o{ki4iXg<}Yzc(N*d(WtzUb zGgI9`s&3Y~-+6g4)~pQQ_5K=U9ywGZ@aNqz(Zh$O7G~}Jam73K827S0c6%mY$|>ue zX}^AbL{aYlRqKUPIq%mRu9+)-YyXog-GYz5-?kU(;y*k0$NVpOx9jKWtl6ADCsvxgV_GSYG||W~u&KAUE8 z&OiU>i}$+MusA$1XSbjHW~NLt&Fv97^Gq@? zUG}%%n|*!VT~lDWUWyu7+Pdw0N0@A;mF zZ};>~&fRzSb%jdYuY0oU4eKw7`j)KuJ28>v5~F<1&0VFh&&|zNZ)cuv*FD|med3M{ zdC$7zQ+I2XdL8|z9Iqd@Ni%-Yr;t-Wr*hV>Wo-;v8Yoo0^wR66TAVc|%rp1AY}ip3 zdH;X;d)>|LaauAzKR()FFyqoSgQbcVOZNt9d3f31`!IWPh|9K|CqZ+HmtO5T`}a@2 zjAgXS$4sfX>~*ttnrmI(_t|cysl%j=#ovna=bZ@8_!_h{V%fFrFR#6Mb^NpWvz5+m zJ}-oA%dhY7IJ$0W;d#|Jfh8UHjrQyBN^>=?ID38n@Avm|He2s`mTnhkBQ^cpj;#t6 zUk+VoiurY>)qUC{W%;wF97mV!4>&Px%9OZ$bINRAv(;sr#Oy9JRaJfZY3YC>m87jijbmsaeqWX|(h#&)3mf|kx7qpmcr1Lw_h1@$j@M6mrGKH<&KAT=RV(;Z4-WHxN?=ts)oWX z)!*N_c8dkhcXW+5U9;uQ^p*3jrthA1Hh4BW=nq7TbV*=-?uC4<;n#`h4kI$FguENVRBTjk3f$u#_ z_RgLZ#TbdPCu=Pn7{h-S!uPfC6QX{|VX-(C#vXa^-uzcy#wJ|$CZNFc)n7iKg z=Oho63n@JkhDs_bE-OPGOyju{n07z>lfqevm}Iud8Qne^XV35de%3sjPtJzp@KiAt z(XCQ7yctW@7|e>^`|qpuhcXts${g2`eYcH7X72~P= z+kU$=M%$`;=eCp(HQl+pG^YOCb-+7s$JCzrzutK*+&Sy6?}=YR)ytFqdMb)C3IAFq zaBa%GUxK}rcfZ`*|M32c$`9x7_HaKxbyO?PYyE^NdT;F(JU_IsY^BAtqQe6B-)BzP zZm**Fa;>h`;k##Uu^kIryiMs@mUWA%QH*WJ_BT?Gl#Q1>h|l)Qdsx5T?2(M)R^`jT zqtAw96t!QkdHU!l*SA^Ld+wZ=;Mpf5`AFM5=9l**KW;9r^KXm_vJf2iMfh*AI-hB<>#Bt=NCMT*qnBD zp>w;&&bKG0EMKl}BI(?A{all>E)PFr0+p}3GcEhIeLaWbRw^D{Fq|Nnje zdSqne7KIfn-mE<~uh90}1poZE7I(j%*)rp2>6YJ|JHEYK^QMNO#_?79`t^IoMLw_p zm$$1U{TOfNq%YsP4~sWF7Y_b+*Gxy^Pr>hiG(Le}tu77BKmR7rTJrqWql;$7C(PDw z&1>Jb(cV{~ra~+B;nH0P&pRsUUS0T-G3m#(^Z$bD@;0t;{vOzP{P6U1jrQ?t^d8^R z67iaO^|v8I&^>*j{T=BJ0XL?#o^AN4^vXWyuyc1Mb7cO4DZgf34%?u4)y>9OeEFA` zRzZaiYs@%u%d#HxT&OuWL1Dtyt=D2gInFXED9%40b4pV5cCA-{!{eXwWdSpSR>w}* zE)aFKApCMsD>M6Ei7y}1kG;IOaNSOJeZ#jJd$RX+u9tj}&DS&YTKsz3;+JMNpPn3; zX2(7Ku=4WI-G5vUZ{Kxm!mL?*w(axtlUto8PM;ng6B85>!NJ?Uy*!zppMPzb_H^wd zNmuqfRCzr6@aB)a?C~iI9u5u;PEJmFdGGpUtrtABD179SnW?!pKyG&eqoe+fh0g8w z_E!J?`E%mS3n?0Gn%29;XRw<}E-_@D#dGIn+Me3q-~4o}3Ol=2nXOI~d}Swa)iiR+ ztjseGUVrcJSg*`)WB>d6l$$TIKfT)QDav?Qy;st%GiTPnpJ7+HlW%Nz`{j!2<^7&B z`O0saJlwmxaZhg0{u|F0EO)!`@$T2x?UP?e6c{emsm*=9(EIKBqstnLj-GFKcR!|g z<5#cY^D{Ho279?OVR&H&n=8}E(fT7Xy5;(Z~jfqcLy#m-kJPJ zY+26AQ+wy}&*EsDwWavOYo!^Nu1;iE`xsQUY0~^IllGN2_GNr*IHCW0&zwo0j0~R1 zL_EpJ%RRE@?0p}#$+5?mEa|b_otX4TzdByZ;Neu=+dMm;pMSb7sKa-`C7z1jjcg3p z_U&2{J^TCee8MV$I=+uxYx|i(~FM(eDmtb_&-%Io;D_@<=*AvIye6$*M&bz zk7eD^HW#<*d33CIZ>>~ycxY(c?pcvBEPve+3pe&p4_7ufH?ee8o6Om&^l3@vgoh7y zh3p7yiQ#4!DKVa`<~z$E@zBS|$NOb0Kb_X!f8nc}{PZtXwe#(2t;*kBSr;quW$qEd zB30Fj8+%*KoNG>STsYj$pL=&#uV4DoMVo4;*dIyW+45cb&WdNBzWsf(qC4zipk0>Z z$9=V7`X2=Y15ZuL?(|G?z4xF)Lta(G$H(UDhRI?)=O@po*z~Yk^VMDn$LB9*xGlRP z`}^iZ$%79AdqWqjcqf}Yf93+=JJH)SmrtH9WLmfC_S(zo`E$Hh|NK5t_Wb?3289v2 z+PN+6t}9uNcK-G=donBf;UCMdcHhR09O+`UOghbvkhC3EK zdwyLzEPg-bfPD(f$G5k)o9Empc;q7V$IH8=>y=;>@2d9I*Uje55>Yb`3*}T5O1}4g zbCs{}l9@sC7chVL+{$)X`uhxqtx>#d-ICuQi|gHU=gu8dskJeB;@wC6HYL8bW&ghD z%ue2O#Rcpw{BkcW>;8Vdes_0ydP>TLugm3I6D+H$s=mFsX>4V6>-zO@t*J$>$-$e> z`M6|FIQc+rlhEYA$jG0+-@EVo{cbmCoVsY?qD5hk*DwFDuP||;+|=@O>u;A#c-Hng zXmzOX>>t@%r9NFfeEITj!9VK_Yb+lA6EUqZN<94V(Gv!~>cbB&6i<-<*}tn>T>ssz zt*?K4e0-t!$@Axz7gZLtUtHoj*(~?gmzS59*Z%%?XHUqbhQ#10{MS=9$OxxJux*hv zH9dCb%$fOhza*#W>q=>Xh6VmrPSh1J$$E12#_owujbTBJ#|~Y-yjoD?o&Uv`C;o_N zHfG+P|BxYPJ=gVZ2lF33D8GDw|M&*b`B+b$JZWlTigMr;(pf36hELY2rM=x-Wzw#d z=KY6KCM>l-c}m-Dv7)(o{{4Nm)!*OgYHBWIb%D%<{1SZn^yS0Xw`Y7=?oiFh+rEAK z_T|&3@3x*be^G$OhoWb^5{6Ob%Ix>?d|zDH>FNi^DVKO>wNh5cQO9GyIXt=8t*Z!e;wv3R`&bt_Pw2*om+l@4{ckN zv?Sof-#<0BcO*k*`z`<8ly&9A<-@`6pDhc^e!#|`XTjh+Yiri?4U$%;WF_s^efs=) z^QKJ;9$FMUaPacts%bm8{FeP*J0Xr1C&k1mE-o%6xwk}aala6MZN}1nBIUs}9%i}z z#0NgdTDir|^Y6`>HqDK@yX)1zwQanrreE8|+x748JACM3j{dbnh3~DY^4+W`wM#d7 zh3DTDt}Z(Kz}EQo{=NNanpcH?cdf~O^nP{F$`i_G@7}$8`Es{O{(`pFR~86`eYL`hVwBt~z3?uV!UvHZ?UJI&{dY;ccxgdGXYRMUyWkI$FPo3A-(9rnu z@#D8oUqUpVeCXuce{XN~^~1uQJP!g^oAPH^oS5AI`oZ)5+bhl%@7T4gs=Av0AQOk? z^xA)aer`@bzij#P`@2fD)zz18*zh6$`ne?^J~`P&`p!1v<>TYylebiGQ91k>A z_EZX2_34CNko)_zC~j%c&)>g)|M>Ca*DteUpAN6G{w}xmFoW2=INo`&Nk@{6B<{)m zVLJQr;o<%A_H}=b^-6#Fws28ZM;NojnMsWDIWLn$I9gqAi~0W0;^gVci7d-I9CvcZ zLfb0l13K>%jF?}y@mRfSezjilhr-Un$6_Wj@7`6#%gcXpIe+rx`Sbf{v-7sM?{06O zEo~xW^`qoSv)fV@qq_RG!^`F}NAN3eEtIP{>}Xe!IPvj;^hCS7nT<{U`>tHM^7{IE zXKtq66O+w2owTM3*)#UKo}Q+=aB0KOmDgWyjanO_vuz{yw|58cMcb6LGgd6N`x zI?!U{$$NJSaICnz;FtHxO`C+a7CgC^`=s~TkwfuCMVlUOw$ax=fA;QOUQS8Atx>wu zwNs3mq{{c^@7ZxScyjiu2i1K4!e=Kgc~V|pp3!3S;Ce>~$B&*CPX%YrQ>RaNK5r0v zq865ymzSBD$t(8qRHKs0&fn(@{{<=CiJ$4iw!SNSMMHgUP0bXqr87cvZ%nk3IktGS zcmw;@$8NPzZYdJ09{L*?_siPvOFy4q{_akt%XJ4=*R^fBs-`bm_2dq``FQK2vjcPf zTy449ARY*ha;ZOO0fZ3Q9W@%!r@mz|T1zklpPjKJYS{r~g)y6+wOdZX}w zcu}w0;sA|@$)PGj6PKQqzYza<{<0LkX5Z}g-sca@OADS)O`3TA-@kum%Nz7xySj3) z1qTEisBLKK4`SYZYiXnCPoDMeEv&jt9qKEfxs+;+B*obvA0%{wWVnoY*sMZt?Po z)0g|L4`niGd;D(i?prZ0EK1(xy{pQxxRS-Ixc#BJp@|Itl@o#a+3vDTdsgcGS;n+4 zCN}nK#MZf|C7l!gU#*LGI=EIjv;Sfo!)?X+EU`(pA1){CD1LtKXt$>Nq)A3bMlaqv zxPCpcw#^}7!?GoO9Xyj#|Ln>9S!Cj(yuI@O&x?2G&AeKxXnfODPgPZ~^6-(3)vH!D z6daf{mH7jBwb(K-0}0Wq!mGQwx>jFb_x#D7Yp=G%&6AVr{dI5e?(d)8-#xpVo3}lV z|1O(U(SpF$Q>P`$ESczBa9`Q-)i&8Xo9Eo$koey6&Gd66lj3e)kbmo*eQld#?qglK z%;z0{O^X*BN^~Ebeb6f-(>(v)pZ))>%U%X?<(^!ysH$Xb03d)uT7R&5-a-rr%wP5>NSzgr%S8uOM zOg4RGAX(qHeM9E46)O!NhV@8Yi+hl|qrhG8*Vbb*W=^bpapB>XFI$?LoTNU4fTxIU z<#z7ap&`N*FQ30QjQK3ffy2sIvUvaW-{7-Jaa3SG(nAMf9LNOo_e zcl_$vt4CQ`Wh(Bi=#}_ERsGoy`N;)5&D{n&)V+2nG*{_*owwKc{one~f%B6l%vSmHXx_2oVL#o=F7ofJU358%`~Cg>H9x)5(w^PjU9KtH z+tt-36%tZ!zwpArix(FbE^eDQPws_jm)x5-Z)9X-PVN;=|1zkV!7Itl^_w-MnUfs1?6%t}{Wx=9F zzmg5xZ=5~5Ht;Z;pI@KG42OlyK5FiP9C9xUij=ko&ynG+e^YoS(SMr!(e7l)HYz*h^REt=gNHt<-XRm&@f3dQ7`2z7iz8|{V?<}7?w@2rEV|wYI|1xh4T3B@= zEo1%X1z(j^Pn4LiDtJ%l;KFvX&38|Go#x`=E-o&=5m3f>zl~7@{lC}A5ed&us9+?-j zdROPptSheHd0Tmo;8JZ(-JQki{fqaBh+Me3eZ`856^^c7|A(gBaC-LW&6{`c+LZYJ zELh`m=(vmr-xKq4XV<*`{|{$0%fC|CVx(z)OL3yd4%I{dmLk=S9AqH@ZhP0A>5LUXn5WXWYyx;&2@vOj<5 zZh@nI??Lt|#$~L|XZO9YSCBEBpV4`rGfe*Y{vFYZRfii|HFqemREvZNELqhie?%dW zmCy8qw@`7x|I({huTIriwqlLOp8vo1R{t!2cPDW5)h#yzz!|6ORX+zS*OSBuclW$= zZOs4LoB29h4%|MO!1l}iS%Ji1zNC$ZJx|mG{c+csCZK+JL;DShN{K}RZPKic`yCy; z4f|bN7PdrI9Guk~@WI@1$Bsh<=0|k4Jy^uPw{k}!kIs)3O!cc&3p@5L+x0Bb(=#*k z<>7Yz?yj!xuC9O$jo}4bLIq=G(KX{TXZ1AJg=g8w$&+C zDU}@)r2Z{*d9n9~!L5UTpM`xg=&*_LcC+j8i85k26w#9?aa@l`w<8 zPxv7@CYeu9EiQisZswvJ}`X96seF$)^)O{8{Cwb}9X(oRO+yi|Sz zAB(4pc;<)Eop0Yinw0-mBt`l>Djp`5kDVgzW9#OKpBJlYjr~Rfz zWnMx1X^rg`E-DWWES6r@$h)DjLbceaWz7R6 zo_DPE=0`sm=t`(%6*S9eOmRr(e!N&Ii#KwQuzuCT(A8JHrh2Um2@7AmqUq17RZfoV zwk9EvQ2Z6&ZQ0{pr#SI|)2UX8wv|iEf{GTmK4iD%`5yG)O(3WFrGrxQl^(w9Ck3TeKKd0(-L_IWHsrT$R<@!QRx| zuKM-n9`)iL4+)`!_2>5&|NQZDjr#o)-tSy3sUt@6sq;j~QEjD#q_GOU<2d!F#IN`o{;Hr_Fx#_iO+A z@~@K$;yydEZM$Eqda=&^xZUcD>G^MW+fDF1mtnZY^%Z;I;p@t$kLdgFmn;0gY~R}Q zTlUKB>mTcO?a7pFpVx5UeBG`4%|AcN-(8-@bmZ*){}(mv^Q50zx~CsGFH@_tclVcw z|8kcDZfvQDKlQ-vIp6({d5;e*s{N9G*JSxKc2GGCssp=T?eyf{m7RZ-f3L$mjiltc z+B2t%*IhaN?!uav)eCmMWBC%#_v)~B_4(b8gx)RNUBI~HaQxd>YwuesSG?>$@Z$-MsT}Eu7qOrSED(_U-A9 z6aOl{kiEN-@j$H`x8B>huJmiNNu8}bpPyjZ^6L7&iF^u6@>%|Twz2$gAlcpgd*!ma zoh3!{(d?>CDqV7&0|uKos^7%<;GuU&CQB8Tw7qPS^f6Kq=g|N_5Ph1q5*+_ zb(bE?uCtWRYmBp~`}3n!-g`^b1v`s*h5vqh^ggnty5g(d?1_bqcfMY@z9@dvfxL|` z_>H9Y^i9nu?RodG(`WJYnKz=?B8>IV>C`B?Uf0?5pe0b@-RJ&qeN`!f-hmQAa}0!z ztpD;<=c>*TRo5y8t)%8W{o@JYAr))CnQ^n*{oL7-sP)Ns>+a=s)0t)6-g(9eoqqOq z?zWp8t=|P7Kl#$8FM9R=kri$^e-iTfXTGd`xtA&9$?+LtQy|9`&EW9{4}W~nzXnCrj!dHvzT z#9Fr6nstvi)}O7e4d0cSa;S=v_ws|2@9OL3U->DzP&~5xu+6)`P~%PCY?t?}&O09+ zvMTGE-j?TA3a>7VnX9;b`mP_LvA2IMu1VQ19m~t9@?Y&Ydih zV*iTs-z;CxWd=f@7ZmdP{`^0%5L(FKl{XIZFiPFe&yQ5%AD+t=YD$LdMIz} zZhLV1C(nJXX8V2pFUcoc=-N-4e=*;A&QCC_vXxHF z%lNF*xbN+s<`-t(KXz1Yi(D=C_vPfdH*>!1WWBKA-R5boD+Enbp6xleu4-=L3lXh# zG1s@hf3fWO{E6wR0hM3bZtrVeeK2V*+tbLpr&cXxC87~p>+U2tTkn{)JkeRVXxo|P zk5-kQGe2M?&&?fOr+W2_QtD~_`zxxWw|#%TsdDDh6#X^d=H}kt*!OqS#`o8L-nhq| za`5MdLsfh)UmUx(RrmF;l?s`!Y~swa&m2m6ntHkD<}Z!=4OZXhPTe3X7Onm}uX2yv z^}3vG)3{D2cSScvp5BtU(e9L4R&zz`u2&^B{odR1t_tPZ?BmmqzusO}VlJ2Z+DQ5I z(P(!6xD6K%Z!(*a8OA?r+ElTp*NraS`kngY?ppI-<-7J}{Jo;McUn#PlAGCk|Cipo z(0hGpbn)+UugEQRrzXrhvHEBBUPm3HZ@;n|f9J%#$9pel1)sl{Ev+Zo zt-b!wCxuPdBT_uAXUngdu<6Z}4Ps}$`o7oA6u6e3b%jOn$p)!}=&w@7=K{laCV!F0 zlP^`j|I`0lgUfE`_kVu0T=x!aPTM2+Z^!4h%IuA$*H-QLr6Ts)_`u_H?fpN@BDYNI zQny$?$?V#}E3XQyxBL)`sGYucpRd`rbK9TqI`6S9>Y3=Bs4+`}$K#mae$6$Yjlix{#>y?m1^aE1ITF^KVVH zojl8YedukmrIE7JmZ#pfhzm2#50hJ`s?ln>`9#uGwbNPq&)n`WmD0R!wDp<$@ucV# zXVSJF%)Ps3-p!(Jp-*4elwHsKDZJur)wV$UC$p1o9@`@3&OZI-qP4SfWlyc2cI!=I z*nnEGA*)8_w=#6n`XbCH$VQ>C-r0f=iNUSJT3fd`R!NQH~;oy zNBgCIxTbwv(4p4Go8|rPUc1|*Kf>-^)%)*F*;$}-b#1PALdm6SdpXT_ri(RWY^o0H zT6C34h~MN`@bJ#&{SDH$Ql4x%Aajhb7IL-;h%l>v*+2gwXXwG zW6w9u$(?icWaOb=Yu0Uf6|CcxQCh;2F0?k1Q~t8Ke<>`t4^)5*_!q@b7v*z&iu)x(wlWYU)^Mt zzhJ|>xZb@sF3WBl*}B3fH?Q#LUKiyp9tXdcPdRq`%<3Ii&Ul~NB{DTjM%KZ!j1Q{9H%*;( zoauQ^n0?R&tGF<+p!P7`g&|iXb}To`x>~hArt6f>XU%Oo{jK8Nd%ezNPpz0KD|_wL ziw)P}!hXAMySifK@)ISgX*UnaUko#ScKi|NEya&nNfZ4$Q!BaVrL{FFd^_MQCuDw< zTkxKdy2feiy3S6?MFnSWRDCc?`M-`u;OZ4SB{#!hhc_2Ej(^c**Kgi!F z(H-r5=?}8E)w^U@zMOhr(ML!3*Q3+22NSQ}U$%k!g6Qp5`7`F%FL_Zh zHS$|?So*(JNzum-ZE}sA>soJ~&8btr&Ny3o-L&WFvvu!$>Iuo*Y`^tgr_Q-8(=0dZ z{q&i;@Yq__WVQ>OIw2wT%!W&x&8JJTY}SYfW1V!5d*7Sh`x@WRz4#J*3)tajc=gH!njx!$mvO8)n=D~WkN{c`@HHCMJozIfc#{dw9w z`Rn~#i`!yPr@cAUzhRRDlU~ZrojJ$+QX(6=w0L$BtyTNyKYAwr zFJns0>sR`pQr`tk+n9RY-~W;5f)|pvE_w6uZ+~O;<;m?&{Qa*loVtBSd&Bz$--=e; z{A%*^593ijsjJ6)Y9Ft$4Rc8{R^oTcsax^RM5@Aa(0AD`FAxbVPicbVKGQAH8OzAA4J@SD`#yHS5x|1Q=kmG670t;T9qC=zgX?qm7dq6v$3u2`{R#lNbX z2@6hr&EUoGN4Gw?yj)!pTL!ncPX_+WPO_Jfzjd6W12UAcE&b6U>LeJN!&xz1vr zUVibKA6I+p=e7^Imv3$F?Z17-;eGalTG9U|{}?6e^`;g-PCh$(#~D=+Nt_1@Rb z{;_P+OYxYHi#rTAt{oj6# z@4vX{zPvnN^>Y73xhK4&6br9>oU2gYP%Z25E9!iYrWllA@69>&kCoqH@giU94htL%eTCY@#M|ar)Kl7h~#+M@){n=b~zq&WpP2= z<3;jYN2E4W6 zwWqJ1e`(wOmq97*twnj-^YHugoTgnV-hKS{(c0o)x60qE74!)Pm&e%bZ+ugGg)PMX zxp|B5?!SMYu$^4;;=!!TwTjBQMl8d&3ngJ1=*@%J*AS4x4S1^pQ&|^ zDNSt85s~gkJb%QFOE#G<&$2%g@cfrmnX%Zy)|McLl`B@Pc$K?CQ07}wg|vCX-NTC( z?=F9T$u2@qa!1+G34D?F_uMNxBBoaHVbadJMRLiHtWE5GA8mN>U}N@n*|W?U(%%*x z60dG`Kd!L;LPE8k`C6}~LDvdmoeI)-F8W&gMM)>>?qAo`-wG4d*!1M5%-hQAbnJ(t zg3e6dM=#PozI{LMztF9=in<@Vca-BE=Du4Tr@V&!8yD}ko#Jcx_RW4-xIX2V!}F!_ zW9QrlI{!Gp@Nv1qGtM_47uNOy` z)Gb|Ov3O>6v`5ShJx!(87k(R5ZJnR2{)DwJ=-5%&U0cum{T?(wN&JQNocnP{*8H`# z$*VW|Vl4CY!7t9EUyX~nS$N~DuHTPLd;du8(%P?Yw|ei>E#rJ=9aXNi_nLiOhR(a+ zOvig)97vn@aGJvft-!w@x}Ce{%yISeyW`Ms<8I@|;*>XUROJ-Qbl;2U-qb7OER&La zzTv}y{v+y6lO@a<*eP>@r;=(JZG10x8C%!*>xtv zOyS=`>t{vUws9ror5``uDs{ic=I6PMkqfJj#mtsvj+u3%Tty}QhUC2WhZ<&EzxX`0 z)hhFdif_@0!@mEUcp7?6me&=Y?9|eC4Sl(XB%DkHG5a%|bOWG4tPuBHX zF+Y3ErJLgPQAN$RfnmcEj z^S`^j@p%PbO8vK>-!rZKpKO0&R&cib`E{OSJ;$G&`?g@}t}8n?rup%_IB;`{;XA=i zmlez>+y0P!W6PN1cFtSYrfhD`#YNm}ZZfYHE;Q0-KVx68$~gVX;}epv|M7XR6zSB%u$z*{Yt4)-A%ANj~PFVi@lVEW|Tj%TL=Ij4u zZcAuPX{($twQBB_^XF>Si#ASQrZoS%($U>p-ej2F-uZvl)Ag>7_co?Jm%r%zS$6qi zk5h?@A})k|nx7?k_~`CScY^-AY>04rCI0LGZ>7qI78>u`@1H()YU0|1IR)~84RI%y ze|Whn{E4W_HaD^9D$S{>aR(1vd(ry2z;5}b&;T>nP{Z&U=0CNsH~tiRd4Nq+R5bK2 zuW8*mO@>bQ0v3b1y+V(o?rLi=7Ni>6)jsYu-!?~knt4ILN6d~SzTG9a8a_Oz7i%c? z$PoBsHFGk5(szYs@spY_)~@HP+x{`P-uc}AJJ%W|nnVx$s6KZ5z+R_IJC_~a!@4#4 zeDz6b2bZMNqMPgEtseI+s$K2W@a@U0|5s#fyF_j!t!MjaX!h;lpM|%$#M)|m)2n~D zn@fo>?~D}c)c4_b&|90_6jXoyP$IAMyL*!h8aKYUvvbE11#hLV&-XrR3hpjG!CSwv zGp@Dx#h#>~C8s<2)zYQ5)vez!CH1bvy1H{>CvEPYtY}%e`tcp{T)V}&a`)G-eevX5 zy|f+YlUK+4-!F*tEM{G0a^BW^CwFa4y+hKq*dj6YJ$%iu9-K4-R3s@d(TrgUL*Va^+MlOnb!9_31qK7!}=l6 zWy{Cy!HecijE;2NyYP6Y@SZ?I=?DHS3LBEBfC`Z-nP)s&XOr#9^IO=$oPcz&vPki?%jJE zX7aB&Ct{Kj@#D+k#zkv-FPF_)_4?ZN!{#o3O^$`whvzTK&G2at}0{1C|#4r<)1E-z2~5b$2QdW&m$#5MM>CoF_6akWR?IAyu|$=hot zcV~C0dx*``oIfwdfA-XAhG9~x4QIPDUWj-$J$M`cl=ms&i@Nltwwjm7e`|>C zb6RavYZ~&NwUTF}&STxs-#<8(DaxHcPwSg8Hk7?%`c?LXno`k*^ahcnIn zbtEhcp0sc(vwyF+^w6|*b&0|+LsyPP1>!GPr%gMqWmb5lrBj(rb>HXYs9OhB4ZlSD zfSQN$F3-;g+P+pOy*AC?O{#P8^Jm{?6#TKgd$!|N!KcsX@~Uj}u1;a{a>WBe{av4D z{gGtlmAaC4eO;ht_u41?sMda*cyw~D2PjjK_l>*YJAw%7j={>kJ1)1YjV*PQbo zpU3N-wcdASdHCn1IVGyu{Gp=njG6bk-#;Y(fW2g42HOUUF9mruXL=Jqy*pm$*DLiu zK|Qmo|7w?H+u8RlGv54a7KwCFcbj)YiR*j*F1^D)o_zcpslffcTz*=kJZIX%XG~N4 z3chDPzJ4rnJxlffYrdPa|2aGJYH4Y$s*=h|aLdkUHU3<}t+%UMas8)V*T4K(oD%-# zY0P;oKas!xb`+G|?@4zn)17~3vrN;Tb?*}Y%S@Vbdil$#ch^LHnSOZNz z<$9*I-n_>r*Gc;?mp-}fP6vZ`3fE?fzSmzv`p@PUiha~RJ!{_nm$k}gU%Rb3JZIer zrP;qKFMC_`UcdTz4(n6q`nz2-C7vlwm1_12JG|ZS?Yup=OzQjIyfT;(-*R=H@@}n< z(mO40iq3oz>nmnAStP-D%ALO=%2`Xxa@(}F_fBqjqqXdQ4md8Qv$pWQUzhQi>%hd= z-DMfC6+EAuT>926FR`gjXYOnLE;;G@3qM-+z1j8mMeLdQT1UkP2ivwyE#8^QvGa;U zSt&<;Y)4$n_ki+xM&qcrLd{`3r%v2sQ%tT^mrkee3N;gXFio zDdD2eQ@z*ntvyw;KiueT==0QglSe1lb*(wf=JtA@D}U@A&YPy!mlx09#4dC5YV7m7 zyVO*dyGm@UsNT|iq*c+A>rk_6oa{t#i<_M>HVdM=@6_vm)+}qS?|HD@{lvPR@-t7Y zlkG{lu3G$e&JwmwuOGd2)pPt`;ahFxEIGlTr$yW`d9st@>u|mWi&ln8om_X!knvbU z{zJ=k*^|1$|0}$o^JIqxUxLr$tLw8qeHY`A2>x``EH`lLisMD+J@r=wZNEGJqp8On z7eBrlv!HrkBw>PZ9~(t&5bv`woPTr7yLPU zQ_cpdNEwSws|}_&S!eH4TWQ(W3L2Amwf?g5iFJ=xr+<|=cDDD$PL9dmcSVHDG-c)l znml}Xc4Dludj8G3@7mA)H<=KdE`P&%-Ki7Jsz%Dw>ui3SsqN;HSX;<#c=M{MOj(=w zt_>}3s`w|zE>_E&bldjM9xE+MeP4Ga7S*N9kg7cUd@obG>z$@x3z6#gtT#^G%eB0bRKCxoxO-ifRHx7u8EXfRvcEs?eaTxl)!IHTJ=Xr1$KfBh6!%QE zDxO`XeY~)@xaZZPxi=>!zO$G3VD>9yW?>&sbN)7|VX-)U>&@%=zfZJP zE>L88e>zDZb#?KAGahAkIUXGo^5@=^oiy)yo`wwjuWnI(A#ICm*_UHyd_DDar8aZz z+CKH&TxN%}T2jKTZqMxM>RKh&pT+QO{VB)v=Z83|d)X~##LPN2Id-$%(Uj|tzeklw z@2HaZFUx(V!Mt|MJ4w-dehMnPiw>n+*ZF(!?}qm(?qy%^d<{M=b~oW`-n=)bDlKjE z{8Rd0#9fIxlQGpm=Xl}SokxmeB&VhCO^a{gvRub5JL80`)ZCT>Hw>ho%5BUtNy?j% z@aUK1+12&)k`;CfDZ7^){kr+Pi=KPRS@k%#O|LiRnB_32?cP-BK7C$&ig<1vGwa?b zmh0}Q?*8h~x@6*BGyAD~at?U-PCONVRyx^tuWk41Z{J&sMD#?ytGj3Q$kg6T;HxM| zxqh5=B8*V zr=&r?o!ahOl}$+r-J+Y{>(8u<7QD2op>@Ky8?Qw^J*wQ$ue4iBJ3``@sM>C}BPP#I zuB$V+dLTph)V5tW($?zLMLLyzeY!WPIWIv@=fTmfy$g!2)FyArp7I&gz?Jy(iOW0i zFN1%X?zYbbhr9xOD%5~m+&J&t5?6uAAumq;sOkmyPVzDmx&26uc zo7<=SKELV0ky_h#nMW@+A2nRN)m1cTzFtp!%kg=Y7DkssX7a6F{5SscG6U9L!!|1= z>pcM$YP+S5?VeM$YU|N}Z@s}M#WwD{b@!vI!1o81>n5ypt@|Z4nRRk(WX?mrnI=qc zcP!q~ej{S*qJo{5FNIA@3Fn%)9MqCB-}I5COLB4P^%ZsAZfp8Yly}Dkv3-#@Uh`if z?}EZ%kFvcsFZZ65zN{uJr=z%gTSv#IuamE^F%)QPuh=#%M((+B>fgJXEf;UqN1i(7 zasOg|O5!H%=z?6~m>|oq^}K97ZsJdOE@(T?H%V7v{l>G)*PM5bd%2rok2LF!kd;5| ze7RO_^1rq;c~f@KuYIq7{FFhdm99!Z$_xb!vVkF0v?go||%A`^QPYxzpZfM~1ooa=AON z_j&r>8&fUSRdy$RTD#?%$3E9fs}H=K8rpZaUCfPV?VR0Sa+{82>&tDqATmdD{x&hO&KPqZwnHqYQ*pYe%FHSX+>O{*l9Pybmn?|%nd#*Qe} z>J;Cyujh5|vu~ZhaK(yM%X}vU`>eECH1T%8p+eE;8%5-#CSy_dxfzpV3p+eOZM@L^OFMdd1s&WucbY^M{FTj^{6#f2Ysw6sXTYgF7K-F1=n}{ zY`>f*_x$9#<|><)AEeZF@0vL=c5TG^{?IoI0)^EiPOjSsZ?nEn54KHqJ$LWd$qoTS zxfX%VPt%`&n^Ez|GS@Qe@JanccfO=tYkPKV+jY&GQ$bY%F1$+a)&J8myoDu;FV1s) zU1p#8tK*299e>v(e=gnLTDd=ZTOzy-Hw1RKyFSZgV(0x-8|JZXe=F0Y^uF%T)0#vM z@MY!Ie7lw|c|P;>lsBM8a;SXjXL7j2S%+!9@-yD!`>Cwr*PPob z`OHV>-##yQ(Ko%XzUxcvaZBHdlb4M4eNW!=%eP?Lhglm_k3YKk@&Ec+Q~Z~Q|N8Rk z^11D;>+_}WUppI{+PD9g!SAMZyw20nkK~7)<*wo`|?uszV@Z*b$h|XkF88(cl+x1MhP5u-EVI<=dO9}rT?qdj&72=5L<0r_rle=;{n5)gFzL}nw$cg7pU-e zc%&|zlr^o9rP^bCEBDic-ItPDhxcuVQs$C-; zCs^_^HX(M-^j%@^K3G_{sPATb>v=PK`7;0Tz`(%3tEU5b=UqHir6S<=x@E^ShZF0j zU&>pybm`n%XD7xshvnHHoE&>T|LKW!iw^}BJes+oV&cWq9%WD43=I}W;%v#V$}e^s{1?qf>p{Zd~v|0w6+H#_z%@59fS=Nud7#mjxPC_7;I*6QJo zxaTX@TFvFVcmJBy(w*OodpI8K)sxz@qt#aF*jCH3bDWVv(a*K6&N(`L`<6$#715f< za%V1;yrJc;$zf_2c`v;3Z8r1YuhG(9uIKwtw7O$_aQ}1j+sZZSZvDhrFO)ZtX46U~GiSzzkU~zcHcV@A&sp0QJ zcDJ4KW!4tjWnc*!-v?OUfWJF{*=|c_fTheyMpxZgj4Bjq&)VE-+|4EveNfxC_*&hKMaP)i_@3`I>J(==bjdQ~^}g)%l+(qlp7nmT2!5iw z(OGQ&R^v@6H$y)kubQWKOzfQY?`RIm=IyQ-Tk5jo&rh0clHRpgtpmJu$? zs|y~XT)O7OI$_S6rA}KXUXpEuPx z-x_TnuTCqKS9`GjmfG%fos4?VZY0|Cw9i$3dMlsa z{;qDV-lo^xjY6E<@3?MA&g<7(7JGL=RM70bvc)mCB`wzJ1@ZVr3o)N8IKDeSA?bOv z{;H+N*6ub6c*(Z@h{YmV8CxFF^(tG=Y?tiT;nU;k@pGEi{`Pdu?Bd%@1>DWC4_Py! zSDdL`BpdKB-rMPD^^JWZ)q=dyM(50{ua{{5(q89Wem*TgFLlPA(22_1He4w3srRY> zd&Z^y?W>@Tj~{=Hk?rd@zN)y|sB~?Nd$(hePn@F&+my^>39}?09;{n@uc>mwDd;fq zjpE$kZ65idRy&qYw|KE7wZi6*;h}ZE+$8s~`qZ1x&}h>CYQ`k?I%dMs82;}iJXSMO z8O|-cdYcv9k-oR>F*LME~JLTt3 z`+TR>sMM?e`t~aC!y%&?^LzG4JbC)(#ZIXi<)<9Vw61vE{9>}B_|i`Qrda{erfz+! zxsI&bt#QtwDD&=@x{H=|6}H;ESxbL?33>L-bK7U1so%`R*(%vgwXff8Ij5+VyKZKy zV!_onCR=pxt_|6u`@$x;caMj}6@?Sh%Nd>OzpniGRNlL9c2#^xd*=1*B`f&!@7PV` zeW;VYWPes+;*I;$WKYZ8$v-gbsc2x%y@#pWUaViUlDpKv@N((YKg+G0&GR`tBXVmq zlGlhlaFWz9^qIz4FwHD!mGsVombUv$#h!A-Pn%?DP@Jdxc}2|>nJ>8ossW2-hRIe%X~t-5^L)YzY`&rdZS^nS-V{qmAY zVFq>%ds3pC{rHY*MC_~)jz0Etw$691g8#>)PUSpj+`rVbU>3v2N4atuy>6^N&!Y|K{cMF_!tI^kYiF)w z;P`T9^OP^Ar&@dx+`No$TH+K*SEK*;d>Eb`JayYEWTyH5UlGi$OieS)4l)|Qu+yEM zvwoBJ<q;6j9DTMfJO8tN zllksw-+kBnJg$D@>=$p;g#S*xvd{%Q=zHpNdcp~T_tMo{UCSdrFczdu?D;ui-S(_^ z)!!7eXT9@u{k>M#BG}IMr+!9Q)MiGmxi>AEZBF^kjAoXf{y6Er_)fjjAk|$vb&6Ly zOcY+HEx#j-wRyE8=Y`X}RgG+^rHi@P!kDdI?2TP$o)M7tTaL***@zzH_Le9 zF+00m;8*sS%a`H}Wv}=A`{g1N9&K~uxr$Gjul2uYD~<&EJD1g(%{H45+aJ718(e)0 z%BC%=I@UF3@7KqIZ%-7=WYIcz?ycR!AH}zdt{j`c@5P%_6Jxht-+orY^W-|vyaG=A z)&GD0iFL_RBDH^y_$Nmc$IPGb=GLYq8P_=%>SkP6V0OOijn+HkQ+fwxhOQ2A-=FrM zML$&N|Ew$LCth6UKu+@FunU*L#bKWn$T z-J&(&pc12Mp?cz$TQ3sY_HX}v`*;N_&wu5fYX=1P)z5n)wcW<#>x^S%P#+%RFC{lg0am zwj{TIlePMBc%kg-N9nB}0;E4}u4U}Jy^N*k%&aZ13lc2P+!dQpCHPC=`}Xf_vG=@ukbUmyE5VvCkHuOfj4gM|+n1?u@mpnYSm3ME)p+A)?oOMF@Bcrz8n)Q($G6|| ze6qjZT__A$()`}-a=y8!sOZ(t(|b!z=e1nS(k*}QcTo1!T=~gu22t~k(#_weJCw10 zy*w#a*K(bdsLi}LtBf8W>{@iahdcTExr(%u>z_{Ao>n~Z`jy;XuP@6#bAH*iYx-aP z2mY3uUPrra(mt@Te)qaN_buXPP5i+XmlG%Q?)SkZ(Ysz>D3dVwr*|<=G_d%qLVM@w zhaa3KY+B>N#QDDBdq!RE;fNpRufKn8J5xUGu=~}D>C?Bg-#S@$S}k?oMus*Sc1iB` zX@{FcDtD~@b%?cgjnkQ>jWZj)kKOt8?d)df%4^vV-ep&(W(od16bzc?u8*8olYIQV ztf$1b13`E={D)9`foj+ z4Jy0)R8y{toGDxz`f-~4d23;BzI4O;(-h8@dgNsKmBn5QpStOsL)qPPR~6ll_s&Rl zE0cYn?pkJ>ue5vFylDLhrNxr_#a0=LM3*0W?WXnX4N(=tvUJAT zR);-QQ>%Jj-d_0fraqg%rq>s%XWY6aJ302Ct&J61WogFgg$E;j*LHeI-MMME$24)v zw*x)bzBwxR^2AK^xUnj^#y92qxAOC~jJeKIYyOIT>YUzG(fT#udxcxzdzUYpME^?Z*+-RrvS^t9x@*B0lE z`7JiBe&24q`RyjHjZ1e(s_j;rmD~OKmq2x>)XViXI}Ebx`OjN3ZOUfv>(l0vYkGCz zW}ouzXX|43>^)(*;(dlwS+D%5$+45IHq3O}v^r|-D$z+nt-t*&*7fmU=h3fw&;I+I zXUk)&T_Ls@UZfsi2ne6#m{`@|Nh<@)87r+l`z+@yWHdF{-r$uAb4Tvu*zv-Hf? zn;UHwo8~Q?xHjs<#MrMtS25|jm(^}~dEe&d)W-*<_O7{V>(O;`or-+=6n@3s&vM%1 zZ(FuXoLpBnCCuIp_s zmDFP*H<{9do`omL%&C;q@vm3)iZZ*Wf83*t_sNNM!jnZc47*NMP9yCag9o`^ zR%!`5-;TLnd-B>G$k6c>OX*+9ZK?mWFE_2-UE2M@ndd1(vDnX^%=z=?@m!Bs8NoUK zJ#XaHiluMgdhK1>-I&x}mayeo;I!SvI%y9&Jwk%RxPET6^5i{t!BygEhHDz*xq9sl zpw{=Is#Afy2U5Z%L5nf0I@xcoyk2a4neW~0jo(3wF@6R8zFt1>ME=d(2eWF$ukqyZ z$nb}0udQC^W~|OuvTUc+k1OXBHf86v{d-V%qg*J$r|j#U(oL@2c^lIB*Z3Vdxo57! zi`3Uzvz|&)@gNy4@f4?bz~hSNxQt@mJHAevH0f zEMv9RyeLMRrD}R6;~}T3vt*dJZjIb|E#TdokP~NJ;?CR?zOZv|!@pOt>y+odIr8=L z?CXDwPJ5Ic{jr|ivPSmZo#s~pxv>sqM|Z|Wm6@vPFkexjBH%&O__`g_9h*eW|Gh36+6; zeycJ{qgS__`TdTM_ve>$@7Ani@nSHa_b^dzr_P>VeVRf0ws0-;4fCDl{O%k_nXlG$ z&okP+>w3LGGrI9kz4ME?9p1>DF^qZ~^;C2k!wyFGGTU&S{0Dv~)}6VO$!u^_bdHk~ z=gqHXYP*xNR>$i|$NE2& zs@TA|?c}40Zc0wW>r)J+X$>dW#m!Ag4fl7fQ{1;F-RQ^K)6xQc z+1_UgpGvH?;*If|d}HgeE7w$S+iYx|5WCT6XRhhfy$1YYNlW${%?*#35c`?StHJa_ z;d#ML+FCPPQqSn$7tgg?``Pn_xQ>;k!tQ-PpEkZX+w(NvEagDQT$vvl%9|se-H#Sw zcwp@+rxTcdH%QKcJtz44*W!;i9M1?8`edJdFM3HVR^q?Md0Xxaa+_aeIof^uzqBp& z;%aLz-(pR_c`Is999olq;dGR)wha5p|E~fR*6|zO@euZoJ}h%5gsJM+{WJUBvOIat zD%2lc_HD(X>-~?-AFopgnVT_j|3ahL+Hcf!_+PxAT=%lWweiIY(2|*}@d~q3t~0y2 zWglA?_;*^*4S~|4o(XTFvfax5zOmkOttIXCzte1>Hv7LB+!qe1-7G!zYj-eD%5~nr z87F3$@s~2qI8hb&^h&+SmwMh(o}DkE{ua-B6Q%SeX^-^J-65+Y-q|&Xggmvm`L*}V zmC6<7njSZKqSnrq3+dszubjYnbLz!cPvd?VdQ96p_0;6p_4z$Um9e*3=1W_wn{ly9 zd~)o5`$aXfk!8Z0UdQ_6?%g`C;_O+IOBwd|tLEIB{rup+Y0uy0P5=M$R^y^Gy-u65 ze_3@~Jvp(?irHn}oofzlccsto|CbbgapzgJP1&DMXxQ7YJSBf%hZXDUq&abMPjA#_ zBp$hN%JTiK_C5DY{IzZc=RTadDRXx~)1~|-TeqIF9fnd*<0sl|&bqI8e8rDt)z`DR z*ROid=CNnb*-tMG*8~_oku=v{t9hwoj_jtoFQw~#th}z6YRwZnb!W-s|Ff?X9Tx2hfU(fGrz6gascI|;1qV_d-w50%e-bciyj}5tAUD~o#!+T&e!5e+^eRx z@3V5+-eVWun}Qpi;(O06t~w?(A@=BuH@A`>ecb=%SgYjgugA7YDr>yPJLdgr{k8vx zVt8HWx9PLkgseQW^0!*uM7l zW}n-fv5(ka$xbPq7?Lb}ckjY4{u4r)m#v>8^5VqAkgMf=^?yz}dIc>7mGYZ})OOc_ z#=pZkBsN<8ER1VZHn?f}XXWY3YL(ToDc4`d|A^n$BEQ6D!yo^*Kfav*s~3Odr%X)Z z=c_LMDyfyHsJ8N7#gE<2?Hrz^WgPBSuJ)PNAKo_i6fre@!L)Hn)Wnecw}ekj z4%z?QbJg{}N4NUs-tSZ2wCuo5<{L^}{8s4)R(w*q%9`6N{m5h0`+W0>A^dy2=l=k2 zY2CE+#83CjmnJ3uJd+71z&$kx|yh#dmUH6}g+}O&{F7@K*E0=^n zPrC|gY?8#c9G_sx#&(|1i0RSJhrPC%=KOk{OYf_JrX00SyK+A|c3xKS84r(t*<69^ zLOBy+n{`gCD-^zWASL{R#|D+%%a+f*f8cA=#$?W$Qycd&ZCWiFeKoap;+v{A<=tjd z2Pem-p2)tV{8)s&^JmnA{B@t7ezM%yx!vQ}56}wj^gBkgMKZhYzx0-1m|Y}lcK%t= zP4C>JCiB-E=()DN((U#3XFb>Q&(FR2b8F{CsqbfBX8%4Txpv9v-bWVOV{&hR2CvWL z8m;=++0DnjD8+cY>A%$W-`nQz&0Avjv((&qRrB&~asH*|0nxc0tO{Erg!b);(oQQm zaM!c5v-AVQyd|sr^^dEBy0vJnE@k?X_+ipRo@UQgw_<*XtF26{oiBJrX^PJMmF+Rb zleCPICS|pKI^^n{yZOU}*17+8&731F@oUjW2D_wbOIH_zm*?K(Fl{=#Tf3$=<@&mX z2fwv=NzHOyvBc-Xgr&uQT`n#bwlWc%6x)0_PGnN7GjB@x+MuOt);|38?t#JY57$~> zxJH&;&uj z$oA_8W?cPuZf>Hy+}n)Og3x8@btkuk&z)X-@kNwjM>12m@2QacE9Ti9Uhcs2uCHz0 zWv{fJYmNVp&57P;#-=~>^>dx#ft@YG6Y0&D5pvK3OtQ?-L zm*HxCe5YuuB4~WNFh)FmV>@&5^Ak5LJ8Yd&*1i+d{~7i~=!uEew8h)(B8>M`eC7W( zchVfOuWOQ@>oTbnPg*6Gr8rl0u^?Bqh|VdMs#LxwjU}&)0<;UGe1deJT@IgSWaAmy z#C|1ATJ`tf+b3=_EW=$^i;8tDT)iy-H1pD!yXo~C=IZ0&(voXs zZeBg>qMEyGfA#W!(=NWZHtoL4Kif_rnT;YqQrAwkMFOZ|90oVn2|)Hi9D zci@Xd3ENiL#fPq#?B;hxWqb98N?rf5zlC8h@}7vEuC_Hh=kQ8w*~OGYHg~Mk-n^Ed zAyTQGG;K5gf$H_(Fc{y3+QHZDnJNfDeoLv*&Rz^}KUl5!E#?UZnL$&96XX>`8K(Mzenwfpaxx$5t> z!j>fGG0EHvO@5cED%}&t793P;RKmXha89V1^7Ey9^G@1t&$-DP_P))u<;^SCJu>o} zm6vSZcJ=bgtx3u3TEZ$Ha#mawE!ZxR(x)`_;OvbOiZgc9we>e#^kSO$=*^bbmNL)9 zuCgub4-qMtAbzMcRbSV3*4eUm`_qoT&@0%^=ccXBK4F8*9I-7^|Ad*?)c3He=3l(F z_xm(ujx5GMU(=?sykTgylvkOW`YN@iMDw`H)tI@lF0ZX;MV;95KJ9*k|NAG)u1|B& z%#yb9;3__!+92?B=dbJjNJi9)dlOe-6Qcfo@_1>D|kmGOGE)>%P#WkVvcWX3$jktH6bA-)1xKxBW72kD+ev|Mukgj2Zj#j{MrJdhzqeEyrtD zFLyVc?wtJpU-CcSG`DjfgHmN~`JY&KB>U8{Emz)O>w9@DR^hjc%dcPVWgG@E_mehd zcb^TxXmuKju~eeU+p4>8yp^S60Q;{Bn3z>2UGHGfRFy@gF`ndt-`bi5=SX zQe(l%it^p|uhhOTJ#de|yRD@4{P&k$sT(YIu3G+h?di(1clP`cV0e1D>4`A!hnKg) zk4DaJ?YR~m-+!ZEoyxHQ>DZblH&$JiD*V9a_PXt}YLbTS?xROCzIJwe`rQBGz}E|> zg3}qIDr4^}7iufmZsP9S)iYVPKrQF#o$ptE`p$ai`Sq5)Z}gAspI_Y9mnZrKxr*Lc zU#ix{9~Ar{Sn*ePq_^46)3=>pO)V1HxFExMZR$?P_GWJHyj6E3WUB%{1ShWExMI@x zCDkH_9+i8%|Gn}4M~iI@-q zX?Ti;-reL_X1aJ1TVls*(VL==<9tm5Z>NO2ZfO=U>e5_U+maI+&bljO-Rw72Z0Cv! zu3w(<=GTf=s}0?%%dV;}>v!(S?B$cb61I@7S0=OAmY?ly_#yd(Eyq+{II$;m)uJDz;S$Hr;qH>KK~LY&VN3e52{@4RAv*L^h)v92GFpwsA#R* zgL((S&D&~>jE=Yjy|w%JBR)*bc+#t{xyEimle9$ffvG$Hi9gGd=v=e%_?G%vZ+<( zBDJ{p>b6B&16<{|FZrM}Q}&5T<7Dpt6|oO$4t1pz)%pcn{Oo(W+<4oY86pMmB3q^W zJ|31mWGgvy%_dL3r`Gi~a?6wFKjh=`pXd{I(PaCiOe{WZ$ zUjNe$I`Jwb<=tZ_diB%Ko8m)hm`^!=<8>!K?+WzXPlXrI9DePW&3w9Gd< z+zwk$eRwZbF>%YJQhVWhANM;1tlt0T$%%FAw736WvTVl0Sobom)J{*$@+bynw_R|<(=ukEbgBr`eo{zj$Uza&qr zi_iVfI{VyP@bcl8tJOBW4)G~d{Vlci;gpqTJ6_ixo8y`GWJgub!!Rax(8}RC-p*oQ zlI?eEziV1vckfG(lwa9bn{>txjlWuC4m$QnDDhYYUOaV$K`OV+Yr3C~VP8^tLg0mu zi<%9mF6%nF*6{9&)Sd1>YBf)?AC+`CW)?7uUFVI~`a3Jj-X`Sxyi{J;UkDDP+X0Jn zE6V#WN?kkbP$qj~Vr+cAb&~OMBT?7>PVJa`x-a+ z@TOcp_pQt9dtkkwn6JcIM+I4l9Z3al-^zT-L|KJ5W%rcVoVZ&Y?{r(>{MOr?H%)ma z$40(c`tIMNP0k;b*DsB{*7IhT$i&hN-k!?)_g5OfIa(eXB^xz0QDyhCgiYB8R(VR! zc=M~On`vUho2;#8RMmD@-T5~|dAHiSSj#2O&#p>lh;j1a#Po`V#@u=D7VKZHbHx*~F!;&Ib(8b{TUeKT&%T~^{EF@2 zX3+kXGM^MHsl6%t(xt+> zo4c3gD?XEJtV>F;RZ@G`bzn}kIe-3&2@I3J$35Ygvf$|qM%l){zdrx(>6bFfQu&pi91+JbBU^ZAB$`-YC^3BTK7S>;@ zdgm5bz4~dbUaa{0iTA?DZu^-t1SaoT_S#!t@2z$I^ID&>tC_FnwO>5bDL5&1XZHCw zAuA@nx)l8IoM+#gTPY{qKZP&KU;mCxU$43Hvl6$NcO)n;TKieeX- zexUO15XSDQHjH`)A}5X}4Gi6ao;JOc?k}LNfZZ?4iQ&D#q--bv|HON{C2{<8u?r=NQ&qVI2y>qwbR5+kJI1? z|2w0O4coi7K3`yIp^>B3&MDW&{N|MY)fvaFOzwe3XI5pJxbL5k z>MPM5>!c>f9ygu8$1b1C#>2nu-|2Pv9baVsx`n-x)>zz>J^R6;OB?@ZU#K_nn$7L? z;|;^}&_k8JX&c2W%y|mdhJB3f7rF9u{uR=>}cc+TmH-b+d3AV zRodS3ZxtNWGGk@Q^^FlI@8!}6+!!#4(?W_z%B@iG5u4jl!z{B&Wu6k7OH8aJZ{Jun zx8#oKq!r4GI_HY@G&QvbUXkm)u^`ByGw8~vXZONguU3DzTXD$nm3i&|_ou}zOW#?3 zpHu#B=kmC_-}`o*_C7Z0;si0i$#%WrG55U6%6QMuzWSoKIDX#ljxO%v4z=F5Gl9 z=3j8>E59QP@5{Y1E=?;qspGQd?$#3+Ke*QGTy_^XAkS?9xqcfpcRE4~H(=oV{kl=GAQFWlN>jJ*wNV`t$q3c9`NByEbr%*Pw7tnxOkfAj5Jv##}==BEx%&%N2BUZL5(*Jyk8)rE6+)~5%aJ@6sg;bhE# z10M=r*qpd{cpI-o)}C8i^IufBYi_o`5gpBMcm3l3==e9szD|%n9@8ew&?(DYzT!V) z?|O^f!TgL>_1*zb&zCEn`4~}RU0)oqbk9fGa`n{-)7$^cUzxg%Uw+2IyP&v&AZI7q^zVA6z%CMTto;O#uVy8!Q-pvJ`mh0}BDfM5{ne_ zwINxb7uQAmczDWIt(!7ciU$Pz#gFa#ymsA>?B|a!y#1qV`!I)Lm0nbD*lM?%9cyoy ze_?U4fARJ~_T2k>=PqUMDH0L0RlM)7Fnzhmry`-NKUTiKqM&0L%r{fE_M*L(wRME^ z_c{7!PhRk<4?cc=wfp+h7w6i~S@~Ad&3=|%teegDT>;@cw01?#lM@bFc6-_Ux|rps z>#07J{sJq;`|7FE} zDao7Z`|FEtNlN^?-)wp-Euq4rz>Q()rJtv2{<;}JzIs`0Hv8lEBEI`4?^7^0-~J$D>Penw zyLV3iR9swt%$$GQlbcaS^7l7hI=1c8>BlUr{_OjGbt})Wd=$(c<}FcI`M*B*@MZqW z+y(Ym=37s@US5!XdF!11PY)MgFL-%X)#X#IiNL-;2adeEI$i7iYMX-krhUy;v)4bZ znZy5jQv0XHhnBE${`N?}88^-8>nt|cH>;dkmzu3x^Q9mseDTuC+u;dUz5f-xdSX6% z|G$aTH>Fqn7gseiSOCNKeMMR zJ38JvI90FfxNevAt-CY$U*z9e^89hz@w~?R3EaDvsMxodtE|~kIC+QIl{qgnChlkw zGG3xl;<8iFe$u@YS+7(YKm2`O6a4!*v%`CSF3UG-TO>^lHg9d*d_Z#DU4i~;zGGnt zQ#)7l1n!pJS0y3Jag|ZwdBVHUm~@WnQypF0GuQl_?_$HUXz~4jWw#2>&*4{lzfmne z!mu>{*vj*3Uj`q({jA2Ka(n8vV^c4GOMl{j#;s?W)&H05T+_c9{CnHWnQ!*fR5k1B z{OLB~g`XyG?{mwERb8*E_j+r>`5o)_&(pc$QdZ4&l`o|J$QS;}RdF|rjO}ywie)h> z?P5Qbtslb~xk0*L>ynGz?WuCA{j)M(E6@Ei)88w~JS6{Sm2dowk5!Kz9<>*_IFjy z!A%Q0zVJ^v^Hu)JovjnT^tb3uzkX=0hl7pkm9I)`SExQe{9E8-!6D1(ChNO{i?+6| zOPV_EaQ5~|w^qI`{gqTUFZwt~%7uhRFTPt*3x)c>zh1l}I*vPW&ap*1w}&zs>wbH6 zC{o{J?isiFQfmVeS(l3D6+Osao&0A0MceGzx@H#Y&QCV1d*&T^dYdS-&aLmCe%5zO z2xe9tE2)(BkKAK!SCw_7-~^lTisiLG*k07nFii3b4m;hZbN;u@y_&k>kW*<5548-g z-;v*vSNB5ycKV+yskKX{M84kV|MEgX*=c^pL_@h%e1V09*KJdlz1r0%um7Ui?eEsp z@@^hC6Zii69-VgcLuKUdUvjs$y_pQw>C*jzugm--dLBsgZcBV51F?uUsx3%N@$39t6>^5(hC^<{8yl*v$+4!}FmiWt&)1}p;4B&`^i=fjkD*h?@kJGuD9FY z@Oj%T8KqVFQwqPT$@_WiWOAE4`8acyUW}uSlUFIHRO&auk5eKi%BZ)l)^jX6!xS6y zwRN?^q~;2NqdsSkznQ_`-ZSM&o=CR7=4K%glT$B}M3&hs$Ps^W=vJx6?wMcOPUx+; zsQ9+!?VhDSIGL8$w-ilyBDHayn><%q#`hT+A!{T0?w)7qU*}`ud@pFCp3clmaZcIC z?Y;;`Ye{nMo6{*=^|*0nmqwDEQrB6%jr_TC#uKMqx*j62*G#_asfTN~h1rCqtyg`o ziyi5UuaI_=eA9AKHpGk1D)Yj#*uMP&>`Wi#mh~JG`z}+T-J;y8WT~9}w*I^LiSG>D zfl()-zRAqoTV23>-&R6%+DRFa-3clea#)rwkJpzJ@tAHXT%JE~;l4ekAExyGw6DK( z*T7d+`h2L|>&?p&p4x5wc`kI7o22-Hx`by{x_=+PpX#N`a{kwX`{#e>&tU8CZNGiI zYW>Oho&L!?t9_NCV{b}a-v8z<@8<&fmnUXSeE;{gpv_V1RPl3<-<{gUbSHb){I_v} zh3O|USKj5=yfDT=(q_TppSL*c<_Ye#-nwWE&UgFluo_+ z7RY2-c0Sm6$-0#l7y!0S!1+`^8E z*$s72}4XVLT(D(hI~Tx0Z|RdwCpKZ;smaVuG> zZp!=^8Qm$*T|X{<^jQ5uZ(!2xPRq~#1mn3yWdmzc*aYI1{`CpeTIF&3^wQHjGkflR zj^@sj(+_-nH*dQmqtR0d|KxzjlH9##oJ6$WhD>;I_msGf>eXkDZEh~t-J_NNlzrNx ztj%i$UaoDk&)n0lwd#MM`<+b%HxFO4JD;7peX61UlD3*%2W{+k^)LEV@zPXz(Vi2* zVm(JiWN$TzCj7{H>CSvTRmXnrQu$d^&R%raOKaJtcYjOTb%V8Gya_){w?C<|{8IVs zO?=S9o1%}MAN=|^zw%g|_P!H5pHKY%K6ADH;fa|O-QO&C-gMq=&P?Iyg;ww0&grb3 zXZ!hU)3HFI?*WJ6Dzj^*U(R3VSHnN4xb)>;_LjVzQLHiPcVa7V-<@!y^6{TNpZVvl znro|D=>6+sr2NTaK9U;e_lK3ae`U&_p6a;etX`x=7l*rHYr(cJVNP#8+_c@zp1wx@ zP3GUFj%_7J|E_zmmNnvfU~JWX#=VU?rYUxfDQ=54^X|N-T9lS5DtP|;iNKEKvtpKu zhN!I+S)0dqyvEc}o_A~6o|iQdn&(Q*PP+81TCiDTq?T~_+!oVAaTBp-UuGU%754a1^~sNK z7`U06tsew%CWuXwp7Y~4&)0(1edjnhw+AF9o_uqsE_1eZw)M97W&4<8WW6}1$rWsu z`}1|jgcoZY-`2z~3U~gk#aG*7+@+-S@@*!3_pZA)UGR9iWwo#Py8mf! zXRW#Leexv!7n2yvr}@p^QE|3o-%O|7Pfn*d-qiULeeS!u*fF2TJ^vM6bf1rT|L$#~ z>#jIIzZ%P#`==fAp8f6eXU$Z}NsXW$>PN+2C%o|BVXr_4LN=<%UlJLRSd+}82duyx*d-Q;5I&go`)emDB9d{+1N%w~)oiiKyeS|D&KG)){k>e zK@o@Uu;gBEzigsY=2lge6?H4;kw*Auj?UOERbQ2IJF?F$5tY=u*thfOk|n;f-&}0F z`FE@CRoPOyE2GVy|H>*)t?M=)zqL=DqF=fCk?m9G)c@|5fA-r>)xT&XW&T8Ao>&Rj tmzu-T4_6&@jW(~400B9s|Jnx_m@k%x7F6d*GB7YOc)I$ztaD0e0svI*MUemi literal 0 HcmV?d00001 diff --git a/docs/plus/unit-testing.rst b/docs/plus/unit-testing.rst index 204e0670..e8c08219 100644 --- a/docs/plus/unit-testing.rst +++ b/docs/plus/unit-testing.rst @@ -14,7 +14,7 @@ Unit Testing ============ -.. versionadded:: 3.0 (PlatformIO Plus) +.. versionadded:: 3.0 (`PlatformIO Plus `_) `Unit Testing (wiki) `_ is a software testing method by which individual units of source code, sets @@ -22,7 +22,7 @@ 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. -PlatformIO Test System supports 2 different test types: +PlatformIO Testing Engine supports 2 different test types: 1. **Local Test** - *[host, native]*, process test on the host machine using :ref:`platform_native`. @@ -33,7 +33,7 @@ PlatformIO Test System supports 2 different test types: You will be able to run the same test on the different target devices (:ref:`embedded_boards`). -PlatformIO Test System consists of: +PlatformIO Testing Engine consists of: * Project builder * Test builder @@ -49,12 +49,20 @@ Also, is possible to ignore some tests for specific environment using .. contents:: +Demo +---- + +Demo of `Local & Embedded: Calculator `_. + +.. image:: ../_static/pioplus-unit-testing-demo.png + :target: https://youtu.be/bo3VVRZVKhA + .. _unit_testing_design: Design ------ -PlatformIO Test System design is based on a few isolated components: +PlatformIO Testing Engine design is based on a few isolated components: 1. **Main program**. Contains the independent modules, procedures, functions or methods that will be the target candidates (TC) for testing. @@ -121,6 +129,9 @@ Workflow } #endif + + .. code-block:: c + /** * Generic C/C++ */ @@ -142,7 +153,7 @@ Workflow 6. Place test to ``test`` directory. If you have more than one test, split them into sub-folders. For example, ``test/test_1/*.[c,cpp,h]``, ``test_N/*.[c,cpp,h]``, etc. If no such directory in ``test`` folder, then - PlatformIO Test System will treat the source code of ``test`` folder + PlatformIO Testing Engine will treat the source code of ``test`` folder as SINGLE test. 7. Run tests using :ref:`cmd_test` command. @@ -381,71 +392,83 @@ Source files Test results ~~~~~~~~~~~~ -.. code-block:: bash +.. code:: - > platformio test --environment uno + > platformio test -e nodemcu --verbose + + PlatformIO Plus (https://pioplus.com) v0.1.0 + Verbose mode can be enabled via `-v, --verbose` option Collected 1 items - ========================= [test::*] Building... (1/3) ============================== + ============================== [test::*] Building... (1/3) ============================== + [Wed Sep 7 15:16:55 2016] Processing nodemcu (platform: espressif8266, board: nodemcu, framework: arduino) + ---------------------------------------------------------------------------------------------------------------------------------------------------------------- + Verbose mode can be enabled via `-v, --verbose` option + Collected 34 compatible libraries + Looking for dependencies... + Project does not have dependencies + Compiling .pioenvs/nodemcu/src/main.o + Compiling .pioenvs/nodemcu/test/output_export.o + Compiling .pioenvs/nodemcu/test/test_main.o + Compiling .pioenvs/nodemcu/UnityTestLib/unity.o + Archiving .pioenvs/nodemcu/libFrameworkArduinoVariant.a + Indexing .pioenvs/nodemcu/libFrameworkArduinoVariant.a + Compiling .pioenvs/nodemcu/FrameworkArduino/Esp.o + Compiling .pioenvs/nodemcu/FrameworkArduino/FS.o + Compiling .pioenvs/nodemcu/FrameworkArduino/HardwareSerial.o + Compiling .pioenvs/nodemcu/FrameworkArduino/IPAddress.o + Archiving .pioenvs/nodemcu/libUnityTestLib.a + Indexing .pioenvs/nodemcu/libUnityTestLib.a + Compiling .pioenvs/nodemcu/FrameworkArduino/MD5Builder.o + ... + Compiling .pioenvs/nodemcu/FrameworkArduino/umm_malloc/umm_malloc.o + Archiving .pioenvs/nodemcu/libFrameworkArduino.a + Indexing .pioenvs/nodemcu/libFrameworkArduino.a + Linking .pioenvs/nodemcu/firmware.elf + Calculating size .pioenvs/nodemcu/firmware.elf + text data bss dec hex filename + 223500 2408 29536 255444 3e5d4 .pioenvs/nodemcu/firmware.elf + Building .pioenvs/nodemcu/firmware.bin - [Wed Jun 15 00:27:42 2016] Processing uno (platform: atmelavr, board: uno, framework: arduino) - -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - avr-g++ -o .pioenvs/uno/test/test_main.o -c -fno-exceptions -fno-threadsafe-statics -std=gnu++11 -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DPLATFORMIO=030000 -DARDUINO_ARCH_AVR -DARDUINO_AVR_UNO -DARDUINO=10608 -DUNIT_TEST -DUNITY_INCLUDE_CONFIG_H -I.pioenvs/uno/FrameworkArduino -I.pioenvs/uno/FrameworkArduinoVariant -Isrc -I.pioenvs/uno/UnityTestLib test/test_main.cpp - avr-g++ -o .pioenvs/uno/firmware.elf -Os -mmcu=atmega328p -Wl,--gc-sections,--relax .pioenvs/uno/src/main.o .pioenvs/uno/test/output_export.o .pioenvs/uno/test/test_main.o -L.pioenvs/uno -Wl,--start-group .pioenvs/uno/libUnityTestLib.a .pioenvs/uno/libFrameworkArduinoVariant.a .pioenvs/uno/libFrameworkArduino.a -lm -Wl,--end-group - avr-objcopy -O ihex -R .eeprom .pioenvs/uno/firmware.elf .pioenvs/uno/firmware.hex - avr-size --mcu=atmega328p -C -d .pioenvs/uno/firmware.elf - AVR Memory Usage - ---------------- - Device: atmega328p + ============================== [test::*] Uploading... (2/3) ============================== + [Wed Sep 7 15:17:01 2016] Processing nodemcu (platform: espressif8266, board: nodemcu, framework: arduino) + ---------------------------------------------------------------------------------------------------------------------------------------------------------------- + Verbose mode can be enabled via `-v, --verbose` option + Collected 34 compatible libraries + Looking for dependencies... + Project does not have dependencies + Linking .pioenvs/nodemcu/firmware.elf + Checking program size .pioenvs/nodemcu/firmware.elf + text data bss dec hex filename + 223500 2408 29536 255444 3e5d4 .pioenvs/nodemcu/firmware.elf + Calculating size .pioenvs/nodemcu/firmware.elf + text data bss dec hex filename + 223500 2408 29536 255444 3e5d4 .pioenvs/nodemcu/firmware.elf + Looking for upload port... + Auto-detected: /dev/cu.SLAB_USBtoUART + Uploading .pioenvs/nodemcu/firmware.bin + Uploading 230064 bytes from .pioenvs/nodemcu/firmware.bin to flash at 0x00000000 + ................................................................................ [ 35% ] + ................................................................................ [ 71% ] + ................................................................. [ 100% ] - Program: 4702 bytes (14.3% Full) - (.text + .data + .bootloader) + =============================== [test::*] Testing... (3/3) =============================== + If you don't see any output for the first 10 secs, please reset board (press reset button) - Data: 460 bytes (22.5% Full) - (.data + .bss + .noinit) - - - ========================= [test::*] Uploading... (2/3) ============================== - - [Wed Jun 15 00:27:43 2016] Processing uno (platform: atmelavr, board: uno, framework: arduino) - -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - avr-g++ -o .pioenvs/uno/firmware.elf -Os -mmcu=atmega328p -Wl,--gc-sections,--relax .pioenvs/uno/src/main.o .pioenvs/uno/test/output_export.o .pioenvs/uno/test/test_main.o -L.pioenvs/uno -Wl,--start-group .pioenvs/uno/libUnityTestLib.a .pioenvs/uno/libFrameworkArduinoVariant.a .pioenvs/uno/libFrameworkArduino.a -lm -Wl,--end-group - MethodWrapper([".pioenvs/uno/firmware.elf"], [".pioenvs/uno/src/main.o", ".pioenvs/uno/test/output_export.o", ".pioenvs/uno/test/test_main.o"]) - Check program size... - text data bss dec hex filename - 4464 238 222 4924 133c .pioenvs/uno/firmware.elf - BeforeUpload(["upload"], [".pioenvs/uno/firmware.hex"]) - Looking for upload port/disk... - avr-size --mcu=atmega328p -C -d .pioenvs/uno/firmware.elf - - Auto-detected: /dev/cu.usbmodemFD131 - avrdude -v -p atmega328p -C "/Users/ikravets/.platformio/packages/tool-avrdude/avrdude.conf" -c arduino -b 115200 -P "/dev/cu.usbmodemFD131" -D -U flash:w:.pioenvs/uno/firmware.hex:i - - [...] - - avrdude done. Thank you. - - ========================= [test::*] Testing... (3/3) ========================= - - If you do not see any output for the first 10 secs, please reset board (press reset button) - - test/test_main.cpp:30:test_led_builtin_pin_number PASSED - test/test_main.cpp:41:test_led_state_high PASSED - test/test_main.cpp:43:test_led_state_low PASSED - test/test_main.cpp:41:test_led_state_high PASSED - test/test_main.cpp:43:test_led_state_low PASSED - test/test_main.cpp:41:test_led_state_high PASSED - test/test_main.cpp:43:test_led_state_low PASSED - test/test_main.cpp:41:test_led_state_high PASSED - test/test_main.cpp:43:test_led_state_low PASSED - test/test_main.cpp:41:test_led_state_high PASSED - test/test_main.cpp:43:test_led_state_low PASSED + test/test_main.cpp:41:test_led_state_high [PASSED] + test/test_main.cpp:43:test_led_state_low [PASSED] + test/test_main.cpp:41:test_led_state_high [PASSED] + test/test_main.cpp:43:test_led_state_low [PASSED] + test/test_main.cpp:41:test_led_state_high [PASSED] + test/test_main.cpp:43:test_led_state_low [PASSED] + test/test_main.cpp:41:test_led_state_high [PASSED] + test/test_main.cpp:43:test_led_state_low [PASSED] ----------------------- - 11 Tests 0 Failures 0 Ignored + 11 Tests 1 Failures 0 Ignored - ========================= [TEST SUMMARY] ===================================== - test:*/env:uno PASSED - ========================= [PASSED] Took 13.35 seconds ======================== + ===================================== [TEST SUMMARY] ===================================== + test:*/env:nodemcu [PASSED] + ================================ [PASSED] Took 38.15 seconds ================================ Examples -------- From a28e04bfdeffc50cbaca7eb7fe0fcdcb5bf8c69f Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 7 Sep 2016 15:56:53 +0300 Subject: [PATCH 279/284] Update pio run command examples --- docs/userguide/cmd_run.rst | 320 ++++++++++++++++++++++++++++--------- 1 file changed, 245 insertions(+), 75 deletions(-) diff --git a/docs/userguide/cmd_run.rst b/docs/userguide/cmd_run.rst index a3b71939..020c112a 100644 --- a/docs/userguide/cmd_run.rst +++ b/docs/userguide/cmd_run.rst @@ -93,27 +93,27 @@ Examples 1. Process `Wiring Blink Example `_ -.. code-block:: bash +.. code:: - $ platformio run - [Sun Jul 17 00:09:16 2016] Processing uno (platform: atmelavr, board: uno, framework: arduino) + > platformio run + + [Wed Sep 7 15:48:58 2016] Processing uno (platform: atmelavr, board: uno, framework: arduino) ----------------------------------------------------------------------------------------------- + Verbose mode can be enabled via `-v, --verbose` option + Collected 36 compatible libraries Looking for dependencies... - Collecting 32 compatible libraries - Processing src/main.cpp - Processing .pioenvs/uno/libFrameworkArduinoVariant.a - Processing .platformio/packages/framework-arduinoavr/cores/arduino/CDC.cpp - Processing .platformio/packages/framework-arduinoavr/cores/arduino/HardwareSerial.cpp - Processing .platformio/packages/framework-arduinoavr/cores/arduino/HardwareSerial0.cpp + Project does not have dependencies + Compiling .pioenvs/uno/src/main.o + Archiving .pioenvs/uno/libFrameworkArduinoVariant.a + Indexing .pioenvs/uno/libFrameworkArduinoVariant.a + Compiling .pioenvs/uno/FrameworkArduino/CDC.o ... - Processing .platformio/packages/framework-arduinoavr/cores/arduino/wiring_analog.c - Processing .platformio/packages/framework-arduinoavr/cores/arduino/wiring_digital.c - Processing .platformio/packages/framework-arduinoavr/cores/arduino/wiring_pulse.c - Processing .platformio/packages/framework-arduinoavr/cores/arduino/wiring_shift.c - Processing .pioenvs/uno/libFrameworkArduino.a - Processing .pioenvs/uno/firmware.elf - Processing .pioenvs/uno/firmware.hex - Processing size + Compiling .pioenvs/uno/FrameworkArduino/wiring_shift.o + Archiving .pioenvs/uno/libFrameworkArduino.a + Indexing .pioenvs/uno/libFrameworkArduino.a + Linking .pioenvs/uno/firmware.elf + Building .pioenvs/uno/firmware.hex + Calculating size .pioenvs/uno/firmware.elf AVR Memory Usage ---------------- Device: atmega328p @@ -125,83 +125,253 @@ Examples (.data + .bss + .noinit) + =========================== [SUCCESS] Took 2.47 seconds =========================== + + [Wed Sep 7 15:49:01 2016] Processing nodemcu (platform: espressif8266, board: nodemcu, framework: arduino) + ----------------------------------------------------------------------------------------------- + Verbose mode can be enabled via `-v, --verbose` option + Collected 34 compatible libraries + Looking for dependencies... + Project does not have dependencies + Compiling .pioenvs/nodemcu/src/main.o + Archiving .pioenvs/nodemcu/libFrameworkArduinoVariant.a + Indexing .pioenvs/nodemcu/libFrameworkArduinoVariant.a + Compiling .pioenvs/nodemcu/FrameworkArduino/Esp.o + Compiling .pioenvs/nodemcu/FrameworkArduino/FS.o + Compiling .pioenvs/nodemcu/FrameworkArduino/HardwareSerial.o + ... + Archiving .pioenvs/nodemcu/libFrameworkArduino.a + Indexing .pioenvs/nodemcu/libFrameworkArduino.a + Linking .pioenvs/nodemcu/firmware.elf + Calculating size .pioenvs/nodemcu/firmware.elf + text data bss dec hex filename + 221240 888 29400 251528 3d688 .pioenvs/nodemcu/firmware.elf + Building .pioenvs/nodemcu/firmware.bin + =========================== [SUCCESS] Took 6.43 seconds =========================== + + [Wed Sep 7 15:49:07 2016] Processing teensy31 (platform: teensy, board: teensy31, framework: arduino) + ----------------------------------------------------------------------------------------------- + Verbose mode can be enabled via `-v, --verbose` option + Collected 96 compatible libraries + Looking for dependencies... + Project does not have dependencies + Compiling .pioenvs/teensy31/src/main.o + Compiling .pioenvs/teensy31/FrameworkArduino/AudioStream.o + Compiling .pioenvs/teensy31/FrameworkArduino/DMAChannel.o + ... + Compiling .pioenvs/teensy31/FrameworkArduino/yield.o + Archiving .pioenvs/teensy31/libFrameworkArduino.a + Indexing .pioenvs/teensy31/libFrameworkArduino.a + Linking .pioenvs/teensy31/firmware.elf + Calculating size .pioenvs/teensy31/firmware.elf + text data bss dec hex filename + 11288 168 2288 13744 35b0 .pioenvs/teensy31/firmware.elf + Building .pioenvs/teensy31/firmware.hex + =========================== [SUCCESS] Took 5.36 seconds =========================== + + [Wed Sep 7 15:49:12 2016] Processing lpmsp430g2553 (platform: timsp430, build_flags: -D LED_BUILTIN=RED_LED, board: lpmsp430g2553, framework: energia) + ----------------------------------------------------------------------------------------------- + Verbose mode can be enabled via `-v, --verbose` option + Collected 29 compatible libraries + Looking for dependencies... + Project does not have dependencies + Compiling .pioenvs/lpmsp430g2553/src/main.o + Compiling .pioenvs/lpmsp430g2553/FrameworkEnergia/HardwareSerial.o + Compiling .pioenvs/lpmsp430g2553/FrameworkEnergia/IPAddress.o + ... + Compiling .pioenvs/lpmsp430g2553/FrameworkEnergia/wiring_digital.o + Compiling .pioenvs/lpmsp430g2553/FrameworkEnergia/wiring_pulse.o + Compiling .pioenvs/lpmsp430g2553/FrameworkEnergia/wiring_shift.o + Archiving .pioenvs/lpmsp430g2553/libFrameworkEnergia.a + Indexing .pioenvs/lpmsp430g2553/libFrameworkEnergia.a + Linking .pioenvs/lpmsp430g2553/firmware.elf + Calculating size .pioenvs/lpmsp430g2553/firmware.elf + text data bss dec hex filename + 820 0 20 840 348 .pioenvs/lpmsp430g2553/firmware.elf + Building .pioenvs/lpmsp430g2553/firmware.hex + =========================== [SUCCESS] Took 2.34 seconds =========================== 2. Process specific environment -.. code-block:: bash +.. code:: - $ platformio run -e arduino_pro5v -e launchpad_lm4f120 - [Sun Jul 17 00:10:14 2016] Processing nodemcu (platform: espressif8266, board: nodemcu, framework: arduino) - -------------------------------------------------------------------------------------------------------- + > platformio run -e nodemcu -e teensy31 + + [Wed Sep 7 15:49:01 2016] Processing nodemcu (platform: espressif8266, board: nodemcu, framework: arduino) + ----------------------------------------------------------------------------------------------- + Verbose mode can be enabled via `-v, --verbose` option + Collected 34 compatible libraries Looking for dependencies... - Collecting 29 compatible libraries - Processing src/main.cpp - Processing .pioenvs/nodemcu/libFrameworkArduinoVariant.a - Processing .platformio/packages/framework-arduinoespressif8266/cores/esp8266/Esp.cpp + Project does not have dependencies + Compiling .pioenvs/nodemcu/src/main.o + Archiving .pioenvs/nodemcu/libFrameworkArduinoVariant.a + Indexing .pioenvs/nodemcu/libFrameworkArduinoVariant.a + Compiling .pioenvs/nodemcu/FrameworkArduino/Esp.o + Compiling .pioenvs/nodemcu/FrameworkArduino/FS.o + Compiling .pioenvs/nodemcu/FrameworkArduino/HardwareSerial.o ... - Processing .platformio/packages/framework-arduinoespressif8266/cores/esp8266/pgmspace.cpp - Processing .platformio/packages/framework-arduinoespressif8266/cores/esp8266/setjmp.S - Processing .pioenvs/nodemcu/libFrameworkArduino.a - Processing .platformio/packages/framework-arduinoespressif8266/tools/sdk/lib/libmesh.a - ... - Processing .platformio/packages/framework-arduinoespressif8266/tools/sdk/lib/libaxtls.a - Processing .platformio/packages/framework-arduinoespressif8266/tools/sdk/lib/libstdc++.a - Processing .pioenvs/nodemcu/firmware.elf - Processing .platformio/packages/tool-esptool/esptool - Processing .pioenvs/nodemcu/firmware.bin - Processing size + Archiving .pioenvs/nodemcu/libFrameworkArduino.a + Indexing .pioenvs/nodemcu/libFrameworkArduino.a + Linking .pioenvs/nodemcu/firmware.elf + Calculating size .pioenvs/nodemcu/firmware.elf text data bss dec hex filename - 221456 884 29496 251836 3d7bc .pioenvs/nodemcu/firmware.elf + 221240 888 29400 251528 3d688 .pioenvs/nodemcu/firmware.elf + Building .pioenvs/nodemcu/firmware.bin + =========================== [SUCCESS] Took 6.43 seconds =========================== + + [Wed Sep 7 15:49:07 2016] Processing teensy31 (platform: teensy, board: teensy31, framework: arduino) + ----------------------------------------------------------------------------------------------- + Verbose mode can be enabled via `-v, --verbose` option + Collected 96 compatible libraries + Looking for dependencies... + Project does not have dependencies + Compiling .pioenvs/teensy31/src/main.o + Compiling .pioenvs/teensy31/FrameworkArduino/AudioStream.o + Compiling .pioenvs/teensy31/FrameworkArduino/DMAChannel.o + ... + Compiling .pioenvs/teensy31/FrameworkArduino/yield.o + Archiving .pioenvs/teensy31/libFrameworkArduino.a + Indexing .pioenvs/teensy31/libFrameworkArduino.a + Linking .pioenvs/teensy31/firmware.elf + Calculating size .pioenvs/teensy31/firmware.elf + text data bss dec hex filename + 11288 168 2288 13744 35b0 .pioenvs/teensy31/firmware.elf + Building .pioenvs/teensy31/firmware.hex + =========================== [SUCCESS] Took 5.36 seconds =========================== 3. Process specific target (clean project) -.. code-block:: bash +.. code:: bash - $ platformio run -t clean - [Sun Jul 17 00:19:36 2016] Processing uno (platform: atmelavr, board: uno, framework: arduino) - ---------------------------------------------------------------------------------------------------------------------------------------------------------------- - Looking for dependencies... - Collecting 32 compatible libraries - Removed .pioenvs/uno/FrameworkArduino/CDC.o - Removed .pioenvs/uno/FrameworkArduino/HardwareSerial.o - ... - Removed .pioenvs/uno/libFrameworkArduinoVariant.a - Removed .pioenvs/uno/src/main.o - Removed .pioenvs/uno/libFrameworkArduino.a + > platformio run -t clean + [Wed Sep 7 15:53:26 2016] Processing uno (platform: atmelavr, board: uno, framework: arduino) + ----------------------------------------------------------------------------------------------------- Removed .pioenvs/uno/firmware.elf Removed .pioenvs/uno/firmware.hex + Removed .pioenvs/uno/libFrameworkArduino.a + Removed .pioenvs/uno/libFrameworkArduinoVariant.a + Removed .pioenvs/uno/FrameworkArduino/_wiring_pulse.o + Removed .pioenvs/uno/FrameworkArduino/abi.o + Removed .pioenvs/uno/FrameworkArduino/CDC.o + Removed .pioenvs/uno/FrameworkArduino/HardwareSerial.o + Removed .pioenvs/uno/FrameworkArduino/HardwareSerial0.o + Removed .pioenvs/uno/FrameworkArduino/HardwareSerial1.o + Removed .pioenvs/uno/FrameworkArduino/HardwareSerial2.o + Removed .pioenvs/uno/FrameworkArduino/HardwareSerial3.o + Removed .pioenvs/uno/FrameworkArduino/hooks.o + Removed .pioenvs/uno/FrameworkArduino/IPAddress.o + Removed .pioenvs/uno/FrameworkArduino/main.o + Removed .pioenvs/uno/FrameworkArduino/new.o + Removed .pioenvs/uno/FrameworkArduino/PluggableUSB.o + Removed .pioenvs/uno/FrameworkArduino/Print.o + Removed .pioenvs/uno/FrameworkArduino/Stream.o + Removed .pioenvs/uno/FrameworkArduino/Tone.o + Removed .pioenvs/uno/FrameworkArduino/USBCore.o + Removed .pioenvs/uno/FrameworkArduino/WInterrupts.o + Removed .pioenvs/uno/FrameworkArduino/wiring.o + Removed .pioenvs/uno/FrameworkArduino/wiring_analog.o + Removed .pioenvs/uno/FrameworkArduino/wiring_digital.o + Removed .pioenvs/uno/FrameworkArduino/wiring_pulse.o + Removed .pioenvs/uno/FrameworkArduino/wiring_shift.o + Removed .pioenvs/uno/FrameworkArduino/WMath.o + Removed .pioenvs/uno/FrameworkArduino/WString.o + Removed .pioenvs/uno/src/main.o + Done cleaning + ======================= [SUCCESS] Took 0.49 seconds ======================= + + [Wed Sep 7 15:53:27 2016] Processing nodemcu (platform: espressif8266, board: nodemcu, framework: arduino) + ----------------------------------------------------------------------------------------------------- + Removed .pioenvs/nodemcu/firmware.bin + Removed .pioenvs/nodemcu/firmware.elf + Removed .pioenvs/nodemcu/libFrameworkArduino.a + Removed .pioenvs/nodemcu/libFrameworkArduinoVariant.a + ... + Removed .pioenvs/nodemcu/FrameworkArduino/spiffs/spiffs_nucleus.o + Removed .pioenvs/nodemcu/FrameworkArduino/umm_malloc/umm_malloc.o + Removed .pioenvs/nodemcu/src/main.o + Done cleaning + ======================= [SUCCESS] Took 0.50 seconds ======================= + + [Wed Sep 7 15:53:27 2016] Processing teensy31 (platform: teensy, board: teensy31, framework: arduino) + ----------------------------------------------------------------------------------------------------- + Removed .pioenvs/teensy31/firmware.elf + Removed .pioenvs/teensy31/firmware.hex + Removed .pioenvs/teensy31/libFrameworkArduino.a + Removed .pioenvs/teensy31/FrameworkArduino/analog.o + Removed .pioenvs/teensy31/FrameworkArduino/AudioStream.o + ... + Removed .pioenvs/teensy31/FrameworkArduino/WString.o + Removed .pioenvs/teensy31/FrameworkArduino/yield.o + Removed .pioenvs/teensy31/src/main.o + Done cleaning + ======================= [SUCCESS] Took 0.50 seconds ======================= + + [Wed Sep 7 15:53:28 2016] Processing lpmsp430g2553 (platform: timsp430, build_flags: -D LED_BUILTIN=RED_LED, board: lpmsp430g2553, framework: energia) + ----------------------------------------------------------------------------------------------------- + Removed .pioenvs/lpmsp430g2553/firmware.elf + Removed .pioenvs/lpmsp430g2553/firmware.hex + Removed .pioenvs/lpmsp430g2553/libFrameworkEnergia.a + Removed .pioenvs/lpmsp430g2553/FrameworkEnergia/atof.o + ... + Removed .pioenvs/lpmsp430g2553/FrameworkEnergia/avr/dtostrf.o + Removed .pioenvs/lpmsp430g2553/src/main.o + Done cleaning + ======================= [SUCCESS] Took 0.49 seconds ======================= 4. Mix environments and targets -.. code-block:: bash +.. code:: - $ platformio run -e teensy31 -t upload - [Sun Jul 17 00:27:14 2016] Processing teensy31 (platform: teensy, board: teensy31, framework: arduino) - ------------------------------------------------------------------------------------------------------- + > platformio run -e uno -t upload + + [Wed Sep 7 15:55:11 2016] Processing uno (platform: atmelavr, board: uno, framework: arduino) + -------------------------------------------------------------------------------------------------- + Verbose mode can be enabled via `-v, --verbose` option + Collected 36 compatible libraries Looking for dependencies... - Collecting 25 compatible libraries - Processing src/main.cpp - Processing .platformio/packages/framework-arduinoteensy/cores/teensy3/AudioStream.cpp - Processing .platformio/packages/framework-arduinoteensy/cores/teensy3/DMAChannel.cpp - Processing .platformio/packages/framework-arduinoteensy/cores/teensy3/HardwareSerial1.cpp + Project does not have dependencies + Compiling .pioenvs/uno/src/main.o + Archiving .pioenvs/uno/libFrameworkArduinoVariant.a + Indexing .pioenvs/uno/libFrameworkArduinoVariant.a + Compiling .pioenvs/uno/FrameworkArduino/CDC.o ... - Processing .platformio/packages/framework-arduinoteensy/cores/teensy3/yield.cpp - Processing .platformio/packages/tool-teensy/teensy_loader_cli - Processing .pioenvs/teensy31/libFrameworkArduino.a - Processing .pioenvs/teensy31/firmware.elf - Check program size... + Compiling .pioenvs/uno/FrameworkArduino/wiring_shift.o + Archiving .pioenvs/uno/libFrameworkArduino.a + Indexing .pioenvs/uno/libFrameworkArduino.a + Linking .pioenvs/uno/firmware.elf + Checking program size .pioenvs/uno/firmware.elf text data bss dec hex filename - 11080 168 2288 13536 34e0 .pioenvs/teensy31/firmware.elf - Processing .pioenvs/teensy31/firmware.hex - Processing upload - Teensy Loader, Command Line, Version 2.0 - Read ".pioenvs/teensy31/firmware.hex": 11248 bytes, 4.3% usage - Soft reboot is not implemented for OSX - Waiting for Teensy device... - (hint: press the reset button) - Found HalfKay Bootloader - Read ".pioenvs/teensy31/firmware.hex": 11248 bytes, 4.3% usage - Programming........... - Booting + 1034 0 9 1043 413 .pioenvs/uno/firmware.elf + Building .pioenvs/uno/firmware.hex + Looking for upload port... + Auto-detected: /dev/cu.usbmodemFA141 + Uploading .pioenvs/uno/firmware.hex + + avrdude: AVR device initialized and ready to accept instructions + + Reading | ################################################## | 100% 0.01s + + avrdude: Device signature = 0x1e950f + avrdude: reading input file ".pioenvs/uno/firmware.hex" + avrdude: writing flash (1034 bytes): + + Writing | ################################################## | 100% 0.18s + + avrdude: 1034 bytes of flash written + avrdude: verifying flash memory against .pioenvs/uno/firmware.hex: + avrdude: load data flash data from input file .pioenvs/uno/firmware.hex: + avrdude: input file .pioenvs/uno/firmware.hex contains 1034 bytes + avrdude: reading on-chip flash data: + + Reading | ################################################## | 100% 0.15s + + avrdude: verifying ... + avrdude: 1034 bytes of flash verified + + avrdude: safemode: Fuses OK (H:00, E:00, L:00) + + avrdude done. Thank you. + + ======================== [SUCCESS] Took 4.14 seconds ======================== From f7b994354bbf904953019265ae405c81d9e0b796 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 7 Sep 2016 18:50:09 +0300 Subject: [PATCH 280/284] Search libraries by headers/includes with ``platformio lib search --header`` option --- HISTORY.rst | 3 ++- docs/projectconf.rst | 2 +- platformio/commands/lib.py | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 0f41ac40..dcd8c570 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -7,7 +7,7 @@ PlatformIO 3.0 3.0.0 (2016-??-??) ~~~~~~~~~~~~~~~~~~ -* PlatformIO Plus +* `PlatformIO Plus `__ + Local and Embedded `Unit Testing `__ (`issue #408 `_, @@ -42,6 +42,7 @@ PlatformIO 3.0 (`issue #588 `_) + Allowed ``library.json`` to specify sources other than PlatformIO's Repository (`issue #461 `_) + + Search libraries by headers/includes with ``platformio lib search --header`` option * New Intelligent Library Build System diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 9cf240fe..832c2571 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -787,7 +787,7 @@ Example: .. seealso:: Please make sure to read :ref:`ldf` guide first. -A list with extra directories/storages where Library Dependency Finder will +A list with extra directories/storages where :ref:`ldf` will look for dependencies. Multiple paths are allowed. Please separate them using comma+space ", ". diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index bbb196b7..79a082c3 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -164,6 +164,7 @@ def echo_liblist_item(item): @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, From 3069abfe135cbc30c35ef02b5ff3dbf1467f98f8 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 7 Sep 2016 18:50:25 +0300 Subject: [PATCH 281/284] Add migration guide for PIO2 to PIO3 --- docs/index.rst | 2 + docs/librarymanager/ldf.rst | 2 + docs/migration.rst | 213 +++++++++++++++++++++++++++++ docs/userguide/lib/cmd_install.rst | 5 + docs/userguide/lib/cmd_search.rst | 9 +- 5 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 docs/migration.rst diff --git a/docs/index.rst b/docs/index.rst index 9116b5c5..3b006919 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -143,3 +143,5 @@ Contents articles FAQ history + migration + diff --git a/docs/librarymanager/ldf.rst b/docs/librarymanager/ldf.rst index 269b1e6a..ed56dc39 100644 --- a/docs/librarymanager/ldf.rst +++ b/docs/librarymanager/ldf.rst @@ -41,6 +41,8 @@ Library Dependency Finder has controls that can be set up in :ref:`projectconf`: .. contents:: +.. _ldf_storage: + Storage ------- diff --git a/docs/migration.rst b/docs/migration.rst new file mode 100644 index 00000000..9c28647a --- /dev/null +++ b/docs/migration.rst @@ -0,0 +1,213 @@ +.. Copyright 2014-present PlatformIO + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +.. _migration: + +Migrating from 2.x to 3.0 +========================= + +Guidance on how to upgrade from PlatformIO v2.x to v3.x with emphasis on major +changes, what is new, and what is been removed. + +PlatformIO 3 is not backwards compatible with v2.x. Use this section as a +general guide to upgrading from v2.x to v3.0. For a broader overview, see +`what is new `_ in the v3.0 +release announcement. + +.. contents:: + +Major PlatformIO CLI changes +---------------------------- + +.. note:: + PlatformIO 3.x is 100% non-blocking! You do not need to use ``--force`` + option or setup special ``PLATOFMRIO_SETTING_ENABLE_PROMPTS`` environment. + Use PlatformIO 3.0 with sub-processing without any risk! + +This table shows the CLI changes between v2.x and v3.0. + +.. list-table:: + :header-rows: 1 + + * - PlatformIO 2.x + - PlatformIO 3.x + * - platformio platforms + - :ref:`platformio platform ` + * - platformio serialports + - :ref:`cmd_device` + * - platformio settings set enable_prompts false + - Removed! Now, all PlatformIO 3.0 CLI is 100% non-blocking! + + +PlatformIO 2.x commands will be converted to PlatformIO 3.x automatically. +Nevertheless, we recommend to use PlatformIO 3.x commands for the new projects. + +What is new +----------- + +Development Platforms +~~~~~~~~~~~~~~~~~~~~~ + +We have introduced :ref:`platform_creating_manifest_file` and ported +PlatformIO 2.x development platforms according PlatformIO 3.0 decentralized +architecture. Now, platform related things (build scrips, LD scripts, board +configs, package requirements) are located in own repository. Here is the full +list with `PlatformIO 3.0 open source development platforms `__. You can fork it, modify or create custom. +See :ref:`platform_creating` guide for details. + +* :ref:`platform_creating_manifest_file` +* ``espressif`` development platform has been renamed to :ref:`platform_espressif8266` +* PlatformIO 3.0 :ref:`userguide_platform` +* Custom package repositories +* External embedded board configuration files, isolated build scripts +* Embedded Board compatibility with more than one development platform + +Library Manager and Intelligent Build System +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* Powerful and super-fast :ref:`ldf` that interprets C/C++ Preprocessor + conditional macros with deep search behavior +* Project dependencies per build environment using `projectconf_lib_deps` option +* Depend on a library using VCS URL (GitHub, Git, ARM mbed code registry, Hg, SVN) +* Install library by name +* Strict search for library dependencies +* Multiple library storages: Project's Local, PlatformIO's Global or Custom +* Allowed :ref:`library_config` to specify sources other than PlatformIO's Repository +* Check library compatibility with project environment before building +* Control Library Dependency Finder for compatibility using :ref:`projectconf_lib_compat_mode` option +* Custom library storages/directories with :ref:`projectconf_lib_extra_dirs` option +* Handle extra build flags, source filters and build script from :ref:`library_config` +* Allowed to disable library archiving (``*.ar``) +* Show detailed build information about dependent libraries (Library Dependency Graph) +* Support for the 3rd party manifests (Arduino IDE "library.properties" and + ARM mbed "module.json") +* Build System: Attach custom Before/Pre and After/Post actions for targets using :ref:`projectconf_extra_script` + +Command Line Interface +~~~~~~~~~~~~~~~~~~~~~~ + +We have added new commands and changed some existing ones. Here are the new or +updated commands and options. + +.. list-table:: + :header-rows: 1 + + * - Command + - Description + * - :ref:`cmd_boards` + - Returns all supported boards by PlatformIO + * - :option:`platformio boards --installed` + - Returns currently installed boards + * - :option:`platformio ci --project-option` + - Pass custom option from :ref:`projectconf` + * - :option:`platformio ci --verbose` + - Print detailed information about build process + * - :option:`platformio init --project-option` + - Pass custom option from :ref:`projectconf` + * - :option:`platformio lib --global` + - Manage PlatformIO :ref:`Global Library Storage ` + * - :option:`platformio lib --storage-dir` + - Manage :ref:`Custom Library Storage ` + * - :ref:`cmd_lib_install` + - New PlatformIO 3.0 Library Manager! Semantic Versioning, VCS support and external URL support + * - :option:`platformio lib install --silent` + - Suppress progress reporting when install library + * - :option:`platformio lib install --interactive` + - Allow to make a choice for all prompts when install library + * - :option:`platformio lib search --header` + - Search library by specific header file name (include) + * - :option:`platformio lib update --only-check` + - Do not update, only check for new version + * - :ref:`platformio platform ` + - New PlatformIO 3.0 Platform Manager! Semantic Versioning, VCS support and external URL support. + * - :option:`platformio platform update --only-packages` + - Update only platform packages + * - :option:`platformio platform update --only-check` + - Do not update, only check for new version + * - :ref:`cmd_run` + - By default, prints only human-readable information when processing environments + * - :option:`platformio run --verbose` + - Print detailed processing information + * - :ref:`platformio settings set force_verbose true ` + - Force verbose output when processing environments (globally) + * - :ref:`cmd_test` + - PlatformIO Plus Unit Testing + * - :option:`platformio update --only-check` + - Do not update, only check for new version + +:ref:`projectconf` +~~~~~~~~~~~~~~~~~~ + +We have added new options and changed some existing ones. Here are the new or +updated options. + +.. list-table:: + :header-rows: 1 + + * - Section + - Option + - Description + * - platformio + - :ref:`projectconf_pio_libdeps_dir` + - Internal storage where :ref:`librarymanager` will install project dependencies + * - platformio + - :ref:`projectconf_pio_test_dir` + - Directory where :ref:`unit_testing` engine will look for the tests + * - env + - :ref:`projectconf_lib_deps` + - Specify project dependencies that should be installed automatically to :ref:`projectconf_pio_libdeps_dir` before environment processing. + * - env + - :ref:`projectconf_env_platform` + - PlatformIO 3.0 allows to use specific version of platform using `Semantic Versioning `_ (X.Y.Z=MAJOR.MINOR.PATCH). + * - env + - :ref:`projectconf_lib_extra_dirs` + - A list with extra directories/storages where :ref:`ldf` will look for dependencies + * - env + - :ref:`projectconf_lib_ldf_mode` + - This option specifies how does :ref:`ldf` should analyze dependencies (``#include`` directives) + * - env + - :ref:`projectconf_lib_compat_mode` + - Library compatibility mode allows to control strictness of :ref:`ldf` + * - env + - :ref:`projectconf_test_ignore` + - Ignore tests where the name matches specified patterns + +What is removed +--------------- + +Command Line Interface +~~~~~~~~~~~~~~~~~~~~~~ + +The following commands have been dropped or changed in v3.0. + +.. list-table:: + :header-rows: 1 + + * - Command + - Description + * - platformio init --enable-auto-uploading + - Use :option:`platformio init --project-option` instead of it with ``targets = upload`` value + +:ref:`projectconf` +~~~~~~~~~~~~~~~~~~ + +The following options have been dropped or changed in v3.0. + +.. list-table:: + :header-rows: 1 + + * - Section + - Option + - Description + * - platformio + - :ref:`projectconf_pio_lib_dir` + - Changed: Project's own/private libraries, where in PlatformIO 2.x it was global library storage + diff --git a/docs/userguide/lib/cmd_install.rst b/docs/userguide/lib/cmd_install.rst index 60a846b3..d407d935 100644 --- a/docs/userguide/lib/cmd_install.rst +++ b/docs/userguide/lib/cmd_install.rst @@ -99,6 +99,11 @@ Options Suppress progress reporting +.. option:: + --interactive + +Allow to make a choice for all prompts + Version control --------------- diff --git a/docs/userguide/lib/cmd_search.rst b/docs/userguide/lib/cmd_search.rst index 4bc5d0ea..4ca0789c 100644 --- a/docs/userguide/lib/cmd_search.rst +++ b/docs/userguide/lib/cmd_search.rst @@ -89,18 +89,23 @@ Filter libraries by specified author Filter libraries by specified keyword - .. option:: -f, --framework Filter libraries by specified framework - .. option:: -p, --platform Filter libraries by specified keyword +.. option:: + -i, --header + +Filter libraries by header file (include) + +For example, ``platformio lib search --header "OneWire.h"`` + .. option:: --json-output From cd45749c822e418ece1c11f94876c1a5cb93a749 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 7 Sep 2016 19:05:15 +0300 Subject: [PATCH 282/284] Fix issue with multiple archives when linking firmware --- platformio/builder/tools/piolib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 1439433d..6a357ba5 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -308,7 +308,8 @@ class LibBuilderBase(object): else: self._built_node = self.env.BuildSources( self.build_dir, self.src_dir, self.src_filter) - return libs + [self._built_node] + libs.append(self._built_node) + return libs class UnknownLibBuilder(LibBuilderBase): From 578d8910aaff716f913ae66437a0a2f393f5e8f2 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 7 Sep 2016 19:16:05 +0300 Subject: [PATCH 283/284] Fix menu height for docs --- docs/_static/extra.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/_static/extra.css b/docs/_static/extra.css index a422d397..83ae2147 100644 --- a/docs/_static/extra.css +++ b/docs/_static/extra.css @@ -262,6 +262,12 @@ nav { visibility: none; } +@media (min-width: 768px) { + .wy-side-scroll { + padding-bottom: 50px; + } +} + .navbar-header .navbar-brand { color: #e0e0e0; background: url("../_static/platformio-logo-xs.png") no-repeat; From f78c9436c8f0bf50fa789f96d0b0c3966df6376c Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 7 Sep 2016 20:50:34 +0300 Subject: [PATCH 284/284] Version bump to 3.0.0 (issues #770, #766, #747, #730, #765, #640, #659, #742, #459, #542, #763, #759, #753, #757, #749, #748, #745, #519, #709, #743, #413, #498, #410, #740, #361, #414, #554, #732, #588, #475, #461, #101, #719, #721, #537, #415, #522, #289, #556, #570, #456, #617, #432, #408, #479, #667, #510) --- HISTORY.rst | 2 +- platformio/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index dcd8c570..f96d0962 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -4,7 +4,7 @@ Release Notes PlatformIO 3.0 -------------- -3.0.0 (2016-??-??) +3.0.0 (2016-09-07) ~~~~~~~~~~~~~~~~~~ * `PlatformIO Plus `__ diff --git a/platformio/__init__.py b/platformio/__init__.py index 834b821e..d01eed7d 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0b13") +VERSION = (3, 0, 0) __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio"