Infra
This commit is contained in:
1 parent
ea1afaf833
commit
e0db317146
12 files changed
+444
-56
No files matched your search
@@ -3,9 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import posixpath
|
||||
import signal
|
||||
@@ -13,59 +11,26 @@ import sys
|
||||
from functools import partial
|
||||
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
||||
|
||||
from worker import WORKER, stamp_worker, walk
|
||||
|
||||
NO_CACHE_NAMES = {"sw.js"}
|
||||
NO_CACHE_EXTS = {".html", ".njk", ".json", ".webmanifest"}
|
||||
|
||||
BOOT_PAGE = "/boot.html"
|
||||
|
||||
WORKER = "sw.js"
|
||||
_stamped = (None, None)
|
||||
|
||||
VERSION_LINE = "const VERSION = 'dev';"
|
||||
LIBRARY_VERSION_LINE = "const LIBRARY_VERSION = 'dev';"
|
||||
LIBRARY_LINE = "const LIBRARY = [];"
|
||||
|
||||
def walk(roots):
|
||||
found = {}
|
||||
for root in roots:
|
||||
for dirpath, _dirs, names in os.walk(root):
|
||||
for name in sorted(names):
|
||||
path = os.path.join(dirpath, name)
|
||||
rel = os.path.relpath(path, root).replace(os.sep, "/")
|
||||
found.setdefault(rel, path)
|
||||
return found
|
||||
|
||||
def digest(files):
|
||||
out = hashlib.sha256()
|
||||
for rel in sorted(files):
|
||||
st = os.stat(files[rel])
|
||||
out.update(("%s\0%d\0%d\0" % (rel, st.st_size, st.st_mtime_ns)).encode())
|
||||
return out.hexdigest()[:12]
|
||||
|
||||
def page_url(rel):
|
||||
if rel == "index.html":
|
||||
return "./"
|
||||
return "./" + (rel[:-len(".html")] if rel.endswith(".html") else rel)
|
||||
|
||||
def stamp_worker(roots):
|
||||
chrome = walk(roots[:1])
|
||||
library = {rel: path for rel, path in walk(roots).items() if rel not in chrome}
|
||||
|
||||
src = chrome.pop(WORKER, None)
|
||||
if src is None:
|
||||
return None
|
||||
with open(src, encoding="utf-8") as fh:
|
||||
body = fh.read()
|
||||
|
||||
for line, value in (
|
||||
(VERSION_LINE, "const VERSION = '%s';" % digest(chrome)),
|
||||
(LIBRARY_VERSION_LINE, "const LIBRARY_VERSION = '%s';" % digest(library)),
|
||||
(LIBRARY_LINE, "const LIBRARY = %s;"
|
||||
% json.dumps(sorted(page_url(rel) for rel in library), indent=2)),
|
||||
):
|
||||
if line not in body:
|
||||
raise RuntimeError("%s: expected to find %r to stamp" % (WORKER, line))
|
||||
body = body.replace(line, value, 1)
|
||||
return body.encode("utf-8")
|
||||
def cached_worker(roots):
|
||||
# Stamping hashes every file the worker lists, 11 MB of them, and browsers
|
||||
# ask for sw.js on almost every load. Stats are cheap, so redo the stamp
|
||||
# only when one moves: often under compose, never in a baked image.
|
||||
global _stamped
|
||||
key = tuple((rel, st.st_size, st.st_mtime_ns)
|
||||
for rel, st in ((rel, os.stat(path))
|
||||
for rel, path in sorted(walk(roots).items())))
|
||||
if _stamped[0] != key:
|
||||
_stamped = (key, stamp_worker(roots))
|
||||
return _stamped[1]
|
||||
|
||||
class Handler(SimpleHTTPRequestHandler):
|
||||
extensions_map = {
|
||||
@@ -106,7 +71,7 @@ class Handler(SimpleHTTPRequestHandler):
|
||||
|
||||
def send_worker(self):
|
||||
try:
|
||||
body = stamp_worker(self.roots)
|
||||
body = cached_worker(self.roots)
|
||||
except Exception as err:
|
||||
self.log_message("stamp failed: %s", err)
|
||||
self.send_error(500, "service worker unavailable")
|
||||
|
||||
Reference in new issue
Block a user