diff --git a/esphomeyaml/__main__.py b/esphomeyaml/__main__.py index 8c814446ca..8bd3463780 100644 --- a/esphomeyaml/__main__.py +++ b/esphomeyaml/__main__.py @@ -355,6 +355,17 @@ def command_version(args): return 0 +def command_clean(args, config): + build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH]) + try: + writer.clean_build(build_path) + except OSError as err: + _LOGGER.error("Error deleting build files: %s", err) + return 1 + _LOGGER.info("Done!") + return 0 + + def command_dashboard(args): from esphomeyaml.dashboard import dashboard @@ -375,6 +386,7 @@ POST_CONFIG_ACTIONS = { 'run': command_run, 'clean-mqtt': command_clean_mqtt, 'mqtt-fingerprint': command_mqtt_fingerprint, + 'clean': command_clean, } @@ -445,6 +457,8 @@ def parse_args(argv): subparsers.add_parser('version', help="Print the esphomeyaml version and exit.") + subparsers.add_parser('clean', help="Delete all temporary build files.") + dashboard = subparsers.add_parser('dashboard', help="Create a simple webserver for a dashboard.") dashboard.add_argument("--port", help="The HTTP port to open connections on.", type=int, diff --git a/esphomeyaml/dashboard/dashboard.py b/esphomeyaml/dashboard/dashboard.py index dfa079392b..f9739d24b9 100644 --- a/esphomeyaml/dashboard/dashboard.py +++ b/esphomeyaml/dashboard/dashboard.py @@ -124,6 +124,13 @@ class EsphomeyamlCleanMqttHandler(EsphomeyamlCommandWebSocket): return ["esphomeyaml", config_file, "clean-mqtt"] +class EsphomeyamlCleanHandler(EsphomeyamlCommandWebSocket): + def build_command(self, message): + js = json.loads(message) + config_file = os.path.join(CONFIG_DIR, js['configuration']) + return ["esphomeyaml", config_file, "clean"] + + class SerialPortRequestHandler(BaseHandler): def get(self): if not self.is_authenticated(): @@ -221,6 +228,7 @@ def make_app(debug=False): (r"/compile", EsphomeyamlCompileHandler), (r"/validate", EsphomeyamlValidateHandler), (r"/clean-mqtt", EsphomeyamlCleanMqttHandler), + (r"/clean", EsphomeyamlCleanHandler), (r"/download.bin", DownloadBinaryRequestHandler), (r"/serial-ports", SerialPortRequestHandler), (r"/wizard.html", WizardRequestHandler), diff --git a/esphomeyaml/dashboard/templates/index.html b/esphomeyaml/dashboard/templates/index.html index a13891f16f..7044e9f628 100644 --- a/esphomeyaml/dashboard/templates/index.html +++ b/esphomeyaml/dashboard/templates/index.html @@ -220,6 +220,7 @@
@@ -484,6 +485,18 @@ + + add @@ -849,6 +862,54 @@ }); }); + const cleanModalElem = document.getElementById("modal-clean"); + + document.querySelectorAll(".action-clean").forEach((btn) => { + btn.addEventListener('click', (e) => { + configuration = e.target.getAttribute('data-node'); + const modalInstance = M.Modal.getInstance(cleanModalElem); + const log = cleanModalElem.querySelector(".log"); + log.innerHTML = ""; + const stopLogsButton = cleanModalElem.querySelector(".stop-logs"); + let stopped = false; + stopLogsButton.innerHTML = "Stop"; + modalInstance.open(); + + const filenameField = cleanModalElem.querySelector('.filename'); + filenameField.innerHTML = configuration; + + const logSocket = new WebSocket(wsUrl + "/clean"); + logSocket.addEventListener('message', (event) => { + const data = JSON.parse(event.data); + if (data.event === "line") { + const msg = data.data; + log.innerHTML += colorReplace(msg); + } else if (data.event === "exit") { + if (data.code === 0) { + M.toast({html: "Program exited successfully."}); + downloadButton.classList.remove('disabled'); + } else { + M.toast({html: `Program failed with code ${data.code}`}); + } + stopLogsButton.innerHTML = "Close"; + stopped = true; + } + }); + logSocket.addEventListener('open', () => { + const msg = JSON.stringify({configuration: configuration}); + logSocket.send(msg); + }); + logSocket.addEventListener('close', () => { + if (!stopped) { + M.toast({html: 'Terminated process.'}); + } + }); + modalInstance.options.onCloseStart = () => { + logSocket.close(); + }; + }); + }); + const modalSetupElem = document.getElementById("modal-wizard"); const setupWizardStart = document.getElementById('setup-wizard-start'); const startWizard = () => { diff --git a/esphomeyaml/writer.py b/esphomeyaml/writer.py index d17beff27f..c83078cbaf 100644 --- a/esphomeyaml/writer.py +++ b/esphomeyaml/writer.py @@ -3,7 +3,9 @@ from __future__ import print_function import codecs import errno import json +import logging import os +import shutil from esphomeyaml import core from esphomeyaml.config import iter_components @@ -14,6 +16,8 @@ from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core_config import VERSION_REGEX from esphomeyaml.helpers import relative_path +_LOGGER = logging.getLogger(__name__) + CPP_AUTO_GENERATE_BEGIN = u'// ========== AUTO GENERATED CODE BEGIN ===========' CPP_AUTO_GENERATE_END = u'// =========== AUTO GENERATED CODE END ============' INI_AUTO_GENERATE_BEGIN = u'; ========== AUTO GENERATED CODE BEGIN ===========' @@ -111,17 +115,19 @@ def get_ini_content(config, path): lib_version = config[CONF_ESPHOMEYAML][CONF_ESPHOMELIB_VERSION] lib_path = os.path.join(path, 'lib') dst_path = os.path.join(lib_path, 'esphomelib') + this_version = None if CONF_REPOSITORY in lib_version: tag = next((lib_version[x] for x in (CONF_COMMIT, CONF_BRANCH, CONF_TAG) if x in lib_version), None) - if tag is None: - lib_deps.add(lib_version[CONF_REPOSITORY]) - else: - lib_deps.add(lib_version[CONF_REPOSITORY] + '#' + tag) + this_version = lib_version[CONF_REPOSITORY] + if tag is not None: + this_version += '#' + tag + lib_deps.add(this_version) if os.path.islink(dst_path): os.unlink(dst_path) - else: - src_path = relative_path(lib_version[CONF_LOCAL]) + elif CONF_LOCAL in lib_version: + this_version = lib_version[CONF_LOCAL] + src_path = relative_path(this_version) do_write = True if os.path.islink(dst_path): old_path = os.path.join(os.readlink(dst_path), lib_path) @@ -144,6 +150,25 @@ def get_ini_content(config, path): lib_deps.add(dep['name'] + '@' + dep['version']) else: lib_deps.add(dep['version']) + else: + this_version = lib_version + lib_deps.add(lib_version) + + version_file = os.path.join(path, '.esphomelib_version') + version = None + if os.path.isfile(version_file): + with open(version_file, 'r') as ver_f: + version = ver_f.read() + + if version != this_version: + _LOGGER.info("Esphomelib version change detected. Cleaning build files...") + try: + clean_build(path) + except OSError as err: + _LOGGER.warn("Error deleting build files (%s)! Ignoring...", err) + + with open(version_file, 'w') as ver_f: + ver_f.write(this_version) lib_deps |= get_build_flags(config, 'LIB_DEPS') lib_deps |= get_build_flags(config, 'lib_deps') @@ -207,7 +232,6 @@ def write_platformio_ini(content, path): content_format = find_begin_end(text, INI_AUTO_GENERATE_BEGIN, INI_AUTO_GENERATE_END) else: prev_file = None - mkdir_p(os.path.dirname(path)) content_format = INI_BASE_FORMAT full_file = content_format[0] + INI_AUTO_GENERATE_BEGIN + '\n' + \ content + INI_AUTO_GENERATE_END + content_format[1] @@ -218,6 +242,7 @@ def write_platformio_ini(content, path): def write_platformio_project(config, path): + mkdir_p(path) platformio_ini = os.path.join(path, 'platformio.ini') content = get_ini_content(config, path) if 'esp32_ble_beacon' in config or 'esp32_ble_tracker' in config: @@ -268,3 +293,11 @@ def determine_platformio_version_settings(): settings['flash_mode_key'] = 'board_build.flash_mode' return settings + + +def clean_build(build_path): + for directory in ('.piolibdeps', '.pioenvs'): + dir_path = os.path.join(build_path, directory) + if os.path.isdir(dir_path): + _LOGGER.info("Deleting %s", dir_path) + shutil.rmtree(dir_path)