Mercurial > libervia-web
diff libervia/server/pages.py @ 1253:6d49fae517ba
pages: browser metadata + root `_browser`:
- the `_browser` directory can now be put in root of a site `pages` directory, it will then
include modules for the whole website
- in `_browser` directories (notably the root one), a `browser_meta.json` file can be put to
specify settings for a browser engine
- pathlib.Path is now used LiberviaRootResource.site_path
- introduced some type hints
- task_brython copy modules in root `_browser` to build_path root.
- minimal python version is now 3.7 due to type hints
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 29 Apr 2020 17:34:53 +0200 |
parents | aaf28d45ae67 |
children | b1fb57e9176d |
line wrap: on
line diff
--- a/libervia/server/pages.py Wed Apr 29 15:00:54 2020 +0200 +++ b/libervia/server/pages.py Wed Apr 29 17:34:53 2020 +0200 @@ -1,6 +1,5 @@ #!/usr/bin/env python3 - # Libervia: a Salut à Toi frontend # Copyright (C) 2011-2020 Jérôme Poisson <goffi@goffi.org> @@ -17,14 +16,18 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +from __future__ import annotations + import uuid import os.path import urllib.request, urllib.parse, urllib.error import time import hashlib import copy +import json +from pathlib import Path from functools import reduce -from pathlib import Path +from typing import Optional, List from twisted.web import server from twisted.web import resource as web_resource @@ -36,6 +39,7 @@ from sat.core.i18n import _ from sat.core import exceptions from sat.tools.common import date_utils +from sat.tools.common import utils from sat.core.log import getLogger from sat_frontends.bridge.bridge_frontend import BridgeException @@ -123,7 +127,7 @@ @param host(Libervia): the running instance of Libervia @param vhost_root(web_resource.Resource): root resource of the virtual host which handle this page. - @param root_dir(unicode): aboslute file path of the page + @param root_dir(Path): aboslute file path of the page @param url(unicode): relative URL to the page this URL may not be valid, as pages may require path arguments @param name(unicode, None): if not None, a unique name to identify the page @@ -260,7 +264,7 @@ def createPage(host, meta_path, vhost_root, url_elts, replace_on_conflict=False): """Create a LiberviaPage instance - @param meta_path(unicode): path to the page_meta.py file + @param meta_path(Path): path to the page_meta.py file @param vhost_root(resource.Resource): root resource of the virtual host @param url_elts(list[unicode]): list of path element from root site to this page @param replace_on_conflict(bool): same as for [LiberviaPage] @@ -268,7 +272,7 @@ - page_data: dict containing data of the page - libervia_page: created resource """ - dir_path = os.path.dirname(meta_path) + dir_path = meta_path.parent page_data = {"__name__": ".".join(["page"] + url_elts)} # we don't want to force the presence of __init__.py # so we use execfile instead of import. @@ -295,6 +299,47 @@ replace_on_conflict=replace_on_conflict ) + @staticmethod + def createBrowserData( + vhost_root, + resource: Optional(LiberviaPage), + browser_path: Path, + path_elts: Optional(List[str]), + engine: str = "brython" + ) -> None: + """create and store data for browser dynamic code""" + dyn_data = { + "path": browser_path, + "url_hash": ( + hashlib.sha256('/'.join(path_elts).encode()).hexdigest() + if path_elts is not None else None + ), + } + browser_meta_path = browser_path / C.PAGES_BROWSER_META_FILE + if browser_meta_path.is_file(): + with browser_meta_path.open() as f: + browser_meta = json.load(f) + utils.recursive_update(vhost_root.browser_modules, browser_meta) + if resource is not None: + utils.recursive_update(resource.dyn_data, browser_meta) + + init_path = browser_path / '__init__.py' + if init_path.is_file(): + vhost_root.browser_modules.setdefault( + engine, []).append(dyn_data) + if resource is not None: + resource.dyn_data[engine] = dyn_data + elif path_elts is None: + try: + next(browser_path.glob('*.py')) + except StopIteration: + # no python file, nothing for Brython + pass + else: + vhost_root.browser_modules.setdefault( + engine, []).append(dyn_data) + + @classmethod def importPages(cls, host, vhost_root, root_path=None, _parent=None, _path=None, _extra_pages=False): @@ -302,7 +347,7 @@ @param host(Libervia): Libervia instance @param vhost_root(LiberviaRootResource): root of this VirtualHost - @param root_path(unicode, None): use this root path instead of vhost_root's one + @param root_path(Path, None): use this root path instead of vhost_root's one Used to add default site pages to external sites @param _parent(Resource, None): _parent page. Do not set yourself, this is for internal use only @@ -315,23 +360,27 @@ _path = [] if _parent is None: if root_path is None: - root_dir = os.path.join(vhost_root.site_path, C.PAGES_DIR) + root_dir = vhost_root.site_path / C.PAGES_DIR else: - root_dir = os.path.join(root_path, C.PAGES_DIR) + root_dir = root_path / C.PAGES_DIR _extra_pages = True _parent = vhost_root + root_browser_path = root_dir / C.PAGES_BROWSER_DIR + if root_browser_path.is_dir(): + cls.createBrowserData(vhost_root, None, root_browser_path, None) else: root_dir = _parent.root_dir + for d in os.listdir(root_dir): - dir_path = os.path.join(root_dir, d) - if not os.path.isdir(dir_path): + dir_path = root_dir / d + if not dir_path.is_dir(): continue if _extra_pages and d in _parent.children: log.debug(_("[{host_name}] {path} is already present, ignoring it") .format(host_name=vhost_root.host_name, path='/'.join(_path+[d]))) continue - meta_path = os.path.join(dir_path, C.PAGES_META_FILE) - if os.path.isfile(meta_path): + meta_path = dir_path / C.PAGES_META_FILE + if meta_path.is_file(): new_path = _path + [d] try: page_data, resource = cls.createPage( @@ -342,7 +391,7 @@ continue else: raise e - _parent.putChild(d.encode('utf-8'), resource) + _parent.putChild(str(d).encode(), resource) log_msg = ("[{host_name}] Added /{path} page".format( host_name=vhost_root.host_name, path="[…]/".join(new_path))) @@ -374,17 +423,9 @@ host, vhost_root, _parent=resource, _path=new_path, _extra_pages=_extra_pages) # now we check if there is some code for browser - browser_path = Path(dir_path) / C.PAGES_BROWSER_DIR + browser_path = dir_path / C.PAGES_BROWSER_DIR if browser_path.is_dir(): - # for now we only handle Brython - dyn_data = { - "path": browser_path, - "url_hash": hashlib.sha256( - '/'.join(new_path).encode()).hexdigest(), - } - vhost_root.browser_modules.setdefault( - "brython", []).append(dyn_data) - resource.dyn_data['brython'] = dyn_data + cls.createBrowserData(vhost_root, resource, browser_path, new_path) @classmethod def onFileChange(cls, host, file_path, flags, site_root, site_path):