feat(admin-config-tool): install standalone xceadmin binary via meson

xceadmin's custom_target only built+tested (stamp-file output, no
install:true) — nix build .#xcecore succeeded but shipped nothing in
result/bin, unlike every other component.

Add meson.add_install_script('meson-install.sh'): copies the
xceadmin/xcecommon package dirs (not the whole build-dir venv, whose
pip-generated shebang hardcodes a build path that stops existing after
the build) into $out/lib/xceadmin-site, then writes a wrapper at
$out/bin/xceadmin whose shebang and PYTHONPATH are resolved against
the install script's own nix build environment — real /nix/store
paths for python3 and each dependency (pycapnp, pyyaml, jsonschema,
click), so nix's reference scanner keeps them alive in the closure.
No venv activation needed at runtime.

Verified: meson install --destdir and nix build --option sandbox
false .#xcecore both produce a working result/bin/xceadmin, runnable
standalone with a stripped-down PATH-only environment.
This commit is contained in:
Rongsong Shen 2026-07-22 11:10:40 +00:00
parent e4fd9e1d3f
commit 893a01db7b
2 changed files with 47 additions and 0 deletions

41
src/xceadmin/meson-install.sh Executable file
View file

@ -0,0 +1,41 @@
#!/usr/bin/env bash
# meson install-time script (meson.add_install_script) -- runs after the
# xceadmin custom_target (build_by_default) has already installed+tested
# into its own build-dir venv (meson-build.sh). This script does NOT copy
# that venv wholesale: pip's generated console_scripts wrapper hardcodes
# the *build-directory* absolute path in its shebang, which stops existing
# once the build dir is cleaned up -- copying it verbatim into $out would
# ship a binary with a shebang pointing at nowhere.
#
# Instead: copy just the xceadmin/xcecommon package dirs (pure files, no
# shebang) into $out, and hand-write a wrapper whose shebang and PYTHONPATH
# are resolved against *this* install script's own environment (python3
# and the nix-provided pycapnp/pyyaml/jsonschema/click site-packages come
# from nativeBuildInputs, same as every other phase of this derivation) --
# every path baked in below is a real /nix/store path, so nix's reference
# scanner picks each one up as a proper runtime dependency of $out.
set -euo pipefail
DESTDIR_PREFIX="$MESON_INSTALL_DESTDIR_PREFIX"
PYTHON="$(command -v python3)"
VENV_SITE_GLOB=("$MESON_BUILD_ROOT"/xceadmin/.venv/lib/python3.*/site-packages)
VENV_SITE="${VENV_SITE_GLOB[0]}"
if [ ! -d "$VENV_SITE/xceadmin" ]; then
echo "meson-install.sh: expected $VENV_SITE/xceadmin from the xceadmin build step, not found" >&2
exit 1
fi
SITE_DIR="$DESTDIR_PREFIX/lib/xceadmin-site"
mkdir -p "$SITE_DIR" "$DESTDIR_PREFIX/bin"
rm -rf "$SITE_DIR/xceadmin" "$SITE_DIR/xcecommon"
cp -r "$VENV_SITE/xceadmin" "$VENV_SITE/xcecommon" "$SITE_DIR/"
cat > "$DESTDIR_PREFIX/bin/xceadmin" <<WRAPPER
#!/usr/bin/env bash
export PYTHONPATH="$SITE_DIR:${PYTHONPATH:-}"
exec "$PYTHON" -m xceadmin.cli "\$@"
WRAPPER
chmod +x "$DESTDIR_PREFIX/bin/xceadmin"
echo "=== xceadmin (meson install): wrapper installed at $DESTDIR_PREFIX/bin/xceadmin ==="

View file

@ -32,3 +32,9 @@ xceadmin_stamp = custom_target('xceadmin',
build_always_stale: true,
console: true,
)
# Installs a standalone $out/bin/xceadmin -- runs after xceadmin_stamp
# (ninja install always depends on build_by_default targets first) so the
# build-dir venv it copies from already exists. See meson-install.sh for
# why this isn't a plain `cp` of that venv.
meson.add_install_script('meson-install.sh')