diff --git a/docs/getting-started/full-stack-install.md b/docs/getting-started/full-stack-install.md index dc1cd0496..f74a0e6e8 100644 --- a/docs/getting-started/full-stack-install.md +++ b/docs/getting-started/full-stack-install.md @@ -42,13 +42,15 @@ OpenXR runtime via `HKLM\Software\Khronos\OpenXR\1\ActiveRuntime`. |---|---| | _(none)_ | macOS: runtime only. Windows: runtime + Shell + Leia plug-in. | | `--with mcp` | Also install DisplayXR MCP Tools (macOS: warn-and-skip until a `.pkg` is published). | -| `--with-demos` | Clone each `DisplayXR/displayxr-demo-*` repo into `./demos//`. Does not build them. | +| `--with-demos` | Also **install** each demo's prebuilt release asset (same download → silent-install → marker-check path as the runtime — no source build, so a contributor's graphics toolchain / Vulkan SDK is irrelevant). A demo with no release asset for this OS warn-and-skips. | +| `--with-demo-sources` | **Clone** each `DisplayXR/displayxr-demo-*` repo into `./demos//` for building from source. Does not build them — see each demo's README. Independent of `--with-demos`. | | `--dry-run` | Print every download / install command without running it. | | `--uninstall` | macOS: chain `/Library/Application Support/DisplayXR/uninstall.sh`. Windows: silent-uninstall every `Publisher=DisplayXR` component. | | `-h`, `--help` | Show usage. | -`--with` and `--with-demos` combine freely. `--dry-run` works with all -other flags. +`--with`, `--with-demos`, and `--with-demo-sources` combine freely (pass +both demo flags to install the released demos *and* clone their sources). +`--dry-run` works with all other flags. ## Prerequisites diff --git a/scripts/lib/components.sh b/scripts/lib/components.sh index b921a0cf1..c252708cf 100755 --- a/scripts/lib/components.sh +++ b/scripts/lib/components.sh @@ -14,10 +14,20 @@ # successful install on macOS. Empty = skip check. # COMPONENT_INSTALL_MARKER_WINDOWS_ Registry key whose existence proves a # successful install on Windows. Empty = skip check. +# COMPONENT_PIN_KEY_ versions.json key holding this component's tag, +# when it differs from (e.g. nested under +# "demos"). Empty = the pin key equals . # # A blank platform glob means "warn-and-skip on this platform" — used today # for shell/leia/mcp on macOS. # +# Demos are *installed from their prebuilt release asset*, exactly like +# runtime/shell/leia/mcp — never built from source. So `--with-demos` is +# insensitive to a contributor's build environment (Vulkan SDK, graphics +# toolchains, …): the binary was already compiled by the demo's own CI. +# Demos that ship no release installer are source-only and belong under +# `--with-demo-sources` (clone), not in DEMO_COMPONENTS below. +# # `scripts/setup-displayxr.bat` mirrors these tables inline at the top of the # file (Windows batch can't source bash). Keep both in sync when bumping # components or release contracts. @@ -69,10 +79,18 @@ COMPONENT_PKG_MACOS_gauss_demo="DisplayXRGaussianSplat-*.pkg" COMPONENT_EXE_WINDOWS_gauss_demo="DisplayXRGaussianSplatSetup-*.exe" COMPONENT_INSTALL_MARKER_MACOS_gauss_demo="/Applications/Gaussian Splat Viewer.app" COMPONENT_INSTALL_MARKER_WINDOWS_gauss_demo="HKLM\\Software\\DisplayXR\\Demos\\GaussianSplat" +# Pin lives under the nested "demos" map in versions.json, not a top-level key. +COMPONENT_PIN_KEY_gauss_demo="demos.gaussiansplat" + +# Demo components installed by --with-demos (prebuilt release assets only). +# Space-separated; add a demo here once it ships a release installer that CI +# attaches on a v* tag. The `setup-displayxr.bat` mirror keeps its own copy of +# this list — keep both in sync. +DEMO_COMPONENTS="gauss_demo" # Helper: look up a per-component field for the current platform. -# $1 = component name (runtime, shell, leia_plugin, mcp_tools) -# $2 = field (REPO, PKG_MACOS, EXE_WINDOWS, INSTALL_MARKER_MACOS) +# $1 = component name (runtime, shell, leia_plugin, mcp_tools, gauss_demo) +# $2 = field (REPO, PKG_MACOS, EXE_WINDOWS, INSTALL_MARKER_MACOS, PIN_KEY) # Prints the value (may be empty). component_field() { local var="COMPONENT_${2}_${1}" diff --git a/scripts/setup-displayxr.bat b/scripts/setup-displayxr.bat index 5f7168e2a..471c9eab9 100644 --- a/scripts/setup-displayxr.bat +++ b/scripts/setup-displayxr.bat @@ -11,11 +11,12 @@ REM same default-install semantics, same warn-and-skip pattern for REM components whose pinned release has no Windows asset attached. REM REM Usage: -REM scripts\setup-displayxr.bat :: runtime + shell + leia -REM scripts\setup-displayxr.bat --with mcp :: also DisplayXR MCP Tools -REM scripts\setup-displayxr.bat --with-demos :: also clone demos\ -REM scripts\setup-displayxr.bat --dry-run :: print plan, install nothing -REM scripts\setup-displayxr.bat --uninstall :: uninstall every DisplayXR-published component +REM scripts\setup-displayxr.bat :: runtime + shell + leia +REM scripts\setup-displayxr.bat --with mcp :: also DisplayXR MCP Tools +REM scripts\setup-displayxr.bat --with-demos :: also install each demo's prebuilt release +REM scripts\setup-displayxr.bat --with-demo-sources :: also clone each demo's source into demos\ +REM scripts\setup-displayxr.bat --dry-run :: print plan, install nothing +REM scripts\setup-displayxr.bat --uninstall :: uninstall every DisplayXR-published component REM scripts\setup-displayxr.bat --help REM REM Must be run from an ELEVATED command prompt (Right-click cmd.exe -> @@ -49,10 +50,16 @@ set "COMPONENT_MARKER_mcp_tools=HKLM\Software\DisplayXR\Capabilities\MCP" set "COMPONENT_REPO_gauss_demo=DisplayXR/displayxr-demo-gaussiansplat" set "COMPONENT_EXE_gauss_demo=DisplayXRGaussianSplatSetup-*.exe" set "COMPONENT_MARKER_gauss_demo=HKLM\Software\DisplayXR\Demos\GaussianSplat" +set "COMPONENT_PINKEY_gauss_demo=demos.gaussiansplat" + +REM Demo components installed by --with-demos (prebuilt release assets only). +REM Mirrors DEMO_COMPONENTS in scripts\lib\components.sh; keep in sync. +set "DEMO_COMPONENTS=gauss_demo" REM --- Default flag state --- set "WITH_MCP=0" set "WITH_DEMOS=0" +set "WITH_DEMO_SOURCES=0" set "DRY_RUN=0" set "ACTION=install" set "EXITCODE=0" @@ -65,6 +72,7 @@ if /i "%~1"=="--help" goto :show_help if /i "%~1"=="--dry-run" set "DRY_RUN=1" & shift & goto :argloop if /i "%~1"=="--uninstall" set "ACTION=uninstall" & shift & goto :argloop if /i "%~1"=="--with-demos" set "WITH_DEMOS=1" & shift & goto :argloop +if /i "%~1"=="--with-demo-sources" set "WITH_DEMO_SOURCES=1" & shift & goto :argloop if /i "%~1"=="--with" goto :arg_with echo ERROR: Unknown flag: %~1 1>&2 call :usage 1>&2 @@ -136,8 +144,13 @@ call :install_component shell "%SHELL_TAG%" call :install_component leia_plugin "%LEIA_TAG%" if "%WITH_MCP%"=="1" call :install_component mcp_tools "%MCP_TAG%" -REM --- --with-demos --- -if "%WITH_DEMOS%"=="1" call :clone_demos +REM --- --with-demos: install each demo's prebuilt release asset --- +REM After the core components so demo installers that require the runtime +REM (a hard prereq for some) find it already registered. +if "%WITH_DEMOS%"=="1" call :install_demos + +REM --- --with-demo-sources: clone demo source trees (for building) --- +if "%WITH_DEMO_SOURCES%"=="1" call :clone_demos REM --- Smoke verification --- if "%DRY_RUN%"=="0" if "%EXITCODE%"=="0" ( @@ -175,9 +188,12 @@ echo. echo Usage: scripts\setup-displayxr.bat [flags] echo. echo --with mcp Also install DisplayXR MCP Tools. -echo --with-demos Clone each DisplayXR/displayxr-demo-* repo into -echo .\demos\^\ ^(does not build them; see each -echo demo's README for build steps^). +echo --with-demos Also install each demo's prebuilt release installer +echo ^(no build needed; demos with no Windows asset skip^). +echo --with-demo-sources +echo Also clone each DisplayXR/displayxr-demo-* repo into +echo .\demos\^\ for building from source ^(does not +echo build them^). Independent of --with-demos. echo --dry-run Print everything that would be downloaded and echo installed; perform no privileged operations. echo --uninstall Silent-uninstall every DisplayXR-published component @@ -191,7 +207,7 @@ echo write to HKLM and Program Files. exit /b 0 :usage -echo Usage: scripts\setup-displayxr.bat [--with mcp] [--with-demos] [--dry-run] [--uninstall] [-h^|--help] +echo Usage: scripts\setup-displayxr.bat [--with mcp] [--with-demos] [--with-demo-sources] [--dry-run] [--uninstall] [-h^|--help] exit /b 0 REM Read a pinned tag from versions.json into the named env var. @@ -304,6 +320,19 @@ if not "%_IC_MARKER%"=="" ( echo OK %_IC_NAME% installed. exit /b 0 +REM Install each demo in %DEMO_COMPONENTS% from its prebuilt release asset. +REM Resolves each demo's versions.json pin key (COMPONENT_PINKEY_, +REM default ), reads the pin, and reuses :install_component — same +REM download + silent-install + marker-check path as the core components. +:install_demos +for %%d in (%DEMO_COMPONENTS%) do ( + set "_ID_PINKEY=!COMPONENT_PINKEY_%%d!" + if not defined _ID_PINKEY set "_ID_PINKEY=%%d" + call :read_pin "!_ID_PINKEY!" _ID_TAG + call :install_component %%d "!_ID_TAG!" +) +exit /b 0 + REM Discover and clone all DisplayXR/displayxr-demo-* repos into demos\\. :clone_demos echo. diff --git a/scripts/setup-displayxr.sh b/scripts/setup-displayxr.sh index 953be3c73..89f64f6e2 100755 --- a/scripts/setup-displayxr.sh +++ b/scripts/setup-displayxr.sh @@ -10,11 +10,12 @@ # user-facing installer release. # # Usage: -# ./scripts/setup-displayxr.sh # runtime (+ bundled sim-display) -# ./scripts/setup-displayxr.sh --with mcp # also DisplayXR MCP Tools -# ./scripts/setup-displayxr.sh --with-demos # also clone each demo into demos/ -# ./scripts/setup-displayxr.sh --dry-run # print plan, install nothing -# ./scripts/setup-displayxr.sh --uninstall # chain known uninstallers +# ./scripts/setup-displayxr.sh # runtime (+ bundled sim-display) +# ./scripts/setup-displayxr.sh --with mcp # also DisplayXR MCP Tools +# ./scripts/setup-displayxr.sh --with-demos # also install each demo's prebuilt release +# ./scripts/setup-displayxr.sh --with-demo-sources # also clone each demo's source into demos/ +# ./scripts/setup-displayxr.sh --dry-run # print plan, install nothing +# ./scripts/setup-displayxr.sh --uninstall # chain known uninstallers # ./scripts/setup-displayxr.sh --help set -euo pipefail @@ -42,6 +43,7 @@ ok() { printf '%s OK %s %s\n' "$C_GREEN" "$C_RESET" "$*"; } # --- arg parsing --- WITH_MCP=0 WITH_DEMOS=0 +WITH_DEMO_SOURCES=0 DRY_RUN=0 ACTION=install # install | uninstall | help @@ -53,9 +55,14 @@ Usage: $0 [flags] --with mcp Also install DisplayXR MCP Tools (when a macOS asset is available; warn+skip otherwise). - --with-demos Clone each DisplayXR/displayxr-demo-* repo into - ./demos// (does not build them; see each - demo's README for build steps). + --with-demos Also install each demo's prebuilt release asset + (no build needed — same install path as the runtime). + Demos without a release asset for this OS are skipped. + --with-demo-sources + Also clone each DisplayXR/displayxr-demo-* repo into + ./demos// for building from source (does not + build them; see each demo's README). Independent of + --with-demos; pass both to install and clone. --dry-run Print everything that would be downloaded and installed; perform no privileged operations. --uninstall Chain known uninstallers (runtime + sim-display @@ -77,7 +84,8 @@ while [ $# -gt 0 ]; do *) err "Unknown --with target: $1 (supported: mcp)"; exit 2 ;; esac ;; - --with-demos) WITH_DEMOS=1 ;; + --with-demos) WITH_DEMOS=1 ;; + --with-demo-sources) WITH_DEMO_SOURCES=1 ;; --dry-run) DRY_RUN=1 ;; --uninstall) ACTION=uninstall ;; -h|--help) ACTION=help ;; @@ -173,11 +181,15 @@ COMPONENTS=(runtime) install_component() { local name="$1" - local repo tag glob marker + local repo tag glob marker pin_key repo="$(component_field "$name" REPO)" glob="$(component_field "$name" PKG_MACOS)" marker="$(component_field "$name" INSTALL_MARKER_MACOS)" - tag="$(pinned_tag "$name" 2>/dev/null || true)" + # Most components' versions.json pin key is the component name; demos and + # any future nested entries override it via COMPONENT_PIN_KEY_. + pin_key="$(component_field "$name" PIN_KEY)" + [ -z "$pin_key" ] && pin_key="$name" + tag="$(pinned_tag "$pin_key" 2>/dev/null || true)" if [ -z "$tag" ]; then err "versions.json has no pin for component '$name'." @@ -206,8 +218,13 @@ install_component() { # when a pre-#279 runtime tag is selected. local asset_count asset_count="$(gh release view "$tag" --repo "$repo" --json assets \ - --jq "[.assets[].name | select(test(\"$(printf '%s' "$glob" | sed 's/\*/.*/g')\"))] | length")" - if [ "$asset_count" -eq 0 ]; then + --jq "[.assets[].name | select(test(\"$(printf '%s' "$glob" | sed 's/\*/.*/g')\"))] | length" 2>/dev/null || true)" + # A transient gh/network failure (e.g. a broken pipe) leaves asset_count + # empty or non-numeric — don't let the integer test below abort with + # "integer expected". Only warn-and-skip on a confirmed zero; otherwise + # fall through to the download, which is the real gate (it errors cleanly + # if the asset is genuinely absent). + if [[ "$asset_count" =~ ^[0-9]+$ ]] && [ "$asset_count" -eq 0 ]; then warn "$name @ $tag: no asset matching '$glob' is attached to this release." warn " Pin a newer tag in versions.json once one is available." warn " (Runtime macOS .pkg first appears in the release immediately after PR #279.)" @@ -247,9 +264,21 @@ for c in "${COMPONENTS[@]}"; do install_component "$c" || FAIL=1 done -# --- --with-demos (always after binary installs) --- +# --- --with-demos: install each demo's prebuilt release asset --- +# Runs after the core components so demo installers that require the runtime +# (a hard prereq for some) find it already in place. No source build — a +# demo with no macOS asset on its pinned tag warn-and-skips (return 0). if [ "$WITH_DEMOS" -eq 1 ]; then + info "Installing demo release assets…" + for d in $DEMO_COMPONENTS; do + install_component "$d" || FAIL=1 + done +fi + +# --- --with-demo-sources: clone demo source trees (for building) --- + +if [ "$WITH_DEMO_SOURCES" -eq 1 ]; then info "Discovering DisplayXR demo repos…" DEMOS_DIR="$REPO_ROOT/demos" [ "$DRY_RUN" -eq 0 ] && mkdir -p "$DEMOS_DIR"