From e8123a6ab1d4eab03153ee04515219eb9dd4bfe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 10 Oct 2016 19:27:18 +0200 Subject: [PATCH 01/10] Custom logging handler that cleans files on startup --- src/octoprint/logging/__init__.py | 4 ++++ src/octoprint/logging/handlers.py | 16 ++++++++++++++++ src/octoprint/server/__init__.py | 4 ++-- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 src/octoprint/logging/__init__.py create mode 100644 src/octoprint/logging/handlers.py diff --git a/src/octoprint/logging/__init__.py b/src/octoprint/logging/__init__.py new file mode 100644 index 00000000..6e016b16 --- /dev/null +++ b/src/octoprint/logging/__init__.py @@ -0,0 +1,4 @@ +# coding=utf-8 +from __future__ import absolute_import + +from . import handlers diff --git a/src/octoprint/logging/handlers.py b/src/octoprint/logging/handlers.py new file mode 100644 index 00000000..ad4fcadb --- /dev/null +++ b/src/octoprint/logging/handlers.py @@ -0,0 +1,16 @@ +# coding=utf-8 +from __future__ import absolute_import + +import logging.handlers +import os + +class CleaningTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler): + + def __init__(self, *args, **kwargs): + logging.handlers.TimedRotatingFileHandler.__init__(self, *args, **kwargs) + + # clean up old files on handler start + if self.backupCount > 0: + for s in self.getFilesToDelete(): + os.remove(s) + diff --git a/src/octoprint/server/__init__.py b/src/octoprint/server/__init__.py index 902930df..e74c19a8 100644 --- a/src/octoprint/server/__init__.py +++ b/src/octoprint/server/__init__.py @@ -574,11 +574,11 @@ class Server(object): "stream": "ext://sys.stdout" }, "file": { - "class": "logging.handlers.TimedRotatingFileHandler", + "class": "octoprint.logging.handlers.CleaningTimedRotatingFileHandler", "level": "DEBUG", "formatter": "simple", "when": "D", - "backupCount": "1", + "backupCount": 7, "filename": os.path.join(settings().getBaseFolder("logs"), "octoprint.log") }, "serialFile": { From 139b2277d115f22031bf1dddb4d00530b9ce59bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 10 Oct 2016 19:45:34 +0200 Subject: [PATCH 02/10] Fix missing absolute import declarations --- src/octoprint/__init__.py | 2 ++ src/octoprint/timelapse.py | 1 + src/octoprint/util/__init__.py | 2 ++ 3 files changed, 5 insertions(+) diff --git a/src/octoprint/__init__.py b/src/octoprint/__init__.py index df198672..d45166b5 100644 --- a/src/octoprint/__init__.py +++ b/src/octoprint/__init__.py @@ -1,4 +1,6 @@ #!/usr/bin/env python +from __future__ import absolute_import + import sys from octoprint.daemon import Daemon from octoprint.server import Server diff --git a/src/octoprint/timelapse.py b/src/octoprint/timelapse.py index 026a897d..3e404fcc 100644 --- a/src/octoprint/timelapse.py +++ b/src/octoprint/timelapse.py @@ -1,4 +1,5 @@ # coding=utf-8 +from __future__ import absolute_import __author__ = "Gina Häußge " __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html' diff --git a/src/octoprint/util/__init__.py b/src/octoprint/util/__init__.py index 97aa8a45..afd3ff41 100644 --- a/src/octoprint/util/__init__.py +++ b/src/octoprint/util/__init__.py @@ -1,4 +1,6 @@ # coding=utf-8 +from __future__ import absolute_import + """ This module bundles commonly used utility methods or helper classes that are used in multiple places withing OctoPrint's source code. From 343631b3c6ce63776be3b58c3b557fa2baa3a214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Tue, 11 Oct 2016 10:53:37 +0200 Subject: [PATCH 03/10] Custom SerialLoggingHandler Does roll overs on next connections to the printer --- src/octoprint/logging/handlers.py | 67 +++++++++++++++++++++++++++++++ src/octoprint/printer/standard.py | 4 ++ src/octoprint/server/__init__.py | 12 +++--- 3 files changed, 78 insertions(+), 5 deletions(-) diff --git a/src/octoprint/logging/handlers.py b/src/octoprint/logging/handlers.py index ad4fcadb..fb613429 100644 --- a/src/octoprint/logging/handlers.py +++ b/src/octoprint/logging/handlers.py @@ -3,6 +3,8 @@ from __future__ import absolute_import import logging.handlers import os +import re +import time class CleaningTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler): @@ -14,3 +16,68 @@ class CleaningTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler for s in self.getFilesToDelete(): os.remove(s) + +class SerialLogHandler(logging.handlers.RotatingFileHandler): + + _do_rollover = False + _suffix_template = "%Y-%m-%d_%H-%M-%S" + _file_pattern = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}$") + + @classmethod + def on_open_connection(cls): + cls._do_rollover = True + + def __init__(self, *args, **kwargs): + logging.handlers.RotatingFileHandler.__init__(self, *args, **kwargs) + self.cleanupFiles() + + def emit(self, record): + logging.handlers.RotatingFileHandler.emit(self, record) + + def shouldRollover(self, record): + return self.__class__._do_rollover + + def getFilesToDelete(self): + """ + Determine the files to delete when rolling over. + """ + dirName, baseName = os.path.split(self.baseFilename) + fileNames = os.listdir(dirName) + result = [] + prefix = baseName + "." + plen = len(prefix) + for fileName in fileNames: + if fileName[:plen] == prefix: + suffix = fileName[plen:] + if self.__class__._file_pattern.match(suffix): + result.append(os.path.join(dirName, fileName)) + result.sort() + if len(result) < self.backupCount: + result = [] + else: + result = result[:len(result) - self.backupCount] + return result + + def cleanupFiles(self): + if self.backupCount > 0: + for path in self.getFilesToDelete(): + os.remove(path) + + def doRollover(self): + self.__class__._do_rollover = False + + if self.stream: + self.stream.close() + self.stream = None + + if os.path.exists(self.baseFilename): + # figure out creation date/time to use for file suffix + t = time.localtime(os.stat(self.baseFilename).st_mtime) + dfn = self.baseFilename + "." + time.strftime(self.__class__._suffix_template, t) + if os.path.exists(dfn): + os.remove(dfn) + os.rename(self.baseFilename, dfn) + + self.cleanupFiles() + if not self.delay: + self.stream = self._open() diff --git a/src/octoprint/printer/standard.py b/src/octoprint/printer/standard.py index 83b81a9f..8281aad1 100644 --- a/src/octoprint/printer/standard.py +++ b/src/octoprint/printer/standard.py @@ -194,6 +194,10 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback): if self._comm is not None: self._comm.close() self._printerProfileManager.select(profile) + + from octoprint.logging.handlers import SerialLogHandler + SerialLogHandler.on_open_connection() + self._comm = comm.MachineCom(port, baudrate, callbackObject=self, printerProfileManager=self._printerProfileManager) def disconnect(self): diff --git a/src/octoprint/server/__init__.py b/src/octoprint/server/__init__.py index e74c19a8..b076670b 100644 --- a/src/octoprint/server/__init__.py +++ b/src/octoprint/server/__init__.py @@ -564,6 +564,9 @@ class Server(object): "formatters": { "simple": { "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + }, + "serial": { + "format": "%(asctime)s - %(message)s" } }, "handlers": { @@ -578,14 +581,14 @@ class Server(object): "level": "DEBUG", "formatter": "simple", "when": "D", - "backupCount": 7, + "backupCount": 6, "filename": os.path.join(settings().getBaseFolder("logs"), "octoprint.log") }, "serialFile": { - "class": "logging.handlers.RotatingFileHandler", + "class": "octoprint.logging.handlers.SerialLogHandler", "level": "DEBUG", - "formatter": "simple", - "maxBytes": 2 * 1024 * 1024, # let's limit the serial log to 2MB in size + "formatter": "serial", + "backupCount": 3, "filename": os.path.join(settings().getBaseFolder("logs"), "serial.log") } }, @@ -633,7 +636,6 @@ class Server(object): if settings().getBoolean(["serial", "log"]): # enable debug logging to serial.log logging.getLogger("SERIAL").setLevel(logging.DEBUG) - logging.getLogger("SERIAL").debug("Enabling serial logging") def _setup_app(self, app): from octoprint.server.util.flask import ReverseProxiedEnvironment, OctoPrintFlaskRequest, OctoPrintFlaskResponse From 688a998dd249f77a827215b562cc976f55688fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Tue, 11 Oct 2016 10:54:16 +0200 Subject: [PATCH 04/10] Use CleaningTimedRotatingFileHandler in bundled plugins --- src/octoprint/plugins/cura/__init__.py | 3 ++- src/octoprint/plugins/pluginmanager/__init__.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/octoprint/plugins/cura/__init__.py b/src/octoprint/plugins/cura/__init__.py index bbce724f..773f62f2 100644 --- a/src/octoprint/plugins/cura/__init__.py +++ b/src/octoprint/plugins/cura/__init__.py @@ -46,7 +46,8 @@ class CuraPlugin(octoprint.plugin.SlicerPlugin, def on_startup(self, host, port): # setup our custom logger - cura_logging_handler = logging.handlers.RotatingFileHandler(self._settings.get_plugin_logfile_path(postfix="engine"), maxBytes=2*1024*1024) + from octoprint.logging.handlers import CleaningTimedRotatingFileHandler + cura_logging_handler = CleaningTimedRotatingFileHandler(self._settings.get_plugin_logfile_path(postfix="engine"), when="D", backupCount=3) cura_logging_handler.setFormatter(logging.Formatter("%(asctime)s %(message)s")) cura_logging_handler.setLevel(logging.DEBUG) diff --git a/src/octoprint/plugins/pluginmanager/__init__.py b/src/octoprint/plugins/pluginmanager/__init__.py index eb990d68..c76fbb39 100644 --- a/src/octoprint/plugins/pluginmanager/__init__.py +++ b/src/octoprint/plugins/pluginmanager/__init__.py @@ -65,7 +65,8 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin, ##~~ StartupPlugin def on_startup(self, host, port): - console_logging_handler = logging.handlers.RotatingFileHandler(self._settings.get_plugin_logfile_path(postfix="console"), maxBytes=2*1024*1024) + from octoprint.logging.handlers import CleaningTimedRotatingFileHandler + console_logging_handler = CleaningTimedRotatingFileHandler(self._settings.get_plugin_logfile_path(postfix="console"), when="D", backupCount=3) console_logging_handler.setFormatter(logging.Formatter("%(asctime)s %(message)s")) console_logging_handler.setLevel(logging.DEBUG) From 28de87441f99bd2f84274087d144016180a27c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Wed, 12 Oct 2016 16:50:22 +0200 Subject: [PATCH 05/10] Preparing release of 1.2.17 --- CHANGELOG.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4be9deaf..10fd7102 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # OctoPrint Changelog -## 1.2.17rc1 (2016-10-06) +## 1.2.17 (2016-10-12) ### Improvements @@ -17,7 +17,12 @@ * Fixed broken filter toggling on ``ItemListHelper`` class used for various lists throughout the web interface * Fixed an issue with the preliminary page never reporting that the server is now up if the page generated during preliminary caching had no cache headers set (e.g. because it contained the first run setup wizard) -([Commits](https://github.com/foosel/OctoPrint/compare/1.2.16...1.2.17rc1)) +### More information + + * [Commits](https://github.com/foosel/OctoPrint/compare/1.2.16...1.2.17) + * Release Candidates: + * [1.2.17rc1](https://github.com/foosel/OctoPrint/releases/tag/1.2.17rc1) + ## 1.2.16 (2016-09-23) From 3d26e478e3d80f44009efce21fa76e27f655c7f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Wed, 12 Oct 2016 18:13:46 +0200 Subject: [PATCH 06/10] Fix a bug causing the update of OctoPrint to not work under certain circumstances The bug only manifests if a user had installed 1.2.16 earlier and never once hit "Save" in the settings before attempting to update to 1.2.17. With 1.2.16 the updater script and settings for OctoPrint's own update mechanism were changed to prefer "checkout_folder" instead of "update_folder". In earlier versions however "update_folder" was still used. Saving settings even once (even without any changes!) will migrate the data. But if that's not done a KeyError will be raised when trying to retrieve "update_folder" from the check config, with "checkout_folder" as its fallback. Rather stupid error really. --- src/octoprint/plugins/softwareupdate/updaters/update_script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/octoprint/plugins/softwareupdate/updaters/update_script.py b/src/octoprint/plugins/softwareupdate/updaters/update_script.py index 050b1968..b694643e 100644 --- a/src/octoprint/plugins/softwareupdate/updaters/update_script.py +++ b/src/octoprint/plugins/softwareupdate/updaters/update_script.py @@ -35,7 +35,7 @@ def perform_update(target, check, target_version): update_script = check["update_script"] update_branch = check.get("update_branch", "") force_exact_version = check.get("force_exact_version", False) - folder = check.get("update_folder", check["checkout_folder"]) + folder = check.get("update_folder", check.get("checkout_folder")) # either should be set, tested above pre_update_script = check.get("pre_update_script", None) post_update_script = check.get("post_update_script", None) From 982d121d3b49cbcbcbef274fa55cdbb044cec67a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Wed, 12 Oct 2016 18:36:41 +0200 Subject: [PATCH 07/10] Revert "Preparing release of 1.2.17" This reverts commit 28de87441f99bd2f84274087d144016180a27c17. --- CHANGELOG.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10fd7102..4be9deaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # OctoPrint Changelog -## 1.2.17 (2016-10-12) +## 1.2.17rc1 (2016-10-06) ### Improvements @@ -17,12 +17,7 @@ * Fixed broken filter toggling on ``ItemListHelper`` class used for various lists throughout the web interface * Fixed an issue with the preliminary page never reporting that the server is now up if the page generated during preliminary caching had no cache headers set (e.g. because it contained the first run setup wizard) -### More information - - * [Commits](https://github.com/foosel/OctoPrint/compare/1.2.16...1.2.17) - * Release Candidates: - * [1.2.17rc1](https://github.com/foosel/OctoPrint/releases/tag/1.2.17rc1) - +([Commits](https://github.com/foosel/OctoPrint/compare/1.2.16...1.2.17rc1)) ## 1.2.16 (2016-09-23) From 1370c7a9cc9adba697a97c8c913ccaf7db51ae4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Thu, 13 Oct 2016 12:03:05 +0200 Subject: [PATCH 08/10] Inject plugin_info object into plugin implementations as well --- docs/plugins/concepts.rst | 2 ++ src/octoprint/plugin/core.py | 1 + 2 files changed, 3 insertions(+) diff --git a/docs/plugins/concepts.rst b/docs/plugins/concepts.rst index 42b66d37..947b0ed7 100644 --- a/docs/plugins/concepts.rst +++ b/docs/plugins/concepts.rst @@ -299,6 +299,8 @@ An overview of these properties follows. The plugin's name, as taken from either the ``__plugin_name__`` control property or the package info. ``self._plugin_version`` The plugin's version, as taken from either the ``__plugin_version__`` control property or the package info. +``self._plugin_info`` + The :class:`octoprint.plugin.core.PluginInfo` object associated with the plugin. ``self._basefolder`` The plugin's base folder where it's installed. Can be used to refer to files relative to the plugin's installation location, e.g. included scripts, templates or assets. diff --git a/src/octoprint/plugin/core.py b/src/octoprint/plugin/core.py index bcb28ce0..6b7b327b 100644 --- a/src/octoprint/plugin/core.py +++ b/src/octoprint/plugin/core.py @@ -902,6 +902,7 @@ class PluginManager(object): identifier=name, plugin_name=plugin.name, plugin_version=plugin.version, + plugin_info=plugin, basefolder=os.path.realpath(plugin.location), logger=logging.getLogger(self.logging_prefix + name), )) From 419f3370a24320ec9a90f9edaa667d2740504c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Thu, 13 Oct 2016 12:07:00 +0200 Subject: [PATCH 09/10] Split JS/CSS/LESS assets between core+bundled plugins and external plugins That way a JS error in an external plugin won't nuke the whole UI, which IMHO is worth the additional requests needed to load the split up files. See #1544 for an example of such a situation. --- src/octoprint/server/__init__.py | 61 ++++++++++++++++------ src/octoprint/server/util/flask.py | 29 ++++++---- src/octoprint/templates/javascripts.jinja2 | 15 ++---- src/octoprint/templates/stylesheets.jinja2 | 17 ++---- 4 files changed, 74 insertions(+), 48 deletions(-) diff --git a/src/octoprint/server/__init__.py b/src/octoprint/server/__init__.py index b076670b..2711afa1 100644 --- a/src/octoprint/server/__init__.py +++ b/src/octoprint/server/__init__.py @@ -1015,7 +1015,8 @@ class Server(object): enable_gcodeviewer = settings().getBoolean(["gcodeViewer", "enabled"]) preferred_stylesheet = settings().get(["devel", "stylesheet"]) - dynamic_assets = util.flask.collect_plugin_assets( + dynamic_core_assets = util.flask.collect_core_assets(enable_gcodeviewer=enable_gcodeviewer) + dynamic_plugin_assets = util.flask.collect_plugin_assets( enable_gcodeviewer=enable_gcodeviewer, preferred_stylesheet=preferred_stylesheet ) @@ -1051,11 +1052,13 @@ class Server(object): "js/lib/loglevel.min.js", "js/lib/sockjs-0.3.4.min.js" ] - js_app = dynamic_assets["js"] + [ - "js/app/dataupdater.js", - "js/app/helpers.js", - "js/app/main.js", - ] + js_core = dynamic_core_assets["js"] + \ + dynamic_plugin_assets["bundled"]["js"] + \ + ["js/app/dataupdater.js", + "js/app/helpers.js", + "js/app/main.js"] + js_plugins = dynamic_plugin_assets["external"]["js"] + js_app = js_core + js_plugins css_libs = [ "css/bootstrap.min.css", @@ -1066,13 +1069,21 @@ class Server(object): "css/jquery.fileupload-ui.css", "css/pnotify.min.css" ] - css_app = list(dynamic_assets["css"]) - if len(css_app) == 0: - css_app = ["empty"] + css_core = list(dynamic_core_assets["css"]) + list(dynamic_plugin_assets["bundled"]["css"]) + if len(css_core) == 0: + css_core = ["empty"] + css_plugins = list(dynamic_plugin_assets["external"]["css"]) + if len(css_plugins) == 0: + css_plugins = ["empty"] + css_app = css_core + css_plugins - less_app = list(dynamic_assets["less"]) - if len(less_app) == 0: - less_app = ["empty"] + less_core = list(dynamic_core_assets["less"]) + list(dynamic_plugin_assets["bundled"]["less"]) + if len(less_core) == 0: + less_core = ["empty"] + less_plugins = list(dynamic_plugin_assets["external"]["less"]) + if len(less_plugins) == 0: + less_plugins = ["empty"] + less_app = less_core + less_plugins from webassets.filter import register_filter, Filter from webassets.filter.cssrewrite.base import PatternRewriter @@ -1093,7 +1104,7 @@ class Server(object): return "{import_with_options}\"{import_url}\";".format(**locals()) - class JsDelimiterBundle(Filter): + class JsDelimiterBundler(Filter): name = "js_delimiter_bundler" options = {} def input(self, _in, out, **kwargs): @@ -1101,24 +1112,42 @@ class Server(object): out.write("\n;\n") register_filter(LessImportRewrite) - register_filter(JsDelimiterBundle) + register_filter(JsDelimiterBundler) + # JS js_libs_bundle = Bundle(*js_libs, output="webassets/packed_libs.js", filters="js_delimiter_bundler") if settings().getBoolean(["devel", "webassets", "minify"]): + js_core_bundle = Bundle(*js_core, output="webassets/packed_core.js", filters="rjsmin, js_delimiter_bundler") + js_plugins_bundle = Bundle(*js_plugins, output="webassets/packed_plugins.js", filters="rjsmin, js_delimiter_bundler") js_app_bundle = Bundle(*js_app, output="webassets/packed_app.js", filters="rjsmin, js_delimiter_bundler") else: + js_core_bundle = Bundle(*js_core, output="webassets/packed_core.js", filters="js_delimiter_bundler") + js_plugins_bundle = Bundle(*js_plugins, output="webassets/packed_plugins.js", filters="js_delimiter_bundler") js_app_bundle = Bundle(*js_app, output="webassets/packed_app.js", filters="js_delimiter_bundler") + # CSS css_libs_bundle = Bundle(*css_libs, output="webassets/packed_libs.css") + css_core_bundle = Bundle(*css_core, output="webassets/packed_core.css", filters="cssrewrite") + css_plugins_bundle = Bundle(*css_plugins, output="webassets/packed_plugins.css", filters="cssrewrite") css_app_bundle = Bundle(*css_app, output="webassets/packed_app.css", filters="cssrewrite") - all_less_bundle = Bundle(*less_app, output="webassets/packed_app.less", filters="cssrewrite, less_importrewrite") + # LESS + less_core_bundle = Bundle(*less_core, output="webassets/packed_core.less", filters="cssrewrite, less_importrewrite") + less_plugins_bundle = Bundle(*less_plugins, output="webassets/packed_plugins.less", filters="cssrewrite, less_importrewrite") + less_app_bundle = Bundle(*less_app, output="webassets/packed_app.less", filters="cssrewrite, less_importrewrite") + # asset registration assets.register("js_libs", js_libs_bundle) + assets.register("js_core", js_core_bundle) + assets.register("js_plugins", js_plugins_bundle) assets.register("js_app", js_app_bundle) assets.register("css_libs", css_libs_bundle) + assets.register("css_core", css_core_bundle) + assets.register("css_plugins", css_plugins_bundle) assets.register("css_app", css_app_bundle) - assets.register("less_app", all_less_bundle) + assets.register("less_core", less_core_bundle) + assets.register("less_plugins", less_plugins_bundle) + assets.register("less_app", less_app_bundle) def _start_intermediary_server(self, s): import BaseHTTPServer diff --git a/src/octoprint/server/util/flask.py b/src/octoprint/server/util/flask.py index d16237de..fdc8efd8 100644 --- a/src/octoprint/server/util/flask.py +++ b/src/octoprint/server/util/flask.py @@ -1134,12 +1134,8 @@ class SettingsCheckUpdater(webassets.updater.BaseUpdater): cache_value = webassets.utils.hash_func(json.dumps(settings().effective_yaml)) ctx.cache.set(cache_key, cache_value) -##~~ plugin assets collector - -def collect_plugin_assets(enable_gcodeviewer=True, preferred_stylesheet="css"): - logger = logging.getLogger(__name__ + ".collect_plugin_assets") - - supported_stylesheets = ("css", "less") +##~~ core assets collector +def collect_core_assets(enable_gcodeviewer=True, preferred_stylesheet="css"): assets = dict( js=[], css=[], @@ -1178,9 +1174,24 @@ def collect_plugin_assets(enable_gcodeviewer=True, preferred_stylesheet="css"): elif preferred_stylesheet == "css": assets["css"].append('css/octoprint.css') + return assets + +##~~ plugin assets collector + +def collect_plugin_assets(enable_gcodeviewer=True, preferred_stylesheet="css"): + logger = logging.getLogger(__name__ + ".collect_plugin_assets") + + supported_stylesheets = ("css", "less") + assets = dict(bundled=dict(js=[], css=[], less=[]), + external=dict(js=[], css=[], less=[])) + asset_plugins = octoprint.plugin.plugin_manager().get_implementations(octoprint.plugin.AssetPlugin) for implementation in asset_plugins: name = implementation._identifier + is_bundled = implementation._plugin_info.bundled + + asset_key = "bundled" if is_bundled else "external" + try: all_assets = implementation.get_assets() basefolder = implementation.get_asset_folder() @@ -1198,13 +1209,13 @@ def collect_plugin_assets(enable_gcodeviewer=True, preferred_stylesheet="css"): for asset in all_assets["js"]: if not asset_exists("js", asset): continue - assets["js"].append('plugin/{name}/{asset}'.format(**locals())) + assets[asset_key]["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())) + assets[asset_key][preferred_stylesheet].append('plugin/{name}/{asset}'.format(**locals())) else: for stylesheet in supported_stylesheets: if not stylesheet in all_assets: @@ -1213,7 +1224,7 @@ def collect_plugin_assets(enable_gcodeviewer=True, preferred_stylesheet="css"): for asset in all_assets[stylesheet]: if not asset_exists(stylesheet, asset): continue - assets[stylesheet].append('plugin/{name}/{asset}'.format(**locals())) + assets[asset_key][stylesheet].append('plugin/{name}/{asset}'.format(**locals())) break return assets diff --git a/src/octoprint/templates/javascripts.jinja2 b/src/octoprint/templates/javascripts.jinja2 index acad1952..edebf560 100644 --- a/src/octoprint/templates/javascripts.jinja2 +++ b/src/octoprint/templates/javascripts.jinja2 @@ -1,11 +1,4 @@ -{% assets "js_libs" %} - -{% endassets %} - -{% assets "js_app" %} - -{% endassets %} - -{% if g.locale %} - -{% endif %} +{% assets "js_libs" %}{% endassets %} +{% assets "js_core" %}{% endassets %} +{% assets "js_plugins" %}{% endassets %} +{% if g.locale %}{% endif %} diff --git a/src/octoprint/templates/stylesheets.jinja2 b/src/octoprint/templates/stylesheets.jinja2 index b88de6a0..95e7ae7a 100644 --- a/src/octoprint/templates/stylesheets.jinja2 +++ b/src/octoprint/templates/stylesheets.jinja2 @@ -1,13 +1,6 @@ -{% assets "css_libs" %} - -{% endassets %} - -{% assets "css_app" %} - -{% endassets %} - -{% assets "less_app" %} - -{% endassets %} - +{% assets "css_libs" %}{% endassets %} +{% assets "css_core" %}{% endassets %} +{% assets "css_plugins" %}{% endassets %} +{% assets "less_core" %}{% endassets %} +{% assets "less_plugins" %}{% endassets %} From 91ef5480b172812105947fb03f6f9b60b6ffecd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Thu, 13 Oct 2016 12:12:09 +0200 Subject: [PATCH 10/10] Preparing release of 1.2.17rc2 --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4be9deaf..d3b9e21e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # OctoPrint Changelog +## 1.2.17rc2 (2016-10-13) + +### Improvements + + * Improved the `serial.log` logging handler to roll over serial log on new connections to the printer instead of continuously appending to the same file. Please note that `serial.log` is a debugging tool only and should *not* be left enabled unless you are trying to troubleshoot something in your printer communication. + * Split JS/CSS/LESS asset bundles according into asset bundles for core + bundled plugins ("packed_core.{js|css|less}") and third party plugins ("packed_plugins.{js|css|less}"). That will allow the core UI to still function properly even if an installed third party plugin produces invalid JS and therefore causes a parser error for the whole plugin JS file. See [#1544](https://github.com/foosel/OctoPrint/issues/1544) for an example of such a situation. + +### Bug fixes + + * Fixed a bug causing the update of OctoPrint to not work under certain circumstances: If 1.2.16 was installed and the settings were *never* saved via the "Settings" dialog's "Save", the update of OctoPrint would fail due to a `KeyError` in the updater. Reason is a renamed property, properly switched to when saving the settings. + * Fixed the logging subsystem to not properly clean up after itself. + +([Commits](https://github.com/foosel/OctoPrint/compare/1.2.17rc1...1.2.17rc2)) + ## 1.2.17rc1 (2016-10-06) ### Improvements