#!/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

[^"]+)"' | 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 -C /var/www" }