diff libervia/server/tasks/implicit/task_brython.py @ 1247:a6c7f07f1e4d

tasks: implicit tasks + Brython task: - implicit tasks are tasks launched for every site. - a first one is made for Brython: it will install Brython and copy suitable files and set template data if Brython code is written in page `_browser` subdirectory.
author Goffi <goffi@goffi.org>
date Sun, 26 Apr 2020 22:07:18 +0200
parents
children 821b6ce57f99
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libervia/server/tasks/implicit/task_brython.py	Sun Apr 26 22:07:18 2020 +0200
@@ -0,0 +1,95 @@
+#!/ur/bin/env python3
+
+import shutil
+import json
+from pathlib import Path
+from ast import literal_eval
+from sat.core.i18n import _
+from sat.core.log import getLogger
+from sat.core import exceptions
+from sat.tools.common.template import safe
+from libervia.server.constants import Const as C
+from libervia.server.tasks import task
+
+
+log = getLogger(__name__)
+
+
+class Task(task.Task):
+    DOC_DIRS_DEFAULT = ('doc', 'docs')
+
+    def prepare(self):
+        if "brython" not in self.resource.browser_modules:
+            raise exceptions.CancelError(f"No brython module found")
+
+        brython_js = self.build_path / "brython.js"
+        if not brython_js.is_file():
+            installed_ver = None
+        else:
+            with brython_js.open() as f:
+                for line in f:
+                    if line.startswith('// implementation ['):
+                        installed_ver = literal_eval(line[18:])[:3]
+                        log.debug(
+                            f"brython v{'.'.join(str(v) for v in installed_ver)} already "
+                            f"installed")
+                        break
+                else:
+                    log.warning(
+                        f"brython file at {brython_js} doesn't has implementation "
+                        f"version"
+                    )
+                    installed_ver = None
+
+        import brython
+        ver = [int(v) for v in brython.implementation.split('.')[:3]]
+        if ver != installed_ver:
+            log.info(_("Installing Brython v{version}").format(
+                version='.'.join(str(v) for v in ver)))
+            data_path = Path(brython.__file__).parent / 'data'
+            # shutil has blocking method, but the task is run before we start
+            # the web server, so it's not a big deal
+            shutil.copyfile(data_path / "brython.js", brython_js)
+        else:
+            log.debug("Brython is already installed")
+
+        self.WATCH_DIRS = []
+
+        for dyn_data in self.resource.browser_modules["brython"]:
+            url_hash = dyn_data['url_hash']
+            import_url = f"/{C.BUILD_DIR}/{C.BUILD_DIR_DYN}/{url_hash}"
+            on_load_opts = {
+                "debug": 1,
+                "pythonpath": [import_url],
+            }
+            dyn_data['template'] = {
+                "scripts": [{"src": f"/{C.BUILD_DIR}/brython.js"}],
+                "body_onload": f"brython({json.dumps(on_load_opts)})",
+            }
+            self.WATCH_DIRS.append(dyn_data['path'].resolve())
+
+    def start(self):
+        dyn_path = self.build_path / C.BUILD_DIR_DYN
+        for dyn_data in self.resource.browser_modules["brython"]:
+            url_hash = dyn_data['url_hash']
+            page_dyn_path = dyn_path / url_hash
+            if page_dyn_path.exists():
+                log.debug("cleaning existing path")
+                shutil.rmtree(page_dyn_path)
+
+            page_dyn_path.mkdir(parents=True, exist_ok=True)
+            log.debug("copying browser python files")
+            for p in dyn_data['path'].iterdir():
+                log.debug(f"copying {p}")
+                if p.is_dir():
+                    shutil.copytree(p, page_dyn_path)
+                else:
+                    shutil.copy(p, page_dyn_path)
+
+            script = {
+                'type': 'text/python',
+                'src': f"/{C.BUILD_DIR}/{C.BUILD_DIR_DYN}/{url_hash}/__init__.py"
+            }
+            scripts = dyn_data['template']['scripts']
+            if script not in scripts:
+                scripts.append(script)