From f7858d4ec44fae8aaab0c01887e6b77af39e703b Mon Sep 17 00:00:00 2001 From: Oier Bravo Urtasun Date: Sun, 7 Jun 2026 22:07:35 +0200 Subject: [PATCH] refactor(pack): template custom mod metadata so BASE_DOMAIN isn't frozen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The download URL is the only domain-dependent field in the external-file metadata. Make mods/*.pw.toml build output rendered from committed mods/*.pw.toml.tmpl (url uses ${BASE_DOMAIN}); render-config.sh and add-custom-mod.sh render them + packwiz refresh at deploy/add time. - pack/.packwizignore: keep *.pw.toml.tmpl out of the index - gitignore rendered pack/mods/*.pw.toml + pack/index.toml (build output) - seed a minimal index.toml before refresh (packwiz won't bootstrap one) - add-custom-mod renders inline (BASE_DOMAIN only) — no coupling to dnsmasq's HOST_LAN_IP Domain changes now just need a re-render, not a metadata rewrite. Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitignore | 4 ++ pack/.packwizignore | 3 ++ pack/index.toml | 54 ------------------- ...balm-neoforge-1-21-1-21-0-58.pw.toml.tmpl} | 2 +- ...omskinloader-universal-14-28.pw.toml.tmpl} | 2 +- ...ials-neoforge-1-21-1-21-1-15.pw.toml.tmpl} | 2 +- ...jade-1-21-1-neoforge-15-10-5.pw.toml.tmpl} | 2 +- ...addons-1-21-1-neoforge-6-1-0.pw.toml.tmpl} | 2 +- ...-1-21-1-neoforge-19-27-0-340.pw.toml.tmpl} | 2 +- ...ssions-neoforge-1-21-1-4-0-5.pw.toml.tmpl} | 2 +- ...ces-neoforge-1-21-1-1-6-0-17.pw.toml.tmpl} | 2 +- ...weaks-neoforge-mc1-21-2-26-1.pw.toml.tmpl} | 2 +- tooling/add-custom-mod.sh | 39 +++++++++----- tooling/render-config.sh | 16 ++++++ 14 files changed, 59 insertions(+), 75 deletions(-) create mode 100644 pack/.packwizignore delete mode 100644 pack/index.toml rename pack/mods/{balm-neoforge-1-21-1-21-0-58.pw.toml => balm-neoforge-1-21-1-21-0-58.pw.toml.tmpl} (73%) rename pack/mods/{customskinloader-universal-14-28.pw.toml => customskinloader-universal-14-28.pw.toml.tmpl} (73%) rename pack/mods/{inventoryessentials-neoforge-1-21-1-21-1-15.pw.toml => inventoryessentials-neoforge-1-21-1-21-1-15.pw.toml.tmpl} (72%) rename pack/mods/{jade-1-21-1-neoforge-15-10-5.pw.toml => jade-1-21-1-neoforge-15-10-5.pw.toml.tmpl} (73%) rename pack/mods/{jadeaddons-1-21-1-neoforge-6-1-0.pw.toml => jadeaddons-1-21-1-neoforge-6-1-0.pw.toml.tmpl} (73%) rename pack/mods/{jei-1-21-1-neoforge-19-27-0-340.pw.toml => jei-1-21-1-neoforge-19-27-0-340.pw.toml.tmpl} (73%) rename pack/mods/{justenoughprofessions-neoforge-1-21-1-4-0-5.pw.toml => justenoughprofessions-neoforge-1-21-1-4-0-5.pw.toml.tmpl} (72%) rename pack/mods/{justenoughresources-neoforge-1-21-1-1-6-0-17.pw.toml => justenoughresources-neoforge-1-21-1-1-6-0-17.pw.toml.tmpl} (72%) rename pack/mods/{mousetweaks-neoforge-mc1-21-2-26-1.pw.toml => mousetweaks-neoforge-mc1-21-2-26-1.pw.toml.tmpl} (73%) diff --git a/.gitignore b/.gitignore index 6c870ab..53f0b57 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,10 @@ runtime/authlib-injector.jar # rendered configs (from tooling/render-config.sh) drasl/config/config.toml dnsmasq/dnsmasq.conf +# packwiz external-file metadata + index are rendered from *.pw.toml.tmpl +# (domain-dependent build output); source of truth is the .tmpl + custom/ jars. +pack/mods/*.pw.toml +pack/index.toml # vendored / mirrored binaries mirror/ diff --git a/pack/.packwizignore b/pack/.packwizignore new file mode 100644 index 0000000..37ea812 --- /dev/null +++ b/pack/.packwizignore @@ -0,0 +1,3 @@ +# Template sources for external-file metadata — rendered to *.pw.toml by +# tooling/render-config.sh. packwiz must NOT index the templates themselves. +*.pw.toml.tmpl diff --git a/pack/index.toml b/pack/index.toml deleted file mode 100644 index 1ecd62a..0000000 --- a/pack/index.toml +++ /dev/null @@ -1,54 +0,0 @@ -hash-format = "sha256" - -[[files]] -file = "CustomSkinLoader/CustomSkinLoader.json" -hash = "20f015b837d4178cc1ba6ca074e746dea91b2b97810587bae0fc4e55cf98b1aa" - -[[files]] -file = "README.md" -hash = "3915be75668def5a70667584c7aebdc1ee9a7f7dd9479cb10fb174aad40a6b4e" - -[[files]] -file = "mods/balm-neoforge-1-21-1-21-0-58.pw.toml" -hash = "b70538546ed7ff18186f9319bb00a71a1062ced87c36dd8733cf85dc4bc3ea3c" -metafile = true - -[[files]] -file = "mods/customskinloader-universal-14-28.pw.toml" -hash = "1b9cd3d7819f06130c0e5bf81c6b91452d43651c3fdb304f62d27ca505b9e30f" -metafile = true - -[[files]] -file = "mods/inventoryessentials-neoforge-1-21-1-21-1-15.pw.toml" -hash = "6feb22b4a4561dffde0e6b5a2dbd82d69ba4180295e6c44e5c9ac919db727e74" -metafile = true - -[[files]] -file = "mods/jade-1-21-1-neoforge-15-10-5.pw.toml" -hash = "d35f921f7e076b71630f6ff63dc11d2b1f32321c1aa7787ba3e62dc73b455d16" -metafile = true - -[[files]] -file = "mods/jadeaddons-1-21-1-neoforge-6-1-0.pw.toml" -hash = "b551252e2ece3f005f3ee8094e697ccc5378236adea92814f61ec0cc0a33a7bb" -metafile = true - -[[files]] -file = "mods/jei-1-21-1-neoforge-19-27-0-340.pw.toml" -hash = "001aad372d78d0dd485dfc5f82bffe6b71dd06416cba0d349dbb0dedd048064d" -metafile = true - -[[files]] -file = "mods/justenoughprofessions-neoforge-1-21-1-4-0-5.pw.toml" -hash = "9aa5608992c47c6173020a35bf5f98454f3dbb42ed2815c9736379b4019199d1" -metafile = true - -[[files]] -file = "mods/justenoughresources-neoforge-1-21-1-1-6-0-17.pw.toml" -hash = "a49e5661ea3edaeb992675502e2e4a6bc41bc18b439400f340c77ad8d43550b7" -metafile = true - -[[files]] -file = "mods/mousetweaks-neoforge-mc1-21-2-26-1.pw.toml" -hash = "0a3c27696c5641db806ed2bbe743cb282138365702dc21060a3c888826ea724e" -metafile = true diff --git a/pack/mods/balm-neoforge-1-21-1-21-0-58.pw.toml b/pack/mods/balm-neoforge-1-21-1-21-0-58.pw.toml.tmpl similarity index 73% rename from pack/mods/balm-neoforge-1-21-1-21-0-58.pw.toml rename to pack/mods/balm-neoforge-1-21-1-21-0-58.pw.toml.tmpl index 4854cf1..57da439 100644 --- a/pack/mods/balm-neoforge-1-21-1-21-0-58.pw.toml +++ b/pack/mods/balm-neoforge-1-21-1-21-0-58.pw.toml.tmpl @@ -3,6 +3,6 @@ filename = "balm-neoforge-1.21.1-21.0.58.jar" side = "both" [download] -url = "http://pack.ulicraft.net/custom/balm-neoforge-1.21.1-21.0.58.jar" +url = "http://pack.${BASE_DOMAIN}/custom/balm-neoforge-1.21.1-21.0.58.jar" hash-format = "sha256" hash = "aa2463747bad4c2351869226ea7bce7839510dfd2ac387f8d1588b1ce9309c67" diff --git a/pack/mods/customskinloader-universal-14-28.pw.toml b/pack/mods/customskinloader-universal-14-28.pw.toml.tmpl similarity index 73% rename from pack/mods/customskinloader-universal-14-28.pw.toml rename to pack/mods/customskinloader-universal-14-28.pw.toml.tmpl index 3f4dd29..1903db8 100644 --- a/pack/mods/customskinloader-universal-14-28.pw.toml +++ b/pack/mods/customskinloader-universal-14-28.pw.toml.tmpl @@ -3,6 +3,6 @@ filename = "CustomSkinLoader_Universal-14.28.jar" side = "both" [download] -url = "http://pack.ulicraft.net/custom/CustomSkinLoader_Universal-14.28.jar" +url = "http://pack.${BASE_DOMAIN}/custom/CustomSkinLoader_Universal-14.28.jar" hash-format = "sha256" hash = "0008fb0a91dd1e84d52162cfe96addb5f6aed3b76d426ea7305d7624e31f1894" diff --git a/pack/mods/inventoryessentials-neoforge-1-21-1-21-1-15.pw.toml b/pack/mods/inventoryessentials-neoforge-1-21-1-21-1-15.pw.toml.tmpl similarity index 72% rename from pack/mods/inventoryessentials-neoforge-1-21-1-21-1-15.pw.toml rename to pack/mods/inventoryessentials-neoforge-1-21-1-21-1-15.pw.toml.tmpl index 05de430..99ba2aa 100644 --- a/pack/mods/inventoryessentials-neoforge-1-21-1-21-1-15.pw.toml +++ b/pack/mods/inventoryessentials-neoforge-1-21-1-21-1-15.pw.toml.tmpl @@ -3,6 +3,6 @@ filename = "inventoryessentials-neoforge-1.21.1-21.1.15.jar" side = "both" [download] -url = "http://pack.ulicraft.net/custom/inventoryessentials-neoforge-1.21.1-21.1.15.jar" +url = "http://pack.${BASE_DOMAIN}/custom/inventoryessentials-neoforge-1.21.1-21.1.15.jar" hash-format = "sha256" hash = "b7a5c5526a45256551543419ba2b5d54e56c585d76a645a8cea8cb8ea843ae2c" diff --git a/pack/mods/jade-1-21-1-neoforge-15-10-5.pw.toml b/pack/mods/jade-1-21-1-neoforge-15-10-5.pw.toml.tmpl similarity index 73% rename from pack/mods/jade-1-21-1-neoforge-15-10-5.pw.toml rename to pack/mods/jade-1-21-1-neoforge-15-10-5.pw.toml.tmpl index 65fa540..c6a810a 100644 --- a/pack/mods/jade-1-21-1-neoforge-15-10-5.pw.toml +++ b/pack/mods/jade-1-21-1-neoforge-15-10-5.pw.toml.tmpl @@ -3,6 +3,6 @@ filename = "Jade-1.21.1-NeoForge-15.10.5.jar" side = "both" [download] -url = "http://pack.ulicraft.net/custom/Jade-1.21.1-NeoForge-15.10.5.jar" +url = "http://pack.${BASE_DOMAIN}/custom/Jade-1.21.1-NeoForge-15.10.5.jar" hash-format = "sha256" hash = "067bb4b007e1d6f6b79f0afe99c91252aa825472b99a76d33a60d24442f9e92d" diff --git a/pack/mods/jadeaddons-1-21-1-neoforge-6-1-0.pw.toml b/pack/mods/jadeaddons-1-21-1-neoforge-6-1-0.pw.toml.tmpl similarity index 73% rename from pack/mods/jadeaddons-1-21-1-neoforge-6-1-0.pw.toml rename to pack/mods/jadeaddons-1-21-1-neoforge-6-1-0.pw.toml.tmpl index 663fc64..3d40e43 100644 --- a/pack/mods/jadeaddons-1-21-1-neoforge-6-1-0.pw.toml +++ b/pack/mods/jadeaddons-1-21-1-neoforge-6-1-0.pw.toml.tmpl @@ -3,6 +3,6 @@ filename = "JadeAddons-1.21.1-NeoForge-6.1.0.jar" side = "both" [download] -url = "http://pack.ulicraft.net/custom/JadeAddons-1.21.1-NeoForge-6.1.0.jar" +url = "http://pack.${BASE_DOMAIN}/custom/JadeAddons-1.21.1-NeoForge-6.1.0.jar" hash-format = "sha256" hash = "5f242668ad710092964d4d9afda8a94fa2401665ea13eea67d55d07e4dff8a64" diff --git a/pack/mods/jei-1-21-1-neoforge-19-27-0-340.pw.toml b/pack/mods/jei-1-21-1-neoforge-19-27-0-340.pw.toml.tmpl similarity index 73% rename from pack/mods/jei-1-21-1-neoforge-19-27-0-340.pw.toml rename to pack/mods/jei-1-21-1-neoforge-19-27-0-340.pw.toml.tmpl index cd406f6..72eda59 100644 --- a/pack/mods/jei-1-21-1-neoforge-19-27-0-340.pw.toml +++ b/pack/mods/jei-1-21-1-neoforge-19-27-0-340.pw.toml.tmpl @@ -3,6 +3,6 @@ filename = "jei-1.21.1-neoforge-19.27.0.340.jar" side = "both" [download] -url = "http://pack.ulicraft.net/custom/jei-1.21.1-neoforge-19.27.0.340.jar" +url = "http://pack.${BASE_DOMAIN}/custom/jei-1.21.1-neoforge-19.27.0.340.jar" hash-format = "sha256" hash = "8aaf547432f1b4958239b036356b910692fe40f858c3073d996f56bbf7c99826" diff --git a/pack/mods/justenoughprofessions-neoforge-1-21-1-4-0-5.pw.toml b/pack/mods/justenoughprofessions-neoforge-1-21-1-4-0-5.pw.toml.tmpl similarity index 72% rename from pack/mods/justenoughprofessions-neoforge-1-21-1-4-0-5.pw.toml rename to pack/mods/justenoughprofessions-neoforge-1-21-1-4-0-5.pw.toml.tmpl index be9db83..833671d 100644 --- a/pack/mods/justenoughprofessions-neoforge-1-21-1-4-0-5.pw.toml +++ b/pack/mods/justenoughprofessions-neoforge-1-21-1-4-0-5.pw.toml.tmpl @@ -3,6 +3,6 @@ filename = "JustEnoughProfessions-neoforge-1.21.1-4.0.5.jar" side = "both" [download] -url = "http://pack.ulicraft.net/custom/JustEnoughProfessions-neoforge-1.21.1-4.0.5.jar" +url = "http://pack.${BASE_DOMAIN}/custom/JustEnoughProfessions-neoforge-1.21.1-4.0.5.jar" hash-format = "sha256" hash = "b320b47f1791f56df9e1a05138f0e312e6e54541945ff15f2f1fd398cd1d4d9d" diff --git a/pack/mods/justenoughresources-neoforge-1-21-1-1-6-0-17.pw.toml b/pack/mods/justenoughresources-neoforge-1-21-1-1-6-0-17.pw.toml.tmpl similarity index 72% rename from pack/mods/justenoughresources-neoforge-1-21-1-1-6-0-17.pw.toml rename to pack/mods/justenoughresources-neoforge-1-21-1-1-6-0-17.pw.toml.tmpl index d47af2c..35350db 100644 --- a/pack/mods/justenoughresources-neoforge-1-21-1-1-6-0-17.pw.toml +++ b/pack/mods/justenoughresources-neoforge-1-21-1-1-6-0-17.pw.toml.tmpl @@ -3,6 +3,6 @@ filename = "JustEnoughResources-NeoForge-1.21.1-1.6.0.17.jar" side = "both" [download] -url = "http://pack.ulicraft.net/custom/JustEnoughResources-NeoForge-1.21.1-1.6.0.17.jar" +url = "http://pack.${BASE_DOMAIN}/custom/JustEnoughResources-NeoForge-1.21.1-1.6.0.17.jar" hash-format = "sha256" hash = "7a47d69b5530704690d5a5f0726cd74a2d6c57df17dd4a8589c4ab5212f91460" diff --git a/pack/mods/mousetweaks-neoforge-mc1-21-2-26-1.pw.toml b/pack/mods/mousetweaks-neoforge-mc1-21-2-26-1.pw.toml.tmpl similarity index 73% rename from pack/mods/mousetweaks-neoforge-mc1-21-2-26-1.pw.toml rename to pack/mods/mousetweaks-neoforge-mc1-21-2-26-1.pw.toml.tmpl index 9719afa..991cca6 100644 --- a/pack/mods/mousetweaks-neoforge-mc1-21-2-26-1.pw.toml +++ b/pack/mods/mousetweaks-neoforge-mc1-21-2-26-1.pw.toml.tmpl @@ -3,6 +3,6 @@ filename = "MouseTweaks-neoforge-mc1.21-2.26.1.jar" side = "both" [download] -url = "http://pack.ulicraft.net/custom/MouseTweaks-neoforge-mc1.21-2.26.1.jar" +url = "http://pack.${BASE_DOMAIN}/custom/MouseTweaks-neoforge-mc1.21-2.26.1.jar" hash-format = "sha256" hash = "68e6f4201c5de97b77929a7215c9552495696ca6a3bf3ae4eacc34e135f6cc8b" diff --git a/tooling/add-custom-mod.sh b/tooling/add-custom-mod.sh index b593975..06c27c2 100755 --- a/tooling/add-custom-mod.sh +++ b/tooling/add-custom-mod.sh @@ -2,8 +2,10 @@ # add-custom-mod.sh — add LOCAL jar(s) to the packwiz pack as "external files". # # Implements the "Other external files" flow from -# https://packwiz.infra.link/tutorials/creating/adding-mods/ : a hand-written -# .pw.toml that points at a stable download URL + sha256, then refresh. +# https://packwiz.infra.link/tutorials/creating/adding-mods/ : a .pw.toml +# that points at a stable download URL + sha256, then refresh. Here the metadata +# is written as a TEMPLATE (.pw.toml.tmpl) with a ${BASE_DOMAIN} +# placeholder and rendered by render-config.sh, so the domain is never frozen. # # Since the jars are local (no public URL), we HOST them on the caddy pack # server: each jar is copied to the top-level ./custom/ dir (OUTSIDE ./pack, so @@ -56,6 +58,7 @@ case "$SIDE" in both|client|server) ;; *) die "invalid --side '$SIDE' (both|clie # ---- preflight ------------------------------------------------------------- command -v packwiz >/dev/null 2>&1 || die "missing required tool: packwiz (https://packwiz.infra.link)" command -v sha256sum >/dev/null 2>&1 || die "missing required tool: sha256sum" +command -v envsubst >/dev/null 2>&1 || die "missing required tool: envsubst (gettext)" [ -f .env ] || die ".env not found (copy .env.example and fill it)" # shellcheck disable=SC1091 set -a; . ./.env; set +a @@ -88,9 +91,12 @@ add_one() { # $1 = jar path. Uses NAME (single-jar only), SIDE, FORCE, BASE_DOM slug="$(slugify "$name")" [ -n "$slug" ] || die "could not derive a slug from name '$name'" - meta="pack/mods/${slug}.pw.toml" + # Metadata is a TEMPLATE: the download URL keeps a literal ${BASE_DOMAIN} + # placeholder, rendered to the real .pw.toml by render-config.sh at deploy so + # the domain is never frozen into a committed file. + meta="pack/mods/${slug}.pw.toml.tmpl" dest="custom/${filename}" - url="http://pack.${BASE_DOMAIN}/custom/${filename}" + url_tmpl='http://pack.${BASE_DOMAIN}/custom/'"${filename}" if [ "$FORCE" -ne 1 ]; then [ -e "$meta" ] && die "metadata exists: $meta (use --force to overwrite)" @@ -99,7 +105,7 @@ add_one() { # $1 = jar path. Uses NAME (single-jar only), SIDE, FORCE, BASE_DOM hash="$(sha256sum -- "$jar" | cut -d' ' -f1)" # Skip the copy when the source already IS the hosted file (regen-in-place, - # e.g. `add-custom-mod.sh custom --force` to refresh URLs after a domain change). + # e.g. `add-custom-mod.sh custom --force` to rewrite metadata). [ "$dest" -ef "$jar" ] || cp -- "$jar" "$dest" cat > "$meta" < ${url} (${SIDE}, sha256 ${hash:0:12}…)" + echo " + ${filename} -> http://pack.${BASE_DOMAIN}/custom/${filename} (${SIDE}, sha256 ${hash:0:12}…)" } log "adding ${#JARS[@]} jar(s), side=${SIDE}" for j in "${JARS[@]}"; do add_one "$j"; done -# ---- refresh once ---------------------------------------------------------- -# packwiz refresh rebuilds index.toml (and pack.toml's index hash) so the new -# .pw.toml files are picked up. Must run inside the pack dir. +# ---- render + refresh once ------------------------------------------------- +# Render every metadata template -> .pw.toml (inject ${BASE_DOMAIN} only — no +# coupling to dnsmasq's HOST_LAN_IP), then rebuild the packwiz index. This is +# the same render render-config.sh does at deploy; kept inline so adding a mod +# works with just BASE_DOMAIN set. +log "rendering metadata + refreshing index" +for t in pack/mods/*.pw.toml.tmpl; do + envsubst '${BASE_DOMAIN}' < "$t" > "${t%.tmpl}" +done +# index.toml is gitignored build output; seed a minimal one so packwiz refresh +# (which won't bootstrap a missing index) has something to populate. +[ -f pack/index.toml ] || printf 'hash-format = "sha256"\n' > pack/index.toml ( cd pack && packwiz refresh ) -log "packwiz refresh done — ${#JARS[@]} mod(s) added to the pack" -echo " commit custom/*.jar, pack/mods/*.pw.toml, pack/index.toml, pack/pack.toml" +log "done — ${#JARS[@]} mod(s) added to the pack" +echo " commit: custom/*.jar + pack/mods/*.pw.toml.tmpl (rendered .pw.toml/index are gitignored)" diff --git a/tooling/render-config.sh b/tooling/render-config.sh index b1eeb9c..1a2b289 100755 --- a/tooling/render-config.sh +++ b/tooling/render-config.sh @@ -19,3 +19,19 @@ render() { # $1=template $2=output render drasl/config/config.toml.tmpl drasl/config/config.toml render dnsmasq/dnsmasq.conf.tmpl dnsmasq/dnsmasq.conf + +# packwiz external-file metadata: render every pack/mods/*.pw.toml.tmpl into its +# .pw.toml (injects ${BASE_DOMAIN} into the download URL), then rebuild the +# packwiz index. .packwizignore keeps the .tmpl out of the index. +shopt -s nullglob +tmpls=(pack/mods/*.pw.toml.tmpl) +shopt -u nullglob +if [ "${#tmpls[@]}" -gt 0 ]; then + for t in "${tmpls[@]}"; do render "$t" "${t%.tmpl}"; done + command -v packwiz >/dev/null 2>&1 || { echo "packwiz not found — cannot refresh index" >&2; exit 1; } + # index.toml is gitignored build output; seed a minimal one so packwiz refresh + # (which won't bootstrap a missing index) has something to populate. + [ -f pack/index.toml ] || printf 'hash-format = "sha256"\n' > pack/index.toml + ( cd pack && packwiz refresh ) + echo "refreshed packwiz index (${#tmpls[@]} external metafiles)" +fi