124 lines
5.4 KiB
Text
124 lines
5.4 KiB
Text
|
|
#!/usr/bin/env nu
|
||
|
|
# Assemble a transportable distro tarball from the single manifest
|
||
|
|
# provisioning/distro.ncl — the one source of truth shared with the Dockerfiles
|
||
|
|
# (image_only) and content.nu (content_hot).
|
||
|
|
#
|
||
|
|
# The tarball is the PV payload (site_tree) plus the active profile's image_only
|
||
|
|
# artifacts: the Leptos WASM pkg/ for leptos-hydration, nothing for htmx-ssr.
|
||
|
|
# Unpacked at /var/www/site/ it is exactly what the content-agnostic image
|
||
|
|
# expects on its PV.
|
||
|
|
#
|
||
|
|
# Profile is auto-detected from rendering.ncl (same source as `just build-auto`)
|
||
|
|
# unless given explicitly. website.css is rebuilt first so site/public/styles is
|
||
|
|
# current — both profiles serve it from the PV.
|
||
|
|
#
|
||
|
|
# Usage:
|
||
|
|
# nu scripts/build/distro.nu [profile] # profile: leptos-hydration | htmx-ssr
|
||
|
|
# nu scripts/build/distro.nu --out dist --skip-css
|
||
|
|
|
||
|
|
def detect-profile [project_root: string]: nothing -> string {
|
||
|
|
let dev_root = ($env.DEV_ROOT? | default "/Users/Akasha/Development")
|
||
|
|
let detector = $"($dev_root)/rustelo/scripts/check-wasm-needed.nu"
|
||
|
|
if ($detector | path exists) {
|
||
|
|
let res = (do {
|
||
|
|
cd $project_root
|
||
|
|
^nu $detector --routes-dir site/config --workspace-config site/config/rendering.ncl
|
||
|
|
} | complete)
|
||
|
|
match $res.exit_code {
|
||
|
|
0 => "leptos-hydration"
|
||
|
|
1 => "htmx-ssr"
|
||
|
|
_ => { error make { msg: $"check-wasm-needed.nu failed: ($res.stderr | str trim)" } }
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
open $"($project_root)/site/config/rendering.ncl"
|
||
|
|
| parse --regex 'default_profile = "(?P<p>[^"]+)"' | get p?.0? | default "leptos-hydration"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
def pick-tar []: nothing -> string {
|
||
|
|
let gtar = (do { ^which gtar } | complete)
|
||
|
|
if $gtar.exit_code == 0 { ($gtar.stdout | str trim) } else { "tar" }
|
||
|
|
}
|
||
|
|
|
||
|
|
def main [
|
||
|
|
profile?: string
|
||
|
|
--out: string = "dist"
|
||
|
|
--skip-css
|
||
|
|
]: nothing -> nothing {
|
||
|
|
let project_root = ($env.FILE_PWD | path dirname | path dirname) # scripts/build → root
|
||
|
|
let manifest = $"($project_root)/provisioning/distro.ncl"
|
||
|
|
|
||
|
|
if not ($manifest | path exists) { error make { msg: $"manifest not found: ($manifest)" } }
|
||
|
|
|
||
|
|
let resolved = if ($profile | is-not-empty) {
|
||
|
|
if $profile not-in ["leptos-hydration" "htmx-ssr"] {
|
||
|
|
error make { msg: $"invalid profile '($profile)' (leptos-hydration | htmx-ssr)" }
|
||
|
|
}
|
||
|
|
$profile
|
||
|
|
} else {
|
||
|
|
detect-profile $project_root
|
||
|
|
}
|
||
|
|
print $"profile: ($resolved)"
|
||
|
|
|
||
|
|
let distro = (^nickel export $manifest --format json | from json)
|
||
|
|
let site_tree = $distro.site_tree
|
||
|
|
let image_only = ($distro.image_only | get $resolved)
|
||
|
|
let wanted = ($site_tree ++ $image_only)
|
||
|
|
|
||
|
|
# Refresh website.css so the PV-served stylesheet matches current sources.
|
||
|
|
if not $skip_css {
|
||
|
|
print "css: rebuilding (pnpm run css:build)"
|
||
|
|
do { cd $project_root; ^pnpm run css:build } | complete
|
||
|
|
| if $in.exit_code != 0 { error make { msg: "css:build failed" } } else { ignore }
|
||
|
|
}
|
||
|
|
|
||
|
|
let present = ($wanted | where { |p| ($project_root | path join $p) | path exists })
|
||
|
|
let missing = ($wanted | where { |p| not (($project_root | path join $p) | path exists) })
|
||
|
|
for m in $missing {
|
||
|
|
if ($m | str contains "pkg") {
|
||
|
|
print $"(ansi yellow)warning:(ansi reset) ($m) missing — run `cargo leptos build --release` first for leptos-hydration"
|
||
|
|
} else {
|
||
|
|
print $"(ansi yellow)warning:(ansi reset) manifest path absent: ($m)"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if ($present | is-empty) { error make { msg: "nothing to pack — all manifest paths absent" } }
|
||
|
|
|
||
|
|
let timestamp = (date now | format date "%Y%m%dT%H%M%S")
|
||
|
|
let git_sha = (do { cd $project_root; ^git rev-parse --short HEAD } | complete
|
||
|
|
| if $in.exit_code == 0 { $in.stdout | str trim } else { "unknown" })
|
||
|
|
|
||
|
|
# Normalise both sources into the PV layout rooted at /var/www. Source paths
|
||
|
|
# diverge (site/* are already PV-shaped; the Leptos pkg is at target/site/pkg
|
||
|
|
# but must land at site/pkg next to the binary's WASM). Stage so the archive
|
||
|
|
# is the merged tree — unpacked with `tar -C /var/www` like content.nu does.
|
||
|
|
let stage = (^mktemp -d | str trim)
|
||
|
|
for src in $present {
|
||
|
|
let dest = if ($src | str starts-with "target/site/") {
|
||
|
|
$src | str replace "target/site/" "site/"
|
||
|
|
} else { $src }
|
||
|
|
let dest_abs = ($stage | path join $dest)
|
||
|
|
mkdir ($dest_abs | path dirname)
|
||
|
|
^cp -R ($project_root | path join $src) $dest_abs
|
||
|
|
}
|
||
|
|
|
||
|
|
let out_dir = if ($out | str starts-with "/") { $out } else { $project_root | path join $out }
|
||
|
|
mkdir $out_dir
|
||
|
|
let outfile = $"($out_dir)/website-($resolved)-($timestamp).tgz"
|
||
|
|
let manifest_out = $"($out_dir)/website-($resolved)-($timestamp).manifest.json"
|
||
|
|
|
||
|
|
{
|
||
|
|
version: $timestamp, profile: $resolved, git_sha: $git_sha,
|
||
|
|
site_tree: $site_tree, image_only: $image_only, packed: $present,
|
||
|
|
} | to json | save -f $manifest_out
|
||
|
|
|
||
|
|
let tar_bin = (pick-tar)
|
||
|
|
do { ^$tar_bin --exclude='.DS_Store' -czf $outfile -C $stage site } | complete
|
||
|
|
| if $in.exit_code != 0 { ^rm -rf $stage; error make { msg: "tar failed" } } else { ignore }
|
||
|
|
^rm -rf $stage
|
||
|
|
|
||
|
|
let size = (ls $outfile | get size | first)
|
||
|
|
print $"(ansi green)✅(ansi reset) ($outfile) (($size))"
|
||
|
|
print $" manifest: ($manifest_out)"
|
||
|
|
print $" layout: archive root = site/ → unpack with: tar -xzf <tarball> -C /var/www"
|
||
|
|
}
|