view 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 source

#!/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)