Mercurial > libervia-web
comparison libervia/web/server/tasks/implicit/task_brython.py @ 1518:eb00d593801d
refactoring: rename `libervia` to `libervia.web` + update imports following backend changes
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 02 Jun 2023 16:49:28 +0200 |
parents | libervia/server/tasks/implicit/task_brython.py@73c848c2f41e |
children |
comparison
equal
deleted
inserted
replaced
1517:b8ed9726525b | 1518:eb00d593801d |
---|---|
1 #!/ur/bin/env python3 | |
2 | |
3 from ast import literal_eval | |
4 import json | |
5 from pathlib import Path | |
6 import shutil | |
7 from typing import Any, Dict | |
8 | |
9 from libervia.backend.core import exceptions | |
10 from libervia.backend.core.i18n import _ | |
11 from libervia.backend.core.log import getLogger | |
12 from libervia.backend.tools.common import utils | |
13 | |
14 from libervia.web.server.classes import Script | |
15 from libervia.web.server.constants import Const as C | |
16 from libervia.web.server.tasks import task | |
17 | |
18 | |
19 log = getLogger(__name__) | |
20 | |
21 | |
22 class Task(task.Task): | |
23 | |
24 def prepare(self): | |
25 if "brython" not in self.resource.browser_modules: | |
26 raise exceptions.CancelError("No brython module found") | |
27 | |
28 brython_js = self.build_path / "brython.js" | |
29 if not brython_js.is_file(): | |
30 installed_ver = None | |
31 else: | |
32 with brython_js.open() as f: | |
33 for line in f: | |
34 if line.startswith('// implementation ['): | |
35 installed_ver = literal_eval(line[18:])[:3] | |
36 log.debug( | |
37 f"brython v{'.'.join(str(v) for v in installed_ver)} already " | |
38 f"installed") | |
39 break | |
40 else: | |
41 log.warning( | |
42 f"brython file at {brython_js} doesn't has implementation " | |
43 f"version" | |
44 ) | |
45 installed_ver = None | |
46 | |
47 try: | |
48 import brython | |
49 try: | |
50 from brython.__main__ import implementation | |
51 except ImportError: | |
52 from brython.version import implementation | |
53 except ModuleNotFoundError as e: | |
54 log.error('"brython" module is missing, can\'t use browser code for Brython') | |
55 raise e | |
56 ver = [int(v) for v in implementation.split('.')[:3]] | |
57 if ver != installed_ver: | |
58 log.info(_("Installing Brython v{version}").format( | |
59 version='.'.join(str(v) for v in ver))) | |
60 data_path = Path(brython.__file__).parent / 'data' | |
61 # shutil has blocking method, but the task is run before we start | |
62 # the web server, so it's not a big deal | |
63 shutil.copyfile(data_path / "brython.js", brython_js) | |
64 shutil.copy(data_path / "brython_stdlib.js", self.build_path) | |
65 else: | |
66 log.debug("Brython is already installed") | |
67 | |
68 self.WATCH_DIRS = [] | |
69 self.set_common_scripts() | |
70 | |
71 def set_common_scripts(self): | |
72 for dyn_data in self.resource.browser_modules["brython"]: | |
73 url_hash = dyn_data['url_hash'] | |
74 import_url = f"/{C.BUILD_DIR}/{C.BUILD_DIR_DYN}/{url_hash}" | |
75 dyn_data.setdefault('scripts', utils.OrderedSet()).update([ | |
76 Script(src=f"/{C.BUILD_DIR}/brython.js"), | |
77 Script(src=f"/{C.BUILD_DIR}/brython_stdlib.js"), | |
78 ]) | |
79 dyn_data.setdefault('template', {})['body_onload'] = self.get_body_onload( | |
80 extra_path=[import_url]) | |
81 self.WATCH_DIRS.append(dyn_data['path'].resolve()) | |
82 | |
83 def get_body_onload(self, debug=True, cache=True, extra_path=None): | |
84 on_load_opts: Dict[str, Any] = {"pythonpath": [f"/{C.BUILD_DIR}"]} | |
85 if debug: | |
86 on_load_opts["debug"] = 1 | |
87 if cache: | |
88 on_load_opts["cache"] = True | |
89 if extra_path is not None: | |
90 on_load_opts["pythonpath"].extend(extra_path) | |
91 | |
92 return f"brython({json.dumps(on_load_opts)})" | |
93 | |
94 def copy_files(self, files_paths, dest): | |
95 for p in files_paths: | |
96 log.debug(f"copying {p}") | |
97 if p.is_dir(): | |
98 if p.name == '__pycache__': | |
99 continue | |
100 shutil.copytree(p, dest / p.name) | |
101 else: | |
102 shutil.copy(p, dest) | |
103 | |
104 async def on_dir_event(self, host, filepath, flags): | |
105 self.set_common_scripts() | |
106 await self.manager.run_task_instance(self) | |
107 | |
108 def start(self): | |
109 dyn_path = self.build_path / C.BUILD_DIR_DYN | |
110 for dyn_data in self.resource.browser_modules["brython"]: | |
111 url_hash = dyn_data['url_hash'] | |
112 if url_hash is None: | |
113 # root modules | |
114 url_prefix = dyn_data.get('url_prefix') | |
115 if url_prefix is None: | |
116 dest = self.build_path | |
117 init_dest_url = f"/{C.BUILD_DIR}/__init__.py" | |
118 else: | |
119 dest = self.build_path / url_prefix | |
120 dest.mkdir(exist_ok = True) | |
121 init_dest_url = f"/{C.BUILD_DIR}/{url_prefix}/__init__.py" | |
122 | |
123 self.copy_files(dyn_data['path'].glob('*py'), dest) | |
124 | |
125 init_file = dyn_data['path'] / '__init__.py' | |
126 if init_file.is_file(): | |
127 self.resource.dyn_data_common['scripts'].update([ | |
128 Script(src=f"/{C.BUILD_DIR}/brython.js"), | |
129 Script(src=f"/{C.BUILD_DIR}/brython_stdlib.js"), | |
130 Script(type='text/python', src=init_dest_url) | |
131 ]) | |
132 self.resource.dyn_data_common.setdefault( | |
133 "template", {})['body_onload'] = self.get_body_onload() | |
134 else: | |
135 page_dyn_path = dyn_path / url_hash | |
136 log.debug(f"using dynamic path at {page_dyn_path}") | |
137 if page_dyn_path.exists(): | |
138 log.debug("cleaning existing path") | |
139 shutil.rmtree(page_dyn_path) | |
140 | |
141 page_dyn_path.mkdir(parents=True, exist_ok=True) | |
142 log.debug("copying browser python files") | |
143 self.copy_files(dyn_data['path'].iterdir(), page_dyn_path) | |
144 | |
145 script = Script( | |
146 type='text/python', | |
147 src=f"/{C.BUILD_DIR}/{C.BUILD_DIR_DYN}/{url_hash}/__init__.py" | |
148 ) | |
149 dyn_data.setdefault('scripts', utils.OrderedSet()).add(script) |