From f35f6d23489324066e8a4de51b755077cbc36564 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Wed, 29 May 2019 19:30:35 +0200 Subject: [PATCH] Use copy for custom includes (#568) --- esphome/config.py | 4 ++-- esphome/config_validation.py | 6 +++--- esphome/core_config.py | 42 +++++++++++++++++++++++++++++++++--- esphome/helpers.py | 6 ++++++ esphome/writer.py | 8 +------ 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/esphome/config.py b/esphome/config.py index debd261b41..9b34d53200 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -612,9 +612,9 @@ def _format_vol_invalid(ex, config): else: message += u'[{}] is an invalid option for [{}]. Please check the indentation.'.format( 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) - 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) else: message += humanize_error(config, ex) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 3fcc4d05f4..cc49144d86 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -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, \ TimePeriodMilliseconds, TimePeriodSeconds, TimePeriodMinutes 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 _LOGGER = logging.getLogger(__name__) @@ -617,9 +617,9 @@ if IS_PY2: # Override voluptuous invalid to unicode for py2 def _vol_invalid_unicode(self): path = u' @ data[%s]' % u']['.join(map(repr, self.path)) \ - if self.path else '' + if self.path else u'' # pylint: disable=no-member - output = self.message + output = decode_text(self.message) if self.error_type: output += u' for ' + self.error_type return output + path diff --git a/esphome/core_config.py b/esphome/core_config.py index d02b7c98de..28f2254c65 100644 --- a/esphome/core_config.py +++ b/esphome/core_config.py @@ -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, \ 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.helpers import copy_file_if_changed, walk_files from esphome.pins import ESP8266_FLASH_SIZES, ESP8266_LD_SCRIPTS _LOGGER = logging.getLogger(__name__) @@ -59,6 +60,7 @@ PLATFORMIO_ESP8266_LUT = { PLATFORMIO_ESP32_LUT = { '1.0.0': 'espressif32@1.4.0', '1.0.1': 'espressif32@1.6.0', + '1.0.2': 'espressif32@1.8.0', 'RECOMMENDED': 'espressif32@1.6.0', 'LATEST': 'espressif32', 'DEV': ARDUINO_VERSION_ESP32_DEV, @@ -91,6 +93,22 @@ def default_build_path(): 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({ cv.Required(CONF_NAME): cv.valid_name, 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.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('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]) +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) def add_includes(includes): # Add includes at the very end, so that the included files can access global variables for include in includes: path = CORE.relative_config_path(include) - res = os.path.relpath(path, CORE.relative_build_path('src')).replace(os.path.sep, '/') - cg.add_global(cg.RawStatement(u'#include "{}"'.format(res))) + if os.path.isdir(path): + # 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) diff --git a/esphome/helpers.py b/esphome/helpers.py index b3e7012c29..e38829af2b 100644 --- a/esphome/helpers.py +++ b/esphome/helpers.py @@ -157,6 +157,12 @@ def copy_file_if_changed(src, dst): 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): try: with codecs.open(path, 'r', encoding='utf-8') as f_handle: diff --git a/esphome/writer.py b/esphome/writer.py index ec99ade041..0f27530766 100644 --- a/esphome/writer.py +++ b/esphome/writer.py @@ -8,7 +8,7 @@ from esphome.config import iter_components from esphome.const import CONF_BOARD_FLASH_MODE, CONF_ESPHOME, CONF_PLATFORMIO_OPTIONS, \ HEADER_FILE_EXTENSIONS, SOURCE_FILE_EXTENSIONS 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 _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(): import filecmp import shutil