From 97826b2f3b7edf4196395fac310d6061cfa3725d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Wed, 8 Jul 2015 16:26:08 +0200 Subject: [PATCH] Fix: More resilience against missing plugin assets Two changes: * Asset existence will now be checked before they get included in the assets to bundle by webassets, logging a warning if a file isn't present. * Monkey-patched webassets filter chain to not die when a file doesn't exist, but to log an error instead and just return an empty file instead. (cherry picked from commit 2a5ec33) --- src/octoprint/server/__init__.py | 4 +++ src/octoprint/server/util/flask.py | 44 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/octoprint/server/__init__.py b/src/octoprint/server/__init__.py index 7839a9bd..b99358f4 100644 --- a/src/octoprint/server/__init__.py +++ b/src/octoprint/server/__init__.py @@ -544,6 +544,9 @@ class Server(): }, "tornado.general": { "level": "INFO" + }, + "octoprint.server.util.flask": { + "level": "WARN" } }, "root": { @@ -712,6 +715,7 @@ class Server(): global pluginManager util.flask.fix_webassets_cache() + util.flask.fix_webassets_filtertool() base_folder = settings().getBaseFolder("generated") diff --git a/src/octoprint/server/util/flask.py b/src/octoprint/server/util/flask.py index 0f3d4a05..75f03d24 100644 --- a/src/octoprint/server/util/flask.py +++ b/src/octoprint/server/util/flask.py @@ -19,6 +19,7 @@ import uuid import threading import logging import netaddr +import os from octoprint.settings import settings import octoprint.server @@ -174,6 +175,34 @@ def fix_webassets_cache(): cache.FilesystemCache.set = fixed_set cache.FilesystemCache.get = fixed_get +def fix_webassets_filtertool(): + from webassets.merge import FilterTool, log, MemoryHunk + + error_logger = logging.getLogger(__name__ + ".fix_webassets_filtertool") + + def fixed_wrap_cache(self, key, func): + """Return cache value ``key``, or run ``func``. + """ + if self.cache: + if not self.no_cache_read: + log.debug('Checking cache for key %s', key) + content = self.cache.get(key) + if not content in (False, None): + log.debug('Using cached result for %s', key) + return MemoryHunk(content) + + try: + content = func().getvalue() + if self.cache: + log.debug('Storing result in cache with key %s', key,) + self.cache.set(key, content) + return MemoryHunk(content) + except: + error_logger.exception("Got an exception while trying to apply filter, ignoring file") + return MemoryHunk("") + + FilterTool._wrap_cache = fixed_wrap_cache + #~~ passive login helper def passive_login(): @@ -535,6 +564,8 @@ class SettingsCheckUpdater(webassets.updater.BaseUpdater): ##~~ plugin assets collector def collect_plugin_assets(enable_gcodeviewer=True, enable_timelapse=True, preferred_stylesheet="css"): + logger = logging.getLogger(__name__ + ".collect_plugin_assets") + supported_stylesheets = ("css", "less") assets = dict( js=[], @@ -578,13 +609,24 @@ def collect_plugin_assets(enable_gcodeviewer=True, enable_timelapse=True, prefer for implementation in asset_plugins: name = implementation._identifier all_assets = implementation.get_assets() + basefolder = implementation.get_asset_folder() + + def asset_exists(category, asset): + exists = os.path.exists(os.path.join(basefolder, asset)) + if not exists: + logger.warn("Plugin {} is referring to non existing {} asset {}".format(name, category, asset)) + return exists if "js" in all_assets: for asset in all_assets["js"]: + if not asset_exists("js", asset): + continue assets["js"].append('plugin/{name}/{asset}'.format(**locals())) if preferred_stylesheet in all_assets: for asset in all_assets[preferred_stylesheet]: + if not asset_exists(preferred_stylesheet, asset): + continue assets[preferred_stylesheet].append('plugin/{name}/{asset}'.format(**locals())) else: for stylesheet in supported_stylesheets: @@ -592,6 +634,8 @@ def collect_plugin_assets(enable_gcodeviewer=True, enable_timelapse=True, prefer continue for asset in all_assets[stylesheet]: + if not asset_exists(stylesheet, asset): + continue assets[stylesheet].append('plugin/{name}/{asset}'.format(**locals())) break