Rustelo/scripts/generator/extract-template.nu
Jesús Pérez c0281e759c
chore: update
2026-07-18 20:14:32 +01:00

152 lines
7 KiB
Text

#!/usr/bin/env nu
# extract-template.nu — derive a website template from a living model project
# (jpl-website) as a sanitized snapshot with safe defaults + COMPLETE markers.
#
# Reproducible seed for templates/website-htmx-ssr and templates/website-leptos.
# Re-run to re-snapshot when the model evolves (snapshot model, not a live mirror).
#
# nu extract-template.nu --mode htmx-ssr --out ../templates/website-htmx-ssr
# nu extract-template.nu --mode leptos --out ../templates/website-leptos
#
# Design:
# - crate names stay neutral ("website-*"); the generator renames to the chosen
# project later. Only the jpl-named pages_htmx crate is normalised to website-*.
# - deploy identity (domain, registry, secrets base, author) is replaced with
# safe defaults so NCL still parses and the site runs, each marked COMPLETE.
# - jesusperez portfolio pages and real content are pruned to generic examples.
# Binary / huge extensions to skip during sanitization (everything else is text).
def binary-ext [] {
[png jpg jpeg gif ico svg webp avif woff woff2 ttf otf eot wasm db "db-shm" "db-wal" pdf zip tgz gz xz lock map]
}
# Ordered, specific-before-generic substitutions applied to text files.
def subs [] {
[
# crate normalisation (the one jpl-named crate)
["jpl-pages-htmx" "website-pages-htmx"]
["jpl_pages_htmx" "website_pages_htmx"]
["jpl-website" "website"]
["jpl_website" "website"]
# deploy identity → safe defaults (COMPLETE: set to your own)
["hello@jesusperez.pro" "hello@example.com"]
["dev@jesusperez.pro" "dev@example.com"]
["repo.jesusperez.pro/jesus" "repo.example.com/org"]
["daoreg.librecloud.online" "registry.example.com"]
["daoreg" "registry"]
["reg.librecloud.online" "registry.example.com"]
["librecloud.online" "example.com"]
["jesusperez.pro" "example.com"]
["reg-librecloud-pull" "registry-pull-secret"]
["librecloud-fip-wuji" "gateway-fip"]
["libre-wuji" "secrets-base"]
["librecloud" "example"]
["jesusperezlorenzo" "example-org"]
["@jesusperez_dev" "@example_dev"]
["JesusPerez" "ExampleOrg"]
["jesusperez" "example"]
]
}
def main [
--mode: string = "htmx-ssr" # htmx-ssr | leptos
--src: string = "/Users/Akasha/Development/jpl-website"
--out: string # target template dir (required)
] {
if ($out | is-empty) { error make { msg: "--out is required" } }
if ($mode not-in ["htmx-ssr" "leptos"]) { error make { msg: $"bad --mode ($mode)" } }
let src = ($src | path expand)
let out = ($out | path expand)
if not ($src | path exists) { error make { msg: $"src not found: ($src)" } }
print $"[extract] mode=($mode) src=($src) out=($out)"
if ($out | path exists) { rm -rf $out }
mkdir $out
# --- 1. rsync the tree with explicit excludes -------------------------------
let common_excludes = [
".git/" ".gitignore" "target/" "node_modules/" ".env" ".env.dev" ".k"
"cache/" "dist/" "works-pv/" "lian-build-out/" ".DS_Store"
".ontoref/" ".ontoref-backup-pre-0023.tgz" ".coder/" ".config/" ".cargo/"
".claude/" ".rustelo.ontoref/" ".woodpecker/"
"Cargo.lock" "pnpm-lock.yaml" "rel.sh" "RESUME.md" "test_img_gen.sh"
"card.ncl" "rustelo-deps-overlay.toml"
# jpl-only top-level cruft
"data/" "rustelo/" "crates/site/" "templates/" ".woodpecker/" ".npmrc"
"just/claude-admin.just" "just/claude-content.just" "just/claude-dev.just"
# cluster/workspace-specific deploy bundles — a new site generates its own
"provisioning/workspaces/" "provisioning/rustelo_website/"
# real content — replaced by seed example post + pruned extras
"site/content/blog/"
"site/content/projects/" "site/content/recipes/" "site/content/activities/"
"site/guide/" "site/info/" "site/reflection/" "site/public/kitdigital/"
"site/public/r/" "site/public/content/" "site/public/docs/"
# build artifacts in lian-build
"lian-build/save/" "lian-build/all_Dockerfile" "lian-build/Dockerfile.server"
"lian-build/build_directives_server.ncl"
# jesusperez portfolio pages (htmx j2)
"crates/pages_htmx/templates/pages/kogral.j2"
"crates/pages_htmx/templates/pages/ontoref.j2"
"crates/pages_htmx/templates/pages/provisioning.j2"
"crates/pages_htmx/templates/pages/rustelo.j2"
"crates/pages_htmx/templates/pages/secretumvault.j2"
"crates/pages_htmx/templates/pages/stratumiops.j2"
"crates/pages_htmx/templates/pages/syntaxis.j2"
"crates/pages_htmx/templates/pages/typedialog.j2"
"crates/pages_htmx/templates/pages/vapora.j2"
# jpl logos (binary, name-bearing)
"site/assets/logos/" "site/public/images/logos/"
]
# NOTE: crates are NOT split by mode. jpl's server hard-depends on website-pages
# and optionally website-client; mode is selected via cargo features + cfg, not
# crate membership. Both templates carry the full workspace; only rendering.ncl
# default_profile, the kept Dockerfile, and build features differ. (A pure-htmx
# site can prune the leptos crates later only after making those deps optional.)
let excludes = $common_excludes
let exfile = (mktemp -t rsync-ex.XXXXXX)
$excludes | str join "\n" | save -f $exfile
(^rsync -a --exclude-from $exfile $"($src)/" $"($out)/")
rm -f $exfile
# --- 2. sanitize text files -------------------------------------------------
let bin = (binary-ext)
let files = (glob ($out | path join "**" "*") --no-dir
| where { |f| (($f | path parse | get extension) not-in $bin) and (not ($f | str contains "node_modules")) })
let table = (subs)
mut done = 0
for f in $files {
try {
mut content = (open --raw $f | decode utf-8)
for pair in $table {
$content = ($content | str replace --all ($pair | get 0) ($pair | get 1))
}
$content | save -f $f
$done = $done + 1
} catch {
# binary or non-utf8 file — leave untouched
}
}
print $"[extract] sanitized ($done) / ($files | length) text files"
# --- 3. mode-specific tweaks ------------------------------------------------
# rendering profile default
let rendering = ($out | path join "site" "config" "rendering.ncl")
if ($rendering | path exists) {
let want = (if $mode == "htmx-ssr" { "htmx-ssr" } else { "leptos-hydration" })
open --raw $rendering | decode utf-8 | str replace --all --regex 'default_profile\s*=\s*"[^"]*"' $'default_profile = "($want)"' | save -f $rendering
}
# workspace members are left as-is (full workspace; see note above).
# drop the non-active Dockerfile (rsync excludes are unreliable for single files here)
let drop_dockerfile = (if $mode == "htmx-ssr" { "Dockerfile.leptos-hydration" } else { "Dockerfile.htmx-ssr" })
let df = ($out | path join "lian-build" $drop_dockerfile)
if ($df | path exists) { rm -f $df }
# --- 4. overlay seed (example content, setup doc) ---------------------------
let seed = ($env.FILE_PWD | path join "seed" "common")
if ($seed | path exists) {
^rsync -a $"($seed)/" $"($out)/"
print $"[extract] seed overlaid from ($seed)"
}
print $"[extract] done: ($out)"
}