2015-11-18 17:16:17 +02:00
|
|
|
# Copyright 2014-2015 Ivan Kravets <me@ikravets.com>
|
|
|
|
#
|
|
|
|
# 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.
|
2014-06-07 13:34:31 +03:00
|
|
|
|
2015-09-01 16:15:04 +03:00
|
|
|
import os
|
2015-02-19 22:02:50 +02:00
|
|
|
import re
|
2015-12-26 14:47:42 +02:00
|
|
|
import sys
|
2014-11-22 23:55:17 +02:00
|
|
|
from imp import load_source
|
2015-12-04 21:06:29 +02:00
|
|
|
from multiprocessing import cpu_count
|
2014-11-29 22:39:44 +02:00
|
|
|
from os.path import isdir, isfile, join
|
2014-06-07 13:34:31 +03:00
|
|
|
|
2015-02-15 23:53:15 +02:00
|
|
|
import click
|
|
|
|
|
2015-12-15 15:58:52 +02:00
|
|
|
from platformio import app, exception, util
|
2014-11-29 22:39:44 +02:00
|
|
|
from platformio.app import get_state_item, set_state_item
|
2014-06-07 13:34:31 +03:00
|
|
|
from platformio.pkgmanager import PackageManager
|
|
|
|
|
2015-03-11 18:12:58 +02:00
|
|
|
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")
|
|
|
|
],
|
2015-03-16 19:24:51 +02:00
|
|
|
"framework-arduinomsp430": [
|
|
|
|
("Arduino Wiring-based Framework (MSP430 Core)",
|
|
|
|
"http://arduino.cc/en/Reference/HomePage")
|
|
|
|
],
|
2015-04-02 20:24:22 +03:00
|
|
|
"framework-arduinoespressif": [
|
|
|
|
("Arduino Wiring-based Framework (ESP8266 Core)",
|
|
|
|
"https://github.com/esp8266/Arduino")
|
|
|
|
],
|
2015-12-26 21:24:01 +02:00
|
|
|
"framework-arduinonordicnrf51": [
|
|
|
|
("Arduino Wiring-based Framework (RFDuino Core)",
|
|
|
|
"https://github.com/RFduino/RFduino")
|
|
|
|
],
|
2015-03-11 18:12:58 +02:00
|
|
|
"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")
|
|
|
|
],
|
2015-03-16 17:34:52 +02:00
|
|
|
"framework-libopencm3": [
|
2015-03-11 18:12:58 +02:00
|
|
|
("libOpenCM3 Framework", "http://www.libopencm3.org/")
|
|
|
|
],
|
|
|
|
"framework-mbed": [
|
|
|
|
("mbed Framework", "http://mbed.org")
|
|
|
|
],
|
2015-12-15 15:58:52 +02:00
|
|
|
"framework-wiringpi": [
|
|
|
|
("GPIO Interface library for the Raspberry Pi", "http://wiringpi.com")
|
|
|
|
],
|
2015-04-02 20:24:22 +03:00
|
|
|
"sdk-esp8266": [
|
|
|
|
("ESP8266 SDK", "http://bbs.espressif.com")
|
|
|
|
],
|
2015-03-11 18:12:58 +02:00
|
|
|
"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/")
|
|
|
|
],
|
2015-08-10 21:39:31 +03:00
|
|
|
"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")
|
|
|
|
],
|
2015-04-02 20:24:22 +03:00
|
|
|
"toolchain-xtensa": [
|
|
|
|
("xtensa-gcc", "https://github.com/jcmvbkbc/gcc-xtensa"),
|
|
|
|
("GDB", "http://www.gnu.org/software/gdb/")
|
|
|
|
],
|
2015-03-11 18:12:58 +02:00
|
|
|
"toolchain-timsp430": [
|
|
|
|
("msp-gcc", "http://sourceforge.net/projects/mspgcc/"),
|
|
|
|
("GDB", "http://www.gnu.org/software/gdb/")
|
|
|
|
],
|
2015-12-26 14:47:42 +02:00
|
|
|
"tool-scons": [
|
|
|
|
("SCons software construction tool", "http://www.scons.org")
|
|
|
|
],
|
2015-03-11 18:12:58 +02:00
|
|
|
"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-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/")
|
2015-04-02 20:24:22 +03:00
|
|
|
],
|
|
|
|
"tool-esptool": [
|
|
|
|
("esptool-ck", "https://github.com/igrr/esptool-ck")
|
2015-12-26 21:24:01 +02:00
|
|
|
],
|
|
|
|
"tool-rfdloader": [
|
|
|
|
("rfdloader", "https://github.com/RFduino/RFduino")
|
2015-03-11 18:12:58 +02:00
|
|
|
]
|
|
|
|
}
|
|
|
|
|
2014-06-07 13:34:31 +03:00
|
|
|
|
2015-03-14 00:02:09 +02:00
|
|
|
def get_packages():
|
|
|
|
return PLATFORM_PACKAGES
|
|
|
|
|
|
|
|
|
2014-06-07 13:34:31 +03:00
|
|
|
class PlatformFactory(object):
|
|
|
|
|
2014-11-24 21:36:44 +02:00
|
|
|
@staticmethod
|
2015-03-16 14:15:57 +02:00
|
|
|
def get_clsname(type_):
|
2015-04-20 18:48:38 +01:00
|
|
|
return "%s%sPlatform" % (type_.upper()[0], type_.lower()[1:])
|
2014-11-24 21:36:44 +02:00
|
|
|
|
2014-11-22 23:55:17 +02:00
|
|
|
@staticmethod
|
2015-03-16 14:15:57 +02:00
|
|
|
def load_module(type_, path):
|
2014-11-29 22:39:44 +02:00
|
|
|
module = None
|
|
|
|
try:
|
|
|
|
module = load_source(
|
2015-03-16 14:15:57 +02:00
|
|
|
"platformio.platforms.%s" % type_, path)
|
2014-11-29 22:39:44 +02:00
|
|
|
except ImportError:
|
2015-03-16 14:15:57 +02:00
|
|
|
raise exception.UnknownPlatform(type_)
|
2014-11-29 22:39:44 +02:00
|
|
|
return module
|
|
|
|
|
|
|
|
@classmethod
|
2015-05-01 17:51:20 +01:00
|
|
|
@util.memoized
|
2015-04-23 14:11:30 +01:00
|
|
|
def _lookup_platforms(cls):
|
2014-11-22 23:55:17 +02:00
|
|
|
platforms = {}
|
2015-04-23 14:11:30 +01:00
|
|
|
for d in (util.get_home_dir(), util.get_source_dir()):
|
|
|
|
pdir = join(d, "platforms")
|
|
|
|
if not isdir(pdir):
|
|
|
|
continue
|
2015-09-01 16:15:04 +03:00
|
|
|
for p in sorted(os.listdir(pdir)):
|
2015-04-23 14:11:30 +01:00
|
|
|
if (p in ("__init__.py", "base.py") or not
|
|
|
|
p.endswith(".py")):
|
2014-11-24 21:36:44 +02:00
|
|
|
continue
|
2015-04-23 14:11:30 +01:00
|
|
|
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
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_platforms(cls, installed=False):
|
|
|
|
platforms = cls._lookup_platforms()
|
2014-11-22 23:55:17 +02:00
|
|
|
|
|
|
|
if not installed:
|
|
|
|
return platforms
|
|
|
|
|
|
|
|
installed_platforms = {}
|
2015-03-16 14:15:57 +02:00
|
|
|
for type_ in get_state_item("installed_platforms", []):
|
|
|
|
if type_ in platforms:
|
|
|
|
installed_platforms[type_] = platforms[type_]
|
2014-11-22 23:55:17 +02:00
|
|
|
return installed_platforms
|
|
|
|
|
2014-11-29 22:39:44 +02:00
|
|
|
@classmethod
|
2015-03-16 14:15:57 +02:00
|
|
|
def newPlatform(cls, type_):
|
2014-11-29 22:39:44 +02:00
|
|
|
platforms = cls.get_platforms()
|
2015-03-16 14:15:57 +02:00
|
|
|
if type_ not in platforms:
|
|
|
|
raise exception.UnknownPlatform(type_)
|
2014-06-07 13:34:31 +03:00
|
|
|
|
2014-11-24 21:36:44 +02:00
|
|
|
_instance = getattr(
|
2015-03-16 14:15:57 +02:00
|
|
|
cls.load_module(type_, platforms[type_]),
|
|
|
|
cls.get_clsname(type_)
|
2014-11-24 21:36:44 +02:00
|
|
|
)()
|
|
|
|
assert isinstance(_instance, BasePlatform)
|
|
|
|
return _instance
|
2014-06-07 13:34:31 +03:00
|
|
|
|
|
|
|
|
|
|
|
class BasePlatform(object):
|
|
|
|
|
|
|
|
PACKAGES = {}
|
2015-02-19 22:02:50 +02:00
|
|
|
LINE_ERROR_RE = re.compile(r"(\s+error|error[:\s]+)", re.I)
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
self._found_error = False
|
2015-05-15 22:40:29 +02:00
|
|
|
self._last_echo_line = None
|
|
|
|
|
|
|
|
# 1 = errors
|
|
|
|
# 2 = 1 + warnings
|
|
|
|
# 3 = 2 + others
|
|
|
|
self._verbose_level = 3
|
2014-06-07 13:34:31 +03:00
|
|
|
|
2015-03-16 14:15:57 +02:00
|
|
|
def get_type(self):
|
2014-11-24 21:36:44 +02:00
|
|
|
return self.__class__.__name__[:-8].lower()
|
2014-06-07 13:34:31 +03:00
|
|
|
|
2015-03-16 14:15:57 +02:00
|
|
|
def get_name(self):
|
|
|
|
return self.get_type().title()
|
|
|
|
|
2014-11-22 23:55:17 +02:00
|
|
|
def get_build_script(self):
|
2015-02-15 23:53:15 +02:00
|
|
|
builtin = join(util.get_source_dir(), "builder", "scripts", "%s.py" %
|
2015-03-16 14:15:57 +02:00
|
|
|
self.get_type())
|
2014-11-22 23:55:17 +02:00
|
|
|
if isfile(builtin):
|
|
|
|
return builtin
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2015-03-16 12:47:43 +02:00
|
|
|
def get_description(self):
|
2014-06-12 23:29:47 +03:00
|
|
|
if self.__doc__:
|
2015-03-16 12:47:43 +02:00
|
|
|
doclines = [l.strip() for l in self.__doc__.splitlines() if
|
|
|
|
l.strip()]
|
|
|
|
return " ".join(doclines[:-1]).strip()
|
|
|
|
else:
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
def get_vendor_url(self):
|
|
|
|
if self.__doc__ and "http" in self.__doc__:
|
|
|
|
return self.__doc__[self.__doc__.index("http"):].strip()
|
2014-06-12 23:29:47 +03:00
|
|
|
else:
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2015-08-09 19:05:16 +03:00
|
|
|
def is_embedded(self):
|
|
|
|
for name, opts in self.get_packages().items():
|
|
|
|
if name == "framework-mbed" or opts.get("alias") == "uploader":
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
2014-11-22 23:55:17 +02:00
|
|
|
def get_packages(self):
|
|
|
|
return self.PACKAGES
|
|
|
|
|
2015-12-15 15:58:52 +02:00
|
|
|
def get_package_alias(self, pkgname):
|
|
|
|
return self.PACKAGES[pkgname].get("alias")
|
2014-07-30 23:39:01 +03:00
|
|
|
|
2014-07-30 23:08:36 +03:00
|
|
|
def pkg_aliases_to_names(self, aliases):
|
|
|
|
names = []
|
|
|
|
for alias in aliases:
|
|
|
|
name = alias
|
2014-11-22 23:55:17 +02:00
|
|
|
# lookup by package aliases
|
|
|
|
for _name, _opts in self.get_packages().items():
|
2015-12-15 15:58:52 +02:00
|
|
|
if _opts.get("alias") == alias:
|
|
|
|
name = None
|
|
|
|
names.append(_name)
|
|
|
|
# if alias is the right name
|
|
|
|
if name:
|
|
|
|
names.append(name)
|
2014-07-30 23:08:36 +03:00
|
|
|
return names
|
2014-07-30 22:40:11 +03:00
|
|
|
|
2015-07-17 14:50:06 +03:00
|
|
|
def get_default_packages(self):
|
|
|
|
return [k for k, v in self.get_packages().items()
|
|
|
|
if v.get("default", False)]
|
|
|
|
|
2014-11-22 23:55:17 +02:00
|
|
|
def get_installed_packages(self):
|
|
|
|
pm = PackageManager()
|
|
|
|
return [n for n in self.get_packages().keys() if pm.is_installed(n)]
|
|
|
|
|
2015-12-15 15:58:52 +02:00
|
|
|
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 []))
|
2014-06-07 13:34:31 +03:00
|
|
|
|
2014-07-30 22:40:11 +03:00
|
|
|
upkgs = with_packages | without_packages
|
2014-11-22 23:55:17 +02:00
|
|
|
ppkgs = set(self.get_packages().keys())
|
2014-07-30 23:08:36 +03:00
|
|
|
if not upkgs.issubset(ppkgs):
|
2014-12-03 14:18:22 +02:00
|
|
|
raise exception.UnknownPackage(", ".join(upkgs - ppkgs))
|
2014-06-07 13:34:31 +03:00
|
|
|
|
2014-07-30 22:40:11 +03:00
|
|
|
requirements = []
|
2014-11-22 23:55:17 +02:00
|
|
|
for name, opts in self.get_packages().items():
|
2014-06-07 13:34:31 +03:00
|
|
|
if name in without_packages:
|
|
|
|
continue
|
2014-07-30 22:40:11 +03:00
|
|
|
elif (name in with_packages or (not skip_default_packages and
|
2015-12-15 15:58:52 +02:00
|
|
|
opts.get("default"))):
|
2014-11-22 23:55:17 +02:00
|
|
|
requirements.append(name)
|
|
|
|
|
|
|
|
pm = PackageManager()
|
|
|
|
for name in requirements:
|
|
|
|
pm.install(name)
|
|
|
|
|
|
|
|
# register installed platform
|
2014-11-29 22:39:44 +02:00
|
|
|
data = get_state_item("installed_platforms", [])
|
2015-03-16 14:15:57 +02:00
|
|
|
if self.get_type() not in data:
|
|
|
|
data.append(self.get_type())
|
2014-11-29 22:39:44 +02:00
|
|
|
set_state_item("installed_platforms", data)
|
2014-06-07 13:34:31 +03:00
|
|
|
|
2014-07-30 22:40:11 +03:00
|
|
|
return len(requirements)
|
2014-06-13 20:47:02 +03:00
|
|
|
|
|
|
|
def uninstall(self):
|
2015-03-16 14:15:57 +02:00
|
|
|
platform = self.get_type()
|
2014-11-22 23:55:17 +02:00
|
|
|
installed_platforms = PlatformFactory.get_platforms(
|
|
|
|
installed=True).keys()
|
|
|
|
|
|
|
|
if platform not in installed_platforms:
|
2014-12-03 14:18:22 +02:00
|
|
|
raise exception.PlatformNotInstalledYet(platform)
|
2014-06-07 13:34:31 +03:00
|
|
|
|
2014-11-22 23:55:17 +02:00
|
|
|
deppkgs = set()
|
|
|
|
for item in installed_platforms:
|
|
|
|
if item == platform:
|
|
|
|
continue
|
2014-12-03 20:16:50 +02:00
|
|
|
p = PlatformFactory.newPlatform(item)
|
2014-11-22 23:55:17 +02:00
|
|
|
deppkgs = deppkgs.union(set(p.get_packages().keys()))
|
|
|
|
|
|
|
|
pm = PackageManager()
|
|
|
|
for name in self.get_packages().keys():
|
2014-11-24 22:24:19 +02:00
|
|
|
if not pm.is_installed(name) or name in deppkgs:
|
2014-11-22 23:55:17 +02:00
|
|
|
continue
|
|
|
|
pm.uninstall(name)
|
|
|
|
|
|
|
|
# unregister installed platform
|
2014-11-29 22:39:44 +02:00
|
|
|
installed_platforms.remove(platform)
|
|
|
|
set_state_item("installed_platforms", installed_platforms)
|
2014-06-13 20:47:02 +03:00
|
|
|
|
2014-06-07 13:34:31 +03:00
|
|
|
return True
|
|
|
|
|
2014-06-13 20:47:02 +03:00
|
|
|
def update(self):
|
2014-11-22 23:55:17 +02:00
|
|
|
pm = PackageManager()
|
|
|
|
for name in self.get_installed_packages():
|
|
|
|
pm.update(name)
|
2014-06-07 13:34:31 +03:00
|
|
|
|
2014-11-29 22:39:44 +02:00
|
|
|
def is_outdated(self):
|
|
|
|
pm = PackageManager()
|
|
|
|
obsolated = pm.get_outdated()
|
|
|
|
return not set(self.get_packages().keys()).isdisjoint(set(obsolated))
|
|
|
|
|
2015-12-15 15:58:52 +02:00
|
|
|
def configure_default_packages(self, envoptions, targets):
|
|
|
|
# enbale used frameworks
|
|
|
|
for pkg_name in self.pkg_aliases_to_names(["framework"]):
|
|
|
|
for framework in envoptions.get("framework", "").split(","):
|
|
|
|
framework = framework.lower().strip()
|
|
|
|
if not framework:
|
|
|
|
continue
|
|
|
|
if framework in pkg_name:
|
|
|
|
self.PACKAGES[pkg_name]['default'] = True
|
|
|
|
|
2015-12-26 14:47:42 +02:00
|
|
|
# append SCons tool
|
|
|
|
self.PACKAGES['tool-scons'] = {"default": True}
|
|
|
|
|
2015-12-15 15:58:52 +02:00
|
|
|
# enable upload tools for upload targets
|
2015-12-15 20:25:59 +02:00
|
|
|
if any(["upload" in t for t in targets] + ["program" in targets]):
|
2015-12-15 15:58:52 +02:00
|
|
|
for _name, _opts in self.PACKAGES.iteritems():
|
|
|
|
if _opts.get("alias") == "uploader":
|
|
|
|
self.PACKAGES[_name]['default'] = True
|
|
|
|
elif "uploadlazy" in targets:
|
|
|
|
# skip all packages, allow only upload tools
|
|
|
|
self.PACKAGES[_name]['default'] = False
|
|
|
|
|
2015-12-15 17:04:28 +02:00
|
|
|
def _install_default_packages(self):
|
2015-12-15 15:58:52 +02:00
|
|
|
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())
|
|
|
|
|
2015-05-15 22:40:29 +02:00
|
|
|
def run(self, variables, targets, verbose):
|
2014-06-07 13:34:31 +03:00
|
|
|
assert isinstance(variables, list)
|
|
|
|
assert isinstance(targets, list)
|
|
|
|
|
2015-12-15 15:58:52 +02:00
|
|
|
envoptions = {}
|
|
|
|
for v in variables:
|
|
|
|
_name, _value = v.split("=", 1)
|
|
|
|
envoptions[_name.lower()] = _value
|
2015-05-15 22:40:29 +02:00
|
|
|
|
2015-12-15 15:58:52 +02:00
|
|
|
self.configure_default_packages(envoptions, targets)
|
2015-12-15 17:04:28 +02:00
|
|
|
self._install_default_packages()
|
2014-11-22 23:55:17 +02:00
|
|
|
|
2015-12-15 15:58:52 +02:00
|
|
|
self._verbose_level = int(verbose)
|
2014-11-22 23:55:17 +02:00
|
|
|
|
2014-06-07 13:34:31 +03:00
|
|
|
if "clean" in targets:
|
|
|
|
targets.remove("clean")
|
|
|
|
targets.append("-c")
|
|
|
|
|
2015-12-15 15:58:52 +02:00
|
|
|
if "build_script" not in envoptions:
|
2014-11-22 23:55:17 +02:00
|
|
|
variables.append("BUILD_SCRIPT=%s" % self.get_build_script())
|
|
|
|
|
|
|
|
for v in variables:
|
|
|
|
if not v.startswith("BUILD_SCRIPT="):
|
|
|
|
continue
|
2015-12-15 15:58:52 +02:00
|
|
|
_, path = v.split("=", 1)
|
2014-11-22 23:55:17 +02:00
|
|
|
if not isfile(path):
|
2014-12-03 14:18:22 +02:00
|
|
|
raise exception.BuildScriptNotFound(path)
|
2014-11-22 23:55:17 +02:00
|
|
|
|
2014-12-03 14:18:22 +02:00
|
|
|
# append aliases of the installed packages
|
2015-12-15 15:58:52 +02:00
|
|
|
installed_packages = PackageManager.get_installed()
|
2014-11-22 23:55:17 +02:00
|
|
|
for name, options in self.get_packages().items():
|
2015-02-03 18:44:24 +02:00
|
|
|
if "alias" not in options or name not in installed_packages:
|
2014-11-22 23:55:17 +02:00
|
|
|
continue
|
|
|
|
variables.append(
|
|
|
|
"PIOPACKAGE_%s=%s" % (options['alias'].upper(), name))
|
|
|
|
|
2015-02-19 22:02:50 +02:00
|
|
|
self._found_error = False
|
2015-12-26 14:47:42 +02:00
|
|
|
result = self._run_scons(variables, targets)
|
2015-02-19 22:02:50 +02:00
|
|
|
assert "returncode" in result
|
2015-08-21 19:50:21 +03:00
|
|
|
# if self._found_error:
|
|
|
|
# result['returncode'] = 1
|
2014-06-13 20:47:02 +03:00
|
|
|
|
2015-05-15 22:40:29 +02:00
|
|
|
if self._last_echo_line == ".":
|
|
|
|
click.echo("")
|
|
|
|
|
2014-06-13 20:47:02 +03:00
|
|
|
return result
|
2015-02-15 23:53:15 +02:00
|
|
|
|
2015-12-26 14:47:42 +02:00
|
|
|
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)
|
|
|
|
|
|
|
|
result = util.exec_command(
|
|
|
|
[
|
|
|
|
os.path.normpath(sys.executable),
|
|
|
|
join(util.get_home_dir(), "packages", "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")
|
|
|
|
] + variables + targets,
|
|
|
|
stdout=util.AsyncPipe(self.on_run_out),
|
|
|
|
stderr=util.AsyncPipe(self.on_run_err)
|
|
|
|
)
|
|
|
|
return result
|
|
|
|
|
2015-05-15 22:40:29 +02:00
|
|
|
def on_run_out(self, line):
|
|
|
|
self._echo_line(line, level=3)
|
2015-02-15 23:53:15 +02:00
|
|
|
|
2015-05-15 22:40:29 +02:00
|
|
|
def on_run_err(self, line):
|
2015-02-19 22:02:50 +02:00
|
|
|
is_error = self.LINE_ERROR_RE.search(line) is not None
|
|
|
|
if is_error:
|
|
|
|
self._found_error = True
|
2015-05-15 22:40:29 +02:00
|
|
|
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)
|
2015-12-04 21:06:29 +02:00
|
|
|
|
2015-12-04 22:35:22 +02:00
|
|
|
@staticmethod
|
|
|
|
def get_job_nums():
|
2015-12-04 21:06:29 +02:00
|
|
|
try:
|
|
|
|
return cpu_count()
|
|
|
|
except NotImplementedError:
|
|
|
|
return 1
|