create a wwwdev.sh entry point for helping live web design/development (#92)

* create a wwwdev.sh entry point for developing the web part

* rename script

* fix README

* add a note

* don't depend on deltachat python package

* avoid bailing out on jinja2 errors, and provide file-url for instant clickability

* in webdev mode make page auto-refresh every 3 seconds
This commit is contained in:
holger krekel
2023-12-08 14:32:40 +01:00
committed by GitHub
parent 32360061b4
commit 7cb8f90340
18 changed files with 206 additions and 90 deletions

View File

@@ -3,7 +3,6 @@ Chat Mail pyinfra deploy.
"""
import importlib.resources
import configparser
import textwrap
from pathlib import Path
from pyinfra import host
@@ -11,11 +10,6 @@ from pyinfra.operations import apt, files, server, systemd
from pyinfra.facts.files import File
from pyinfra.facts.systemd import SystemdEnabled
from .acmetool import deploy_acmetool
import markdown
from jinja2 import Template
from .genqr import gen_qr_png_data
def _install_chatmaild() -> None:
@@ -325,67 +319,6 @@ def get_ini_settings(mail_domain, inipath):
return settings
def build_htmlj2_from_markdown(source):
assert source.exists(), source
template_content = open(source).read()
if source.stem == "privacy":
title = "privacy {{ config.mail_domain }}"
elif source.stem == "index":
title = "home {{ config.mail_domain }}"
elif source.stem == "info":
title = "info {{ config.mail_domain }}"
html = markdown.markdown(template_content)
html = (
textwrap.dedent(
f"""\
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>{title}</title>
<link rel="stylesheet" href="./water.css">
</head>
<body>
"""
)
+ html
+ "\n"
+ textwrap.dedent(
"""\
<footer>
<a href="index.html">home</a> |
<a href="info.html">more info</a> |
<a href="privacy.html">privacy</a> |
<a href="https://github.com/deltachat/chatmail">-> public development </a>
</footer>
</body>"""
)
)
target_path = source.with_name(source.stem + ".html.j2")
with open(target_path, "w") as f:
f.write(html)
print(f"wrote {target_path}")
return target_path
def build_webpages(www_path, config):
mail_domain = config["mail_domain"]
qr_data = gen_qr_png_data(mail_domain).read()
www_path.joinpath(f"qr-chatmail-invite-{mail_domain}.png").write_bytes(qr_data)
for path in www_path.iterdir():
if path.suffix == ".md":
path = build_htmlj2_from_markdown(path)
if path.suffix == ".j2":
target = path.with_name(path.name[:-3])
template = Template(path.read_text())
with target.open("w") as f:
f.write(template.render(config=config))
def deploy_chatmail(mail_domain: str, mail_server: str, dkim_selector: str) -> None:
"""Deploy a chat-mail instance.
@@ -393,6 +326,7 @@ def deploy_chatmail(mail_domain: str, mail_server: str, dkim_selector: str) -> N
:param mail_server: the DNS name under which your mail server is reachable
:param dkim_selector:
"""
from .www import build_webpages
apt.update(name="apt update", cache_time=24 * 3600)
server.group(name="Create vmail group", group="vmail", system=True)
@@ -442,8 +376,10 @@ def deploy_chatmail(mail_domain: str, mail_server: str, dkim_selector: str) -> N
config = get_ini_settings(mail_domain, chatmail_ini)
www_path = pkg_root.joinpath("../../../www").resolve()
build_webpages(www_path, config)
files.rsync(f"{www_path}/", "/var/www/html", flags=["-avz"])
build_dir = www_path.joinpath("build")
src_dir = www_path.joinpath("src")
build_webpages(src_dir, build_dir, config)
files.rsync(f"{build_dir}/", "/var/www/html", flags=["-avz"])
_install_chatmaild()
debug = False

View File

@@ -49,10 +49,10 @@ def gen_qr(maildomain, url):
size = width = 384
qr_padding = 6
text_height = font_size * num_lines
height = size + text_height + qr_padding * 2
height = size + text_height
image = Image.new("RGBA", (width, height), "white")
qr_final_size = width - (qr_padding * 2)
qr_final_size = width
if num_lines:
draw = ImageDraw.Draw(image)

View File

@@ -0,0 +1,110 @@
import importlib.resources
import webbrowser
import hashlib
import time
import traceback
import markdown
from jinja2 import Template
from .genqr import gen_qr_png_data
from deploy_chatmail import get_ini_settings
def snapshot_dir_stats(somedir):
d = {}
for path in somedir.iterdir():
if path.is_file() and path.name[0] != "." and path.suffix != ".swp":
mtime = path.stat().st_mtime
hash = hashlib.md5(path.read_bytes()).hexdigest()
d[path] = (mtime, hash)
return d
def prepare_template(source):
assert source.exists(), source
render_vars = {}
render_vars["pagename"] = "home" if source.stem == "index" else source.stem
render_vars["markdown_html"] = markdown.markdown(source.read_text())
page_layout = source.with_name("page-layout.html").read_text()
return render_vars, page_layout
def build_webpages(src_dir, build_dir, config):
try:
_build_webpages(src_dir, build_dir, config)
except Exception:
print(traceback.format_exc())
def _build_webpages(src_dir, build_dir, config):
mail_domain = config["mail_domain"]
assert src_dir.exists(), src_dir
if not build_dir.exists():
build_dir.mkdir()
qr_path = build_dir.joinpath(f"qr-chatmail-invite-{mail_domain}.png")
qr_path.write_bytes(gen_qr_png_data(mail_domain).read())
for path in src_dir.iterdir():
if path.suffix == ".md":
render_vars, content = prepare_template(path)
target = build_dir.joinpath(path.stem + ".html")
# recursive jinja2 rendering
while 1:
new = Template(content).render(config=config, **render_vars)
if new == content:
break
content = new
with target.open("w") as f:
f.write(content)
elif path.name != "page-layout.html":
target = build_dir.joinpath(path.name)
target.write_bytes(path.read_bytes())
return build_dir
def main():
chatmail_domain = "example.testrun.org"
path = importlib.resources.files(__package__)
reporoot = path.joinpath("../../../").resolve()
inipath = reporoot.joinpath("chatmail.ini")
config = get_ini_settings(chatmail_domain, inipath)
config["webdev"] = True
www_path = reporoot.joinpath("www")
src_path = www_path.joinpath("src")
stats = None
build_dir = www_path.joinpath("build")
src_dir = www_path.joinpath("src")
index_path = build_dir.joinpath("index.html")
# start web page generation, open a browser and wait for changes
build_webpages(src_dir, build_dir, config)
webbrowser.open(str(index_path))
stats = snapshot_dir_stats(src_path)
print(f"\nOpened URL: file://{index_path.resolve()}\n")
print(f"watching {src_path} directory for changes")
changenum = 0
for count in range(0, 1000000):
newstats = snapshot_dir_stats(src_path)
if newstats == stats and count % 60 != 0:
count += 1
time.sleep(1.0)
continue
for key in newstats:
if stats[key] != newstats[key]:
print(f"*** CHANGED: {key}")
changenum += 1
stats = newstats
build_webpages(src_dir, build_dir, config)
print(f"[{changenum}] regenerated web pages at: {index_path}")
print(f"URL: file://{index_path.resolve()}\n\n")
count = 0
if __name__ == "__main__":
main()