Use copy for custom includes (#568)

This commit is contained in:
Otto Winter 2019-05-29 19:30:35 +02:00
parent 5fca02c712
commit 4b7c5aa05c
No known key found for this signature in database
GPG key ID: DB66C0BE6013F97E
5 changed files with 51 additions and 15 deletions

View file

@ -612,9 +612,9 @@ def _format_vol_invalid(ex, config):
else: else:
message += u'[{}] is an invalid option for [{}]. Please check the indentation.'.format( message += u'[{}] is an invalid option for [{}]. Please check the indentation.'.format(
ex.path[-1], paren) ex.path[-1], paren)
elif u'extra keys not allowed' in ex.error_message: elif u'extra keys not allowed' in text_type(ex):
message += u'[{}] is an invalid option for [{}].'.format(ex.path[-1], paren) message += u'[{}] is an invalid option for [{}].'.format(ex.path[-1], paren)
elif u'required key not provided' in ex.error_message: elif u'required key not provided' in text_type(ex):
message += u"'{}' is a required option for [{}].".format(ex.path[-1], paren) message += u"'{}' is a required option for [{}].".format(ex.path[-1], paren)
else: else:
message += humanize_error(config, ex) message += humanize_error(config, ex)

View file

@ -20,7 +20,7 @@ from esphome.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY,
from esphome.core import CORE, HexInt, IPAddress, Lambda, TimePeriod, TimePeriodMicroseconds, \ from esphome.core import CORE, HexInt, IPAddress, Lambda, TimePeriod, TimePeriodMicroseconds, \
TimePeriodMilliseconds, TimePeriodSeconds, TimePeriodMinutes TimePeriodMilliseconds, TimePeriodSeconds, TimePeriodMinutes
from esphome.helpers import list_starts_with from esphome.helpers import list_starts_with
from esphome.py_compat import integer_types, string_types, text_type, IS_PY2 from esphome.py_compat import integer_types, string_types, text_type, IS_PY2, decode_text
from esphome.voluptuous_schema import _Schema from esphome.voluptuous_schema import _Schema
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -617,9 +617,9 @@ if IS_PY2:
# Override voluptuous invalid to unicode for py2 # Override voluptuous invalid to unicode for py2
def _vol_invalid_unicode(self): def _vol_invalid_unicode(self):
path = u' @ data[%s]' % u']['.join(map(repr, self.path)) \ path = u' @ data[%s]' % u']['.join(map(repr, self.path)) \
if self.path else '' if self.path else u''
# pylint: disable=no-member # pylint: disable=no-member
output = self.message output = decode_text(self.message)
if self.error_type: if self.error_type:
output += u' for ' + self.error_type output += u' for ' + self.error_type
return output + path return output + path

View file

@ -13,6 +13,7 @@ from esphome.const import ARDUINO_VERSION_ESP32_DEV, ARDUINO_VERSION_ESP8266_DEV
CONF_ESP8266_RESTORE_FROM_FLASH, __version__, ARDUINO_VERSION_ESP8266_2_3_0, \ CONF_ESP8266_RESTORE_FROM_FLASH, __version__, ARDUINO_VERSION_ESP8266_2_3_0, \
ARDUINO_VERSION_ESP8266_2_5_0, ARDUINO_VERSION_ESP8266_2_5_1, ARDUINO_VERSION_ESP8266_2_5_2 ARDUINO_VERSION_ESP8266_2_5_0, ARDUINO_VERSION_ESP8266_2_5_1, ARDUINO_VERSION_ESP8266_2_5_2
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
from esphome.helpers import copy_file_if_changed, walk_files
from esphome.pins import ESP8266_FLASH_SIZES, ESP8266_LD_SCRIPTS from esphome.pins import ESP8266_FLASH_SIZES, ESP8266_LD_SCRIPTS
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -59,6 +60,7 @@ PLATFORMIO_ESP8266_LUT = {
PLATFORMIO_ESP32_LUT = { PLATFORMIO_ESP32_LUT = {
'1.0.0': 'espressif32@1.4.0', '1.0.0': 'espressif32@1.4.0',
'1.0.1': 'espressif32@1.6.0', '1.0.1': 'espressif32@1.6.0',
'1.0.2': 'espressif32@1.8.0',
'RECOMMENDED': 'espressif32@1.6.0', 'RECOMMENDED': 'espressif32@1.6.0',
'LATEST': 'espressif32', 'LATEST': 'espressif32',
'DEV': ARDUINO_VERSION_ESP32_DEV, 'DEV': ARDUINO_VERSION_ESP32_DEV,
@ -91,6 +93,22 @@ def default_build_path():
return CORE.name return CORE.name
VALID_INCLUDE_EXTS = {'.h', '.hpp', '.tcc', '.ino', '.cpp', '.c'}
def valid_include(value):
try:
return cv.directory(value)
except cv.Invalid:
pass
value = cv.file_(value)
_, ext = os.path.splitext(value)
if ext not in VALID_INCLUDE_EXTS:
raise cv.Invalid(u"Include has invalid file extension {} - valid extensions are {}"
u"".format(ext, ', '.join(VALID_INCLUDE_EXTS)))
return value
CONFIG_SCHEMA = cv.Schema({ CONFIG_SCHEMA = cv.Schema({
cv.Required(CONF_NAME): cv.valid_name, cv.Required(CONF_NAME): cv.valid_name,
cv.Required(CONF_PLATFORM): cv.one_of('ESP8266', 'ESP32', upper=True), cv.Required(CONF_PLATFORM): cv.one_of('ESP8266', 'ESP32', upper=True),
@ -115,7 +133,7 @@ CONFIG_SCHEMA = cv.Schema({
cv.Optional(CONF_ON_LOOP): automation.validate_automation({ cv.Optional(CONF_ON_LOOP): automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LoopTrigger), cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LoopTrigger),
}), }),
cv.Optional(CONF_INCLUDES, default=[]): cv.ensure_list(cv.file_), cv.Optional(CONF_INCLUDES, default=[]): cv.ensure_list(valid_include),
cv.Optional(CONF_LIBRARIES, default=[]): cv.ensure_list(cv.string_strict), cv.Optional(CONF_LIBRARIES, default=[]): cv.ensure_list(cv.string_strict),
cv.Optional('esphome_core_version'): cv.invalid("The esphome_core_version option has been " cv.Optional('esphome_core_version'): cv.invalid("The esphome_core_version option has been "
@ -153,13 +171,31 @@ def preload_core_config(config):
CORE.build_path = CORE.relative_config_path(out2[CONF_BUILD_PATH]) CORE.build_path = CORE.relative_config_path(out2[CONF_BUILD_PATH])
def include_file(path, basename):
parts = basename.split(os.path.sep)
dst = CORE.relative_src_path(*parts)
copy_file_if_changed(path, dst)
_, ext = os.path.splitext(path)
if ext in ['.h', '.hpp', '.tcc']:
# Header, add include statement
cg.add_global(cg.RawStatement(u'#include "{}"'.format(basename)))
@coroutine_with_priority(-1000.0) @coroutine_with_priority(-1000.0)
def add_includes(includes): def add_includes(includes):
# Add includes at the very end, so that the included files can access global variables # Add includes at the very end, so that the included files can access global variables
for include in includes: for include in includes:
path = CORE.relative_config_path(include) path = CORE.relative_config_path(include)
res = os.path.relpath(path, CORE.relative_build_path('src')).replace(os.path.sep, '/') if os.path.isdir(path):
cg.add_global(cg.RawStatement(u'#include "{}"'.format(res))) # Directory, copy tree
for p in walk_files(path):
basename = os.path.relpath(p, os.path.dirname(path))
include_file(p, basename)
else:
# Copy file
basename = os.path.basename(path)
include_file(path, basename)
@coroutine_with_priority(100.0) @coroutine_with_priority(100.0)

View file

@ -157,6 +157,12 @@ def copy_file_if_changed(src, dst):
write_file(dst, src_text) write_file(dst, src_text)
def walk_files(path):
for root, _, files in os.walk(path):
for name in files:
yield os.path.join(root, name)
def read_file(path): def read_file(path):
try: try:
with codecs.open(path, 'r', encoding='utf-8') as f_handle: with codecs.open(path, 'r', encoding='utf-8') as f_handle:

View file

@ -8,7 +8,7 @@ from esphome.config import iter_components
from esphome.const import CONF_BOARD_FLASH_MODE, CONF_ESPHOME, CONF_PLATFORMIO_OPTIONS, \ from esphome.const import CONF_BOARD_FLASH_MODE, CONF_ESPHOME, CONF_PLATFORMIO_OPTIONS, \
HEADER_FILE_EXTENSIONS, SOURCE_FILE_EXTENSIONS HEADER_FILE_EXTENSIONS, SOURCE_FILE_EXTENSIONS
from esphome.core import CORE, EsphomeError from esphome.core import CORE, EsphomeError
from esphome.helpers import mkdir_p, read_file, write_file_if_changed from esphome.helpers import mkdir_p, read_file, write_file_if_changed, walk_files
from esphome.storage_json import StorageJSON, storage_path from esphome.storage_json import StorageJSON, storage_path
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -281,12 +281,6 @@ or use the custom_components folder.
""" """
def walk_files(path):
for root, _, files in os.walk(path):
for name in files:
yield os.path.join(root, name)
def copy_src_tree(): def copy_src_tree():
import filecmp import filecmp
import shutil import shutil