Initial version of build.py

This commit is contained in:
Wesley R. Elsberry 2025-10-15 09:21:58 -04:00
parent 5a1477fe19
commit c61c050dc2
1 changed files with 120 additions and 0 deletions

120
scripts/build.py Normal file
View File

@ -0,0 +1,120 @@
#!/usr/bin/env python3
"""
Static site generator for evo-edu framework.
Two modes:
1. --init : Prompt user for site config and save to site.json
2. --config <file> --output <dir> : Render templates using config
"""
import os
import json
import argparse
from pathlib import Path
import shutil
# Template directory (relative to this script)
TEMPLATE_DIR = Path(__file__).parent / "templates"
def prompt_for_config():
"""Prompt user for site configuration."""
print("=== evo-edu Framework Site Config ===")
config = {
"lang": input("Language code (e.g., 'en'): ") or "en",
"title": input("Page title (e.g., 'Notebook On Evolution'): ") or "Notebook On Evolution",
"site_title": input("Site name (e.g., 'evo-edu.org'): ") or "evo-edu.org",
"license": input("License text (e.g., 'CC BY-SA 4.0'): ") or "CC BY-SA 4.0",
"github_url": input("GitHub URL: ") or "https://github.com/evo-edu",
"contact_email": input("Contact email: ") or "admin@evo-edu.org",
"languages": []
}
# Language options
print("\nLanguage switcher options (e.g., en:English, es:Español):")
lang_input = input("Enter as 'code:name' pairs (comma-separated): ") or "en:English"
for pair in lang_input.split(','):
code, name = pair.strip().split(':', 1)
config["languages"].append({"code": code, "name": name})
lang_options = "\n".join([
f'<option value="{lang["code"]}" {"selected" if lang["code"] == config["lang"] else ""}>{lang["name"]}</option>'
for lang in config["languages"]
])
result = result.replace("{{language_options}}", lang_options)
# Save
out_file = input("\nSave config as (default: site.json): ") or "site.json"
with open(out_file, 'w', encoding='utf-8') as f:
json.dump(config, f, indent=2)
print(f"✅ Config saved to {out_file}")
def render_template(template_text, config):
"""Replace {{key}} and {{#each}} blocks with config values."""
result = template_text
# Simple key replacements
for key, value in config.items():
if key != "languages":
result = result.replace("{{" + key + "}}", str(value))
# Handle {{#each languages}}...{{/each}}
if "{{#each languages}}" in result:
lang_block_start = result.find("{{#each languages}}")
lang_block_end = result.find("{{/each}}", lang_block_start)
if lang_block_end != -1:
block = result[lang_block_start + len("{{#each languages}}"):lang_block_end]
rendered_langs = []
for lang in config.get("languages", []):
lang_item = block
lang_item = lang_item.replace("{{code}}", lang["code"])
lang_item = lang_item.replace("{{name}}", lang["name"])
# Handle {{#if (eq code ../lang)}}
if f'{{{{lang}}}}' in result:
selected = 'selected' if lang["code"] == config.get("lang", "") else ''
lang_item = lang_item.replace("{{selected_attr}}", f'selected="{selected}"' if selected else '')
else:
lang_item = lang_item.replace("{{selected_attr}}", "")
rendered_langs.append(lang_item)
result = result[:lang_block_start] + "".join(rendered_langs) + result[lang_block_end + len("{{/each}}"):]
return result
def build_site(config_file, output_dir):
"""Render all templates using config."""
with open(config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
out_path = Path(output_dir)
out_path.mkdir(parents=True, exist_ok=True)
# Copy theme assets
theme_src = Path(__file__).parent / "theme"
for asset in ["style.css", "main.js"]:
shutil.copy(theme_src / asset, out_path / asset)
# Render base.html → index.html (example)
with open(theme_src / "base.html", 'r', encoding='utf-8') as f:
template = f.read()
rendered = render_template(template, config)
with open(out_path / "index.html", 'w', encoding='utf-8') as f:
f.write(rendered)
print(f"✅ Site built in {output_dir}")
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--init", action="store_true", help="Create site config interactively")
parser.add_argument("--config", help="Path to site.json")
parser.add_argument("--output", help="Output directory for built site")
args = parser.parse_args()
if args.init:
prompt_for_config()
elif args.config and args.output:
build_site(args.config, args.output)
else:
print("Usage:")
print(" python build.py --init")
print(" python build.py --config site.json --output ../content/en/")
if __name__ == "__main__":
main()