From b63f84221093ebc9264e5578fcebca162328c6b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Wed, 3 Jun 2015 18:27:30 +0200 Subject: [PATCH] Webassets are now written to ~/.octoprint/generated Same holds true for cache files, so there should be no problem anymore with installs where the static folder is not writable. Also introduced two new devel config vars to disable merging and minifying of the assets, solved the empty-less-bundle problem and made sure babel knows about the jinja extension. --- babel.cfg | 2 +- src/octoprint/server/__init__.py | 65 ++++++++++++---------- src/octoprint/server/util/flask.py | 43 +++++++++++--- src/octoprint/settings.py | 6 +- src/octoprint/static/empty | 0 src/octoprint/templates/javascripts.jinja2 | 7 +-- src/octoprint/templates/stylesheets.jinja2 | 8 +-- 7 files changed, 78 insertions(+), 53 deletions(-) create mode 100644 src/octoprint/static/empty diff --git a/babel.cfg b/babel.cfg index dcdd8e34..014eb25d 100644 --- a/babel.cfg +++ b/babel.cfg @@ -1,7 +1,7 @@ [python: src/octoprint/**.py] [jinja2: src/octoprint/templates/**.jinja2] [jinja2: src/octoprint/plugins/**.jinja2] -extensions=jinja2.ext.autoescape, jinja2.ext.with_ +extensions=jinja2.ext.autoescape, jinja2.ext.with_, webassets.ext.jinja2.AssetsExtension [javascript: src/octoprint/static/js/app/**.js] [javascript: src/octoprint/plugins/**.js] diff --git a/src/octoprint/server/__init__.py b/src/octoprint/server/__init__.py index 5701f6b4..56b2ddd7 100644 --- a/src/octoprint/server/__init__.py +++ b/src/octoprint/server/__init__.py @@ -290,11 +290,6 @@ class Server(): # register API blueprint self._setup_blueprints() - def blueprint_enabled(name, plugin): - if plugin.implementation is None or not isinstance(plugin.implementation, octoprint.plugin.BlueprintPlugin): - return - self._register_blueprint_plugin(plugin.implementation) - pluginLifecycleManager.add_callback(["enabled"], blueprint_enabled) ## Tornado initialization starts here @@ -313,7 +308,7 @@ class Server(): # camera snapshot (r"/downloads/camera/current", util.tornado.UrlForwardHandler, dict(url=s.get(["webcam", "snapshot"]), as_attachment=True, access_validation=util.tornado.access_validation_factory(app, loginManager, util.flask.user_validator))), # generated webassets - (r"/static/webassets/(.*)", util.tornado.LargeResponseHandler, dict(path=s.getBaseFolder("webassets"))) + (r"/static/webassets/(.*)", util.tornado.LargeResponseHandler, dict(path=os.path.join(s.getBaseFolder("generated"), "webassets"))) ] for name, hook in pluginManager.get_hooks("octoprint.server.http.routes").items(): try: @@ -667,12 +662,28 @@ class Server(): global assets global pluginManager + base_folder = settings().getBaseFolder("generated") + AdjustedEnvironment = type(Environment)(Environment.__name__, (Environment,), dict( resolver_class=util.flask.PluginAssetResolver )) - assets = AdjustedEnvironment(app) + class CustomDirectoryEnvironment(AdjustedEnvironment): + @property + def directory(self): + return base_folder - dynamic_assets = util.flask.collect_plugin_assets() + assets = CustomDirectoryEnvironment(app) + assets.debug = not settings().getBoolean(["devel", "webassets", "bundle"]) + + enable_gcodeviewer = settings().getBoolean(["gcodeViewer", "enabled"]) + enable_timelapse = (settings().get(["webcam", "snapshot"]) and settings().get(["webcam", "ffmpeg"])) + preferred_stylesheet = settings().get(["devel", "stylesheet"]) + + dynamic_assets = util.flask.collect_plugin_assets( + enable_gcodeviewer=enable_gcodeviewer, + enable_timelapse=enable_timelapse, + preferred_stylesheet=preferred_stylesheet + ) js_libs = [ "js/lib/jquery/jquery.min.js", @@ -696,16 +707,15 @@ class Server(): "js/lib/jquery/jquery.fileupload.js", "js/lib/jquery/jquery.slimscroll.min.js", "js/lib/jquery/jquery.qrcode.min.js", - "js/lib/sockjs-0.3.4.min.js", "js/lib/moment-with-locales.min.js", "js/lib/pusher.color.min.js", "js/lib/detectmobilebrowser.js", "js/lib/md5.min.js", "js/lib/pnotify.min.js", "js/lib/bootstrap-slider-knockout-binding.js", - "js/lib/loglevel.min.js" + "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", @@ -721,29 +731,24 @@ class Server(): "css/jquery.fileupload-ui.css", "css/pnotify.min.css" ] - - css_app = [] - less_app = [] - for sheet, path in dynamic_assets["stylesheets"]: - if sheet == "css": - css_app.append(path) - elif sheet == "less": - less_app.append(path) + css_app = ["empty"] + dynamic_assets["css"] + less_app = ["empty"] + dynamic_assets["less"] js_libs_bundle = Bundle(*js_libs, output="webassets/packed_libs.js") - js_app_bundle = Bundle(*js_app, output="webassets/package_app.js") + if settings().getBoolean(["devel", "webassets", "minify"]): + js_app_bundle = Bundle(*js_app, output="webassets/package_app.js", filters="rjsmin") + else: + js_app_bundle = Bundle(*js_app, output="webassets/package_app.js") + all_js_bundle = Bundle(js_libs_bundle, js_app_bundle, output="webassets/packed.js") + css_libs_bundle = Bundle(*css_libs, output="webassets/packed_libs.css") + css_app_bundle = Bundle(*css_app, output="webassets/packed_app.css") + all_css_bundle = Bundle(css_libs_bundle, css_app_bundle, output="webassets/packed.css") + all_less_bundle = Bundle(*less_app, output="webassets/packed_app.less") - assets.register("js_libs", js_libs_bundle) - assets.register("js_app", js_app_bundle) - assets.register("css_libs", css_libs_bundle) - - if len(css_app): - css_app_bundle = Bundle(*css_app, output="webassets/packed_app.css") - assets.register("css_app", css_app_bundle) - if len(less_app): - less_app_bundle = Bundle(*less_app, output="webassets/packed_app.less") - assets.register("less_app", less_app_bundle) + assets.register("all_js", all_js_bundle) + assets.register("all_css", all_css_bundle) + assets.register("less_app", all_less_bundle) class LifecycleManager(object): diff --git a/src/octoprint/server/util/flask.py b/src/octoprint/server/util/flask.py index 6ff85474..85c86089 100644 --- a/src/octoprint/server/util/flask.py +++ b/src/octoprint/server/util/flask.py @@ -431,10 +431,34 @@ class PluginAssetResolver(flask.ext.assets.FlaskResolver): return flask.ext.assets.FlaskResolver.split_prefix(self, item) def resolve_output_to_path(self, target, bundle): - if target.startswith("webassets/"): - import os - return os.path.normpath(os.path.join(settings().getBaseFolder("webassets"), target[len("webassets/"):])) - return flask.ext.assets.FlaskResolver.resolve_output_to_path(self, target, bundle) + import os + return os.path.normpath(os.path.join(self.env.directory, target)) + + def resolve_source_to_url(self, filepath, item): + if item.startswith("plugin/"): + try: + prefix, plugin, name = item.split('/', 2) + blueprint = prefix + "." + plugin + + self.env._app.blueprints[blueprint] # keyerror if no module + endpoint = '%s.static' % blueprint + filename = name + except (ValueError, KeyError): + endpoint = 'static' + filename = item + + ctx = None + if not flask._request_ctx_stack.top: + ctx = self.env._app.test_request_context() + ctx.push() + try: + return flask.url_for(endpoint, filename=filename) + finally: + if ctx: + ctx.pop() + + return flask.ext.assets.FlaskResolver.resolve_source_to_url(self, filepath, item) + ##~~ plugin assets collector @@ -442,7 +466,8 @@ def collect_plugin_assets(enable_gcodeviewer=True, enable_timelapse=True, prefer supported_stylesheets = ("css", "less") assets = dict( js=[], - stylesheets=[] + css=[], + less=[] ) assets["js"] = [ 'js/app/viewmodels/appearance.js', @@ -473,9 +498,9 @@ def collect_plugin_assets(enable_gcodeviewer=True, enable_timelapse=True, prefer assets["js"].append('js/app/viewmodels/timelapse.js') if preferred_stylesheet == "less": - assets["stylesheets"].append(("less", 'less/octoprint.less')) + assets["less"].append('less/octoprint.less') elif preferred_stylesheet == "css": - assets["stylesheets"].append(("css", 'css/octoprint.css')) + assets["css"].append('css/octoprint.css') asset_plugins = octoprint.plugin.plugin_manager().get_implementations(octoprint.plugin.AssetPlugin) for implementation in asset_plugins: @@ -488,14 +513,14 @@ def collect_plugin_assets(enable_gcodeviewer=True, enable_timelapse=True, prefer if preferred_stylesheet in all_assets: for asset in all_assets[preferred_stylesheet]: - assets["stylesheets"].append((preferred_stylesheet, 'plugin/{name}/{asset}'.format(**locals()))) + assets[preferred_stylesheet].append('plugin/{name}/{asset}'.format(**locals())) else: for stylesheet in supported_stylesheets: if not stylesheet in all_assets: continue for asset in all_assets[stylesheet]: - assets["stylesheets"].append((stylesheet, 'plugin/{name}/{asset}'.format(**locals()))) + assets[stylesheet].append('plugin/{name}/{asset}'.format(**locals())) break return assets diff --git a/src/octoprint/settings.py b/src/octoprint/settings.py index e65e0037..80a78cad 100644 --- a/src/octoprint/settings.py +++ b/src/octoprint/settings.py @@ -156,7 +156,7 @@ default_settings = { "printerProfiles": None, "scripts": None, "translations": None, - "webassets": None + "generated": None }, "temperature": { "profiles": [ @@ -249,6 +249,10 @@ default_settings = { "cache": { "enabled": True }, + "webassets": { + "minify": True, + "bundle": True + }, "virtualPrinter": { "enabled": False, "okAfterResend": False, diff --git a/src/octoprint/static/empty b/src/octoprint/static/empty new file mode 100644 index 00000000..e69de29b diff --git a/src/octoprint/templates/javascripts.jinja2 b/src/octoprint/templates/javascripts.jinja2 index ccfa4ae7..f285bb11 100644 --- a/src/octoprint/templates/javascripts.jinja2 +++ b/src/octoprint/templates/javascripts.jinja2 @@ -1,9 +1,4 @@ - -{% assets "js_libs" %} - -{% endassets %} - -{% assets "js_app" %} +{% assets "all_js" %} {% endassets %} diff --git a/src/octoprint/templates/stylesheets.jinja2 b/src/octoprint/templates/stylesheets.jinja2 index 8516f823..75337db4 100644 --- a/src/octoprint/templates/stylesheets.jinja2 +++ b/src/octoprint/templates/stylesheets.jinja2 @@ -1,13 +1,9 @@ -{% assets "css_libs" %} +{% assets "all_css" %} {% endassets %} -{% assets "css_app" %} - -{% endassets %} - {% assets "less_app" %} - + {% endassets %}