Mercurial > libervia-backend
comparison libervia/cli/output_template.py @ 4075:47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 02 Jun 2023 14:54:26 +0200 |
parents | libervia/frontends/jp/output_template.py@26b7ed2817da |
children | 0d7bb4df2343 |
comparison
equal
deleted
inserted
replaced
4074:26b7ed2817da | 4075:47401850dec6 |
---|---|
1 #! /usr/bin/env python3 | |
2 | |
3 | |
4 # Libervia CLI | |
5 # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org) | |
6 | |
7 # This program is free software: you can redistribute it and/or modify | |
8 # it under the terms of the GNU Affero General Public License as published by | |
9 # the Free Software Foundation, either version 3 of the License, or | |
10 # (at your option) any later version. | |
11 | |
12 # This program is distributed in the hope that it will be useful, | |
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 # GNU Affero General Public License for more details. | |
16 | |
17 # You should have received a copy of the GNU Affero General Public License | |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 """Standard outputs""" | |
20 | |
21 | |
22 from libervia.cli.constants import Const as C | |
23 from libervia.backend.core.i18n import _ | |
24 from libervia.backend.core import log | |
25 from libervia.backend.tools.common import template | |
26 from functools import partial | |
27 import logging | |
28 import webbrowser | |
29 import tempfile | |
30 import os.path | |
31 | |
32 __outputs__ = ["Template"] | |
33 TEMPLATE = "template" | |
34 OPTIONS = {"template", "browser", "inline-css"} | |
35 | |
36 | |
37 class Template(object): | |
38 """outputs data using SàT templates""" | |
39 | |
40 def __init__(self, libervia_cli): | |
41 self.host = libervia_cli | |
42 libervia_cli.register_output(C.OUTPUT_COMPLEX, TEMPLATE, self.render) | |
43 | |
44 def _front_url_tmp_dir(self, ctx, relative_url, tmp_dir): | |
45 """Get front URL for temporary directory""" | |
46 template_data = ctx['template_data'] | |
47 return "file://" + os.path.join(tmp_dir, template_data.theme, relative_url) | |
48 | |
49 def _do_render(self, template_path, css_inline, **kwargs): | |
50 try: | |
51 return self.renderer.render(template_path, css_inline=css_inline, **kwargs) | |
52 except template.TemplateNotFound: | |
53 self.host.disp(_("Can't find requested template: {template_path}") | |
54 .format(template_path=template_path), error=True) | |
55 self.host.quit(C.EXIT_NOT_FOUND) | |
56 | |
57 def render(self, data): | |
58 """render output data using requested template | |
59 | |
60 template to render the data can be either command's TEMPLATE or | |
61 template output_option requested by user. | |
62 @param data(dict): data is a dict which map from variable name to use in template | |
63 to the variable itself. | |
64 command's template_data_mapping attribute will be used if it exists to convert | |
65 data to a dict usable by the template. | |
66 """ | |
67 # media_dir is needed for the template | |
68 self.host.media_dir = self.host.bridge.config_get("", "media_dir") | |
69 cmd = self.host.command | |
70 try: | |
71 template_path = cmd.TEMPLATE | |
72 except AttributeError: | |
73 if not "template" in cmd.args.output_opts: | |
74 self.host.disp(_( | |
75 "no default template set for this command, you need to specify a " | |
76 "template using --oo template=[path/to/template.html]"), | |
77 error=True, | |
78 ) | |
79 self.host.quit(C.EXIT_BAD_ARG) | |
80 | |
81 options = self.host.parse_output_options() | |
82 self.host.check_output_options(OPTIONS, options) | |
83 try: | |
84 template_path = options["template"] | |
85 except KeyError: | |
86 # template is not specified, we use default one | |
87 pass | |
88 if template_path is None: | |
89 self.host.disp(_("Can't parse template, please check its syntax"), | |
90 error=True) | |
91 self.host.quit(C.EXIT_BAD_ARG) | |
92 | |
93 try: | |
94 mapping_cb = cmd.template_data_mapping | |
95 except AttributeError: | |
96 kwargs = data | |
97 else: | |
98 kwargs = mapping_cb(data) | |
99 | |
100 css_inline = "inline-css" in options | |
101 | |
102 if "browser" in options: | |
103 template_name = os.path.basename(template_path) | |
104 tmp_dir = tempfile.mkdtemp() | |
105 front_url_filter = partial(self._front_url_tmp_dir, tmp_dir=tmp_dir) | |
106 self.renderer = template.Renderer( | |
107 self.host, front_url_filter=front_url_filter, trusted=True) | |
108 rendered = self._do_render(template_path, css_inline=css_inline, **kwargs) | |
109 self.host.disp(_( | |
110 "Browser opening requested.\n" | |
111 "Temporary files are put in the following directory, you'll have to " | |
112 "delete it yourself once finished viewing: {}").format(tmp_dir)) | |
113 tmp_file = os.path.join(tmp_dir, template_name) | |
114 with open(tmp_file, "w") as f: | |
115 f.write(rendered.encode("utf-8")) | |
116 theme, theme_root_path = self.renderer.get_theme_and_root(template_path) | |
117 if theme is None: | |
118 # we have an absolute path | |
119 webbrowser | |
120 static_dir = os.path.join(theme_root_path, C.TEMPLATE_STATIC_DIR) | |
121 if os.path.exists(static_dir): | |
122 # we have to copy static files in a subdirectory, to avoid file download | |
123 # to be blocked by same origin policy | |
124 import shutil | |
125 shutil.copytree( | |
126 static_dir, os.path.join(tmp_dir, theme, C.TEMPLATE_STATIC_DIR) | |
127 ) | |
128 webbrowser.open(tmp_file) | |
129 else: | |
130 # FIXME: Q&D way to disable template logging | |
131 # logs are overcomplicated, and need to be reworked | |
132 template_logger = log.getLogger("sat.tools.common.template") | |
133 template_logger.log = lambda *args: None | |
134 | |
135 logging.disable(logging.WARNING) | |
136 self.renderer = template.Renderer(self.host, trusted=True) | |
137 rendered = self._do_render(template_path, css_inline=css_inline, **kwargs) | |
138 self.host.disp(rendered) |