diff --git a/build.py b/build.py
index e14c237..08970dd 100644
--- a/build.py
+++ b/build.py
@@ -4,68 +4,129 @@ Build a single self-contained HTML file from the source files.
Usage:
python3 build.py [output.html]
-
-If output is not given, defaults to 'background-standalone.html'.
+ python3 build.py --check build to a temp file and only verify
What gets inlined:
- - config.js, i18n.js (plain inside an inline block would end it early
- return s.replace('', '<\\/')
-
-
def inline_script(html, tag, body):
old = '' % tag
- new = '' % body
if old not in html:
raise SystemExit('build.py: expected tag not found: ' + tag)
- return html.replace(old, new, 1)
+ # a literal inside an inline block would end it early
+ return html.replace(old, '' % body.replace('', '<\\/'), 1)
def parse_themes(config_src):
- m = re.search(r'window\.THEMES\s*=\s*\{(.*?)\}', config_src, re.S)
+ """Return {themeId: cssFileName} from window.THEMES.
+
+ Accepts both shapes:
+ 'ash': 'ash.css'
+ 'ash': { css: 'ash.css', lighting: { ... } }
+ """
+ m = re.search(r'window\.THEMES\s*=\s*\{', config_src)
if not m:
raise SystemExit('build.py: window.THEMES not found in config.js')
- return dict(re.findall(r"'([^']+)'\s*:\s*'([^']+\.css)'", m.group(1)))
+ i = m.end()
+ depth = 1
+ block_start = i
+ while i < len(config_src) and depth:
+ c = config_src[i]
+ if c == '{':
+ depth += 1
+ elif c == '}':
+ depth -= 1
+ i += 1
+ block = config_src[block_start:i - 1]
+
+ themes = {}
+ # top level entries only: split on commas that sit at brace depth 0
+ parts, buf, depth = [], '', 0
+ for c in block:
+ if c == '{':
+ depth += 1
+ elif c == '}':
+ depth -= 1
+ if c == ',' and depth == 0:
+ parts.append(buf)
+ buf = ''
+ else:
+ buf += c
+ parts.append(buf)
+
+ for part in parts:
+ entry = re.match(r"\s*['\"]?([A-Za-z0-9_-]+)['\"]?\s*:\s*(.*)", part, re.S)
+ if not entry:
+ continue
+ name, value = entry.group(1), entry.group(2)
+ css = re.search(r"['\"]([^'\"]+\.css)['\"]", value)
+ if not css:
+ raise SystemExit('build.py: theme %r has no .css reference' % name)
+ themes[name] = css.group(1)
+ if not themes:
+ raise SystemExit('build.py: window.THEMES is empty')
+ return themes
+
+
+def verify(html):
+ """Fail if anything still points at a sibling file."""
+ leftovers = re.findall(r'\n'
- % (json.dumps(stars, separators=(',', ':')),
- json.dumps(theme_css))
+ % (json.dumps(stars, separators=(',', ':')), json.dumps(theme_css))
)
- anchor = ''
+ # must come before config.js so the early theme loader sees the CSS
+ anchor = ''
+ if anchor not in html:
+ raise SystemExit('build.py: anchor script tag not found in background.html')
html = html.replace(anchor, embed + anchor, 1)
- html = inline_script(html, 'config.js', read('config.js'))
- html = inline_script(html, 'i18n.js', read('i18n.js'))
- html = inline_script(html, 'vendor/suncalc.js', read('vendor/suncalc.js'))
- html = inline_script(html, 'vendor/plane3d.js', read('vendor/plane3d.js'))
- html = inline_script(html, 'vendor/clouds3d.js', read('vendor/clouds3d.js'))
+ for tag in INLINED_SCRIPTS:
+ html = inline_script(html, tag, read(tag))
- # the default stays but is
- # disabled by the inline-theme loader; keep a guarded fallback anyway
- html = html.replace('\n ]*>', html)
+ if not rep_link:
+ raise SystemExit('build.py: theme-css link not found in background.html')
+ html = html[:rep_link.start()] + '\n ' + \
+ html[rep_link.end():]
+
+ verify(html)
+
+ if check:
+ with tempfile.NamedTemporaryFile('w', suffix='.html', delete=False) as f:
+ f.write(html)
+ tmp = f.name
+ print('OK: self-contained (%d bytes, %d themes, %d stars)'
+ % (len(html), len(themes), len(stars)))
+ os.unlink(tmp)
+ return
with open(os.path.join(ROOT, out), 'w', encoding='utf-8') as f:
f.write(html)
print('Wrote %s (%d bytes)' % (out, len(html)))
- print('Inlined: config.js, i18n.js, suncalc.js, clouds3d.js,')
- print(' stars.json (%d entries), themes: %s'
- % (len(stars), ', '.join(themes)))
+ print('Inlined: %s, stars.json (%d entries), themes: %s'
+ % (', '.join(INLINED_SCRIPTS), len(stars), ', '.join(sorted(themes))))
if __name__ == '__main__':