Add renderer and package readiness validation gates
This commit is contained in:
@@ -99,6 +99,89 @@ function New-PackageReadiness {
|
||||
}
|
||||
}
|
||||
|
||||
function Resolve-PackageStatus {
|
||||
param(
|
||||
[bool]$RootCMakePackageTargetAvailable,
|
||||
[bool]$GateBlocked,
|
||||
[object[]]$Prerequisites
|
||||
)
|
||||
|
||||
if ($GateBlocked) {
|
||||
return "blocked"
|
||||
}
|
||||
|
||||
foreach ($prerequisite in $Prerequisites) {
|
||||
if ($prerequisite.name -eq "root-cmake-package-target") {
|
||||
continue
|
||||
}
|
||||
if (-not $prerequisite.available) {
|
||||
return "blocked"
|
||||
}
|
||||
}
|
||||
|
||||
if ($RootCMakePackageTargetAvailable) {
|
||||
return "validated"
|
||||
}
|
||||
|
||||
return "compile-only"
|
||||
}
|
||||
|
||||
function Get-AndroidNativeCheckInfo {
|
||||
param(
|
||||
[string]$Kind,
|
||||
[bool]$AndroidNativeChecks,
|
||||
[object]$AndroidNativeValidation
|
||||
)
|
||||
|
||||
$command = switch ($Kind) {
|
||||
"android-standard-apk" { "powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages standard" }
|
||||
"android-quest-apk" { "powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages quest -ConfigureOnly" }
|
||||
"android-focus-apk" { "powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages focus -ConfigureOnly" }
|
||||
default { "" }
|
||||
}
|
||||
|
||||
if (-not $AndroidNativeChecks) {
|
||||
return @{ Available = $true; Detail = "$command (not run)" }
|
||||
}
|
||||
|
||||
if ($command.Length -eq 0) {
|
||||
return @{ Available = $false; Detail = "No Android native check plan for kind '$Kind'" }
|
||||
}
|
||||
|
||||
$packages = switch ($Kind) {
|
||||
"android-standard-apk" { @("standard") }
|
||||
"android-quest-apk" { @("quest") }
|
||||
"android-focus-apk" { @("focus") }
|
||||
default { @() }
|
||||
}
|
||||
|
||||
$result = $null
|
||||
foreach ($entry in $AndroidNativeValidation.results) {
|
||||
$hasAll = $true
|
||||
foreach ($pkg in $packages) {
|
||||
if (-not ($entry.packages -contains $pkg)) {
|
||||
$hasAll = $false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasAll) {
|
||||
$result = $entry
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $result) {
|
||||
return @{ Available = $false; Detail = "$command (not executed)" }
|
||||
}
|
||||
|
||||
if ($result.exitCode -ne 0) {
|
||||
return @{ Available = $false; Detail = "$command (exit $($result.exitCode))" }
|
||||
}
|
||||
|
||||
return @{ Available = $true; Detail = $command }
|
||||
}
|
||||
|
||||
function Get-AndroidNativeCheckPlan {
|
||||
param([string[]]$Kinds)
|
||||
|
||||
@@ -188,18 +271,20 @@ function Get-PackageReadiness {
|
||||
$wapproj = Join-Path $root "PanoPainterPackage/PanoPainterPackage.wapproj"
|
||||
$manifest = Join-Path $root "PanoPainterPackage/Package.appxmanifest"
|
||||
$appPackages = Join-Path $root "PanoPainterPackage/AppPackages"
|
||||
$prerequisites = @(
|
||||
(New-Prerequisite -Name "legacy-wapproj" -Available (Test-Path -LiteralPath $wapproj -PathType Leaf) -Detail $wapproj),
|
||||
(New-Prerequisite -Name "appx-manifest" -Available (Test-Path -LiteralPath $manifest -PathType Leaf) -Detail $manifest),
|
||||
(New-Prerequisite -Name "makeappx" -Available (Test-CommandAvailable "makeappx") -Detail "Windows SDK packaging tool"),
|
||||
(New-Prerequisite -Name "signtool" -Available (Test-CommandAvailable "signtool") -Detail "Windows SDK signing tool"),
|
||||
(New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
|
||||
)
|
||||
$status = Resolve-PackageStatus -RootCMakePackageTargetAvailable $false -GateBlocked $true -Prerequisites $prerequisites
|
||||
$readiness += New-PackageReadiness `
|
||||
-Kind $kind `
|
||||
-Status "blocked" `
|
||||
-Status $status `
|
||||
-Reason "legacy-wapproj-present-but-root-cmake-package-target-missing" `
|
||||
-ValidationCommand "msbuild PanoPainterPackage/PanoPainterPackage.wapproj /p:Configuration=$Configuration /p:Platform=x64" `
|
||||
-Prerequisites @(
|
||||
(New-Prerequisite -Name "legacy-wapproj" -Available (Test-Path -LiteralPath $wapproj -PathType Leaf) -Detail $wapproj),
|
||||
(New-Prerequisite -Name "appx-manifest" -Available (Test-Path -LiteralPath $manifest -PathType Leaf) -Detail $manifest),
|
||||
(New-Prerequisite -Name "makeappx" -Available (Test-CommandAvailable "makeappx") -Detail "Windows SDK packaging tool"),
|
||||
(New-Prerequisite -Name "signtool" -Available (Test-CommandAvailable "signtool") -Detail "Windows SDK signing tool"),
|
||||
(New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
|
||||
) `
|
||||
-Prerequisites $prerequisites `
|
||||
-Artifacts @(
|
||||
(New-ArtifactCheck -Name "app-packages" -Path $appPackages -PathType "Container")
|
||||
)
|
||||
@@ -208,19 +293,22 @@ function Get-PackageReadiness {
|
||||
$gradle = Join-Path $root "android/android/build.gradle"
|
||||
$manifest = Join-Path $root "android/android/src/main/AndroidManifest.xml"
|
||||
$apkDir = Join-Path $root "android/android/build/outputs/apk"
|
||||
$androidNativeCheck = Get-AndroidNativeCheckInfo -Kind $kind -AndroidNativeChecks $AndroidNativeChecks -AndroidNativeValidation $androidNativeValidation
|
||||
$prerequisites = @(
|
||||
(New-Prerequisite -Name "gradle-build" -Available (Test-Path -LiteralPath $gradle -PathType Leaf) -Detail $gradle),
|
||||
(New-Prerequisite -Name "android-manifest" -Available (Test-Path -LiteralPath $manifest -PathType Leaf) -Detail $manifest),
|
||||
(New-Prerequisite -Name "gradle" -Available (Test-CommandAvailable "gradle") -Detail "Android package builder"),
|
||||
(New-Prerequisite -Name "retained-native-cmake-check" -Available $androidNativeCheck.Available -Detail $androidNativeCheck.Detail),
|
||||
(New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "android-arm64/android-x64"),
|
||||
(New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
|
||||
)
|
||||
$status = Resolve-PackageStatus -RootCMakePackageTargetAvailable $false -GateBlocked $false -Prerequisites $prerequisites
|
||||
$readiness += New-PackageReadiness `
|
||||
-Kind $kind `
|
||||
-Status "blocked" `
|
||||
-Status $status `
|
||||
-Reason "legacy-gradle-package-not-consuming-root-cmake-targets" `
|
||||
-ValidationCommand "gradle -p android/android assembleDebug" `
|
||||
-Prerequisites @(
|
||||
(New-Prerequisite -Name "gradle-build" -Available (Test-Path -LiteralPath $gradle -PathType Leaf) -Detail $gradle),
|
||||
(New-Prerequisite -Name "android-manifest" -Available (Test-Path -LiteralPath $manifest -PathType Leaf) -Detail $manifest),
|
||||
(New-Prerequisite -Name "gradle" -Available (Test-CommandAvailable "gradle") -Detail "Android package builder"),
|
||||
(New-Prerequisite -Name "retained-native-cmake-check" -Available $true -Detail "powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages standard"),
|
||||
(New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "android-arm64/android-x64"),
|
||||
(New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
|
||||
) `
|
||||
-Prerequisites $prerequisites `
|
||||
-Artifacts @(
|
||||
(New-ArtifactCheck -Name "apk-output" -Path $apkDir -PathType "Container")
|
||||
)
|
||||
@@ -229,19 +317,22 @@ function Get-PackageReadiness {
|
||||
$gradle = Join-Path $root "android/quest/build.gradle"
|
||||
$manifest = Join-Path $root "android/quest/src/main/AndroidManifest.xml"
|
||||
$apkDir = Join-Path $root "android/quest/build/outputs/apk"
|
||||
$androidNativeCheck = Get-AndroidNativeCheckInfo -Kind $kind -AndroidNativeChecks $AndroidNativeChecks -AndroidNativeValidation $androidNativeValidation
|
||||
$prerequisites = @(
|
||||
(New-Prerequisite -Name "gradle-build" -Available (Test-Path -LiteralPath $gradle -PathType Leaf) -Detail $gradle),
|
||||
(New-Prerequisite -Name "android-manifest" -Available (Test-Path -LiteralPath $manifest -PathType Leaf) -Detail $manifest),
|
||||
(New-Prerequisite -Name "gradle" -Available (Test-CommandAvailable "gradle") -Detail "Android package builder"),
|
||||
(New-Prerequisite -Name "retained-native-cmake-check" -Available $androidNativeCheck.Available -Detail $androidNativeCheck.Detail),
|
||||
(New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "android-quest-arm64"),
|
||||
(New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
|
||||
)
|
||||
$status = Resolve-PackageStatus -RootCMakePackageTargetAvailable $false -GateBlocked $false -Prerequisites $prerequisites
|
||||
$readiness += New-PackageReadiness `
|
||||
-Kind $kind `
|
||||
-Status "blocked" `
|
||||
-Status $status `
|
||||
-Reason "legacy-gradle-package-not-consuming-root-cmake-targets" `
|
||||
-ValidationCommand "gradle -p android/quest assembleDebug" `
|
||||
-Prerequisites @(
|
||||
(New-Prerequisite -Name "gradle-build" -Available (Test-Path -LiteralPath $gradle -PathType Leaf) -Detail $gradle),
|
||||
(New-Prerequisite -Name "android-manifest" -Available (Test-Path -LiteralPath $manifest -PathType Leaf) -Detail $manifest),
|
||||
(New-Prerequisite -Name "gradle" -Available (Test-CommandAvailable "gradle") -Detail "Android package builder"),
|
||||
(New-Prerequisite -Name "retained-native-cmake-check" -Available $true -Detail "powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages quest -ConfigureOnly"),
|
||||
(New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "android-quest-arm64"),
|
||||
(New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
|
||||
) `
|
||||
-Prerequisites $prerequisites `
|
||||
-Artifacts @(
|
||||
(New-ArtifactCheck -Name "apk-output" -Path $apkDir -PathType "Container")
|
||||
)
|
||||
@@ -250,19 +341,22 @@ function Get-PackageReadiness {
|
||||
$gradle = Join-Path $root "android/focus/build.gradle"
|
||||
$manifest = Join-Path $root "android/focus/src/main/AndroidManifest.xml"
|
||||
$apkDir = Join-Path $root "android/focus/build/outputs/apk"
|
||||
$androidNativeCheck = Get-AndroidNativeCheckInfo -Kind $kind -AndroidNativeChecks $AndroidNativeChecks -AndroidNativeValidation $androidNativeValidation
|
||||
$prerequisites = @(
|
||||
(New-Prerequisite -Name "gradle-build" -Available (Test-Path -LiteralPath $gradle -PathType Leaf) -Detail $gradle),
|
||||
(New-Prerequisite -Name "android-manifest" -Available (Test-Path -LiteralPath $manifest -PathType Leaf) -Detail $manifest),
|
||||
(New-Prerequisite -Name "gradle" -Available (Test-CommandAvailable "gradle") -Detail "Android package builder"),
|
||||
(New-Prerequisite -Name "retained-native-cmake-check" -Available $androidNativeCheck.Available -Detail $androidNativeCheck.Detail),
|
||||
(New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "android-focus-arm64"),
|
||||
(New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
|
||||
)
|
||||
$status = Resolve-PackageStatus -RootCMakePackageTargetAvailable $false -GateBlocked $false -Prerequisites $prerequisites
|
||||
$readiness += New-PackageReadiness `
|
||||
-Kind $kind `
|
||||
-Status "blocked" `
|
||||
-Status $status `
|
||||
-Reason "legacy-gradle-package-not-consuming-root-cmake-targets" `
|
||||
-ValidationCommand "gradle -p android/focus assembleDebug" `
|
||||
-Prerequisites @(
|
||||
(New-Prerequisite -Name "gradle-build" -Available (Test-Path -LiteralPath $gradle -PathType Leaf) -Detail $gradle),
|
||||
(New-Prerequisite -Name "android-manifest" -Available (Test-Path -LiteralPath $manifest -PathType Leaf) -Detail $manifest),
|
||||
(New-Prerequisite -Name "gradle" -Available (Test-CommandAvailable "gradle") -Detail "Android package builder"),
|
||||
(New-Prerequisite -Name "retained-native-cmake-check" -Available $true -Detail "powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages focus -ConfigureOnly"),
|
||||
(New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "android-focus-arm64"),
|
||||
(New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
|
||||
) `
|
||||
-Prerequisites $prerequisites `
|
||||
-Artifacts @(
|
||||
(New-ArtifactCheck -Name "apk-output" -Path $apkDir -PathType "Container")
|
||||
)
|
||||
@@ -270,17 +364,19 @@ function Get-PackageReadiness {
|
||||
"apple-bundle" {
|
||||
$xcodeProject = Join-Path $root "PanoPainter.xcodeproj/project.pbxproj"
|
||||
$bundleDir = Join-Path $root "out/package/apple"
|
||||
$prerequisites = @(
|
||||
(New-Prerequisite -Name "legacy-xcode-project" -Available (Test-Path -LiteralPath $xcodeProject -PathType Leaf) -Detail $xcodeProject),
|
||||
(New-Prerequisite -Name "xcodebuild" -Available (Test-CommandAvailable "xcodebuild") -Detail "Apple package builder"),
|
||||
(New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "macos/ios-device/ios-simulator"),
|
||||
(New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
|
||||
)
|
||||
$status = Resolve-PackageStatus -RootCMakePackageTargetAvailable $false -GateBlocked $true -Prerequisites $prerequisites
|
||||
$readiness += New-PackageReadiness `
|
||||
-Kind $kind `
|
||||
-Status "blocked" `
|
||||
-Status $status `
|
||||
-Reason "legacy-xcode-project-and-host-toolchain-not-aligned-with-root-cmake-package-target" `
|
||||
-ValidationCommand "xcodebuild -project PanoPainter.xcodeproj -configuration $Configuration" `
|
||||
-Prerequisites @(
|
||||
(New-Prerequisite -Name "legacy-xcode-project" -Available (Test-Path -LiteralPath $xcodeProject -PathType Leaf) -Detail $xcodeProject),
|
||||
(New-Prerequisite -Name "xcodebuild" -Available (Test-CommandAvailable "xcodebuild") -Detail "Apple package builder"),
|
||||
(New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "macos/ios-device/ios-simulator"),
|
||||
(New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
|
||||
) `
|
||||
-Prerequisites $prerequisites `
|
||||
-Artifacts @(
|
||||
(New-ArtifactCheck -Name "apple-package-output" -Path $bundleDir -PathType "Container")
|
||||
)
|
||||
@@ -288,18 +384,20 @@ function Get-PackageReadiness {
|
||||
"linux-app" {
|
||||
$linuxCmake = Join-Path $root "linux/CMakeLists.txt"
|
||||
$linuxBinary = Join-Path $root "out/package/linux/panopainter"
|
||||
$prerequisites = @(
|
||||
(New-Prerequisite -Name "retained-linux-cmake" -Available (Test-Path -LiteralPath $linuxCmake -PathType Leaf) -Detail $linuxCmake),
|
||||
(New-Prerequisite -Name "cmake" -Available (Test-CommandAvailable "cmake") -Detail "Linux retained app CMake configure/build tool"),
|
||||
(New-Prerequisite -Name "retained-platform-cmake-baseline" -Available $true -Detail "python scripts/dev/check_retained_platform_cmake.py"),
|
||||
(New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "linux-clang"),
|
||||
(New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
|
||||
)
|
||||
$status = Resolve-PackageStatus -RootCMakePackageTargetAvailable $false -GateBlocked $false -Prerequisites $prerequisites
|
||||
$readiness += New-PackageReadiness `
|
||||
-Kind $kind `
|
||||
-Status "blocked" `
|
||||
-Status $status `
|
||||
-Reason "retained-linux-cmake-not-consuming-root-cmake-targets" `
|
||||
-ValidationCommand "cmake -S linux -B out/package/linux-retained && cmake --build out/package/linux-retained --target panopainter" `
|
||||
-Prerequisites @(
|
||||
(New-Prerequisite -Name "retained-linux-cmake" -Available (Test-Path -LiteralPath $linuxCmake -PathType Leaf) -Detail $linuxCmake),
|
||||
(New-Prerequisite -Name "cmake" -Available (Test-CommandAvailable "cmake") -Detail "Linux retained app CMake configure/build tool"),
|
||||
(New-Prerequisite -Name "retained-platform-cmake-baseline" -Available $true -Detail "python scripts/dev/check_retained_platform_cmake.py"),
|
||||
(New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "linux-clang"),
|
||||
(New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
|
||||
) `
|
||||
-Prerequisites $prerequisites `
|
||||
-Artifacts @(
|
||||
(New-ArtifactCheck -Name "linux-app-output" -Path $linuxBinary -PathType "Leaf")
|
||||
)
|
||||
@@ -307,19 +405,21 @@ function Get-PackageReadiness {
|
||||
"webgl" {
|
||||
$webglCmake = Join-Path $root "webgl/CMakeLists.txt"
|
||||
$webDir = Join-Path $root "out/package/webgl"
|
||||
$prerequisites = @(
|
||||
(New-Prerequisite -Name "retained-webgl-cmake" -Available (Test-Path -LiteralPath $webglCmake -PathType Leaf) -Detail $webglCmake),
|
||||
(New-Prerequisite -Name "emcc" -Available (Test-CommandAvailable "emcc") -Detail "Emscripten compiler"),
|
||||
(New-Prerequisite -Name "emcmake" -Available (Test-CommandAvailable "emcmake") -Detail "Emscripten CMake wrapper"),
|
||||
(New-Prerequisite -Name "retained-platform-cmake-baseline" -Available $true -Detail "python scripts/dev/check_retained_platform_cmake.py"),
|
||||
(New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "emscripten"),
|
||||
(New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
|
||||
)
|
||||
$status = Resolve-PackageStatus -RootCMakePackageTargetAvailable $false -GateBlocked $false -Prerequisites $prerequisites
|
||||
$readiness += New-PackageReadiness `
|
||||
-Kind $kind `
|
||||
-Status "blocked" `
|
||||
-Status $status `
|
||||
-Reason "retained-webgl-cmake-not-consuming-root-cmake-targets" `
|
||||
-ValidationCommand "emcmake cmake -S webgl -B out/package/webgl-retained && cmake --build out/package/webgl-retained --target panopainter" `
|
||||
-Prerequisites @(
|
||||
(New-Prerequisite -Name "retained-webgl-cmake" -Available (Test-Path -LiteralPath $webglCmake -PathType Leaf) -Detail $webglCmake),
|
||||
(New-Prerequisite -Name "emcc" -Available (Test-CommandAvailable "emcc") -Detail "Emscripten compiler"),
|
||||
(New-Prerequisite -Name "emcmake" -Available (Test-CommandAvailable "emcmake") -Detail "Emscripten CMake wrapper"),
|
||||
(New-Prerequisite -Name "retained-platform-cmake-baseline" -Available $true -Detail "python scripts/dev/check_retained_platform_cmake.py"),
|
||||
(New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "emscripten"),
|
||||
(New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
|
||||
) `
|
||||
-Prerequisites $prerequisites `
|
||||
-Artifacts @(
|
||||
(New-ArtifactCheck -Name "webgl-output" -Path $webDir -PathType "Container")
|
||||
)
|
||||
|
||||
@@ -1,33 +1,100 @@
|
||||
#!/usr/bin/env sh
|
||||
set -u
|
||||
|
||||
preset="${1:-linux-clang}"
|
||||
configuration="${2:-Debug}"
|
||||
target="${3:-PanoPainter}"
|
||||
artifact="${4:-out/build/$preset/$target}"
|
||||
preset="linux-clang"
|
||||
configuration="Debug"
|
||||
target="PanoPainter"
|
||||
cmake_command="cmake"
|
||||
artifact="out/build/$preset/$target"
|
||||
readiness_only=0
|
||||
if [ "${1:-}" = "--readiness-only" ]; then
|
||||
readiness_only=1
|
||||
preset="${2:-linux-clang}"
|
||||
configuration="${3:-Debug}"
|
||||
target="${4:-PanoPainter}"
|
||||
artifact="${5:-out/build/$preset/$target}"
|
||||
android_native_checks=0
|
||||
package_kinds="windows-appx,android-standard-apk,android-quest-apk,android-focus-apk,apple-bundle,linux-app,webgl"
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--readiness-only)
|
||||
readiness_only=1
|
||||
shift
|
||||
;;
|
||||
--android-native-checks)
|
||||
android_native_checks=1
|
||||
shift
|
||||
;;
|
||||
--package-kinds=*)
|
||||
package_kinds="${1#*=}"
|
||||
shift
|
||||
;;
|
||||
--package-kinds)
|
||||
shift
|
||||
if [ "$#" -gt 0 ]; then
|
||||
package_kinds="$1"
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-*)
|
||||
echo "Unknown option: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$#" -ge 1 ]; then
|
||||
preset="${1:-$preset}"
|
||||
configuration="${2:-$configuration}"
|
||||
target="${3:-$target}"
|
||||
artifact="${4:-out/build/$preset/$target}"
|
||||
fi
|
||||
|
||||
start="$(date +%s)"
|
||||
root="$(pwd)"
|
||||
package_kinds="$(printf "%s" "$package_kinds" | tr -d " ")"
|
||||
|
||||
json_escape() {
|
||||
printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\r/\\r/g; s/\n/\\n/g'
|
||||
}
|
||||
|
||||
json_string() {
|
||||
printf '"%s"' "$(printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g')"
|
||||
printf '"%s"' "$(json_escape "$1")"
|
||||
}
|
||||
|
||||
json_bool() {
|
||||
if [ "$1" = "1" ]; then
|
||||
if [ "$1" -eq 1 ]; then
|
||||
printf true
|
||||
else
|
||||
printf false
|
||||
fi
|
||||
}
|
||||
|
||||
json_array_from_csv() {
|
||||
local csv="$1"
|
||||
local first=1
|
||||
local value
|
||||
local items=""
|
||||
|
||||
IFS=','
|
||||
for value in $csv; do
|
||||
if [ -z "$value" ]; then
|
||||
continue
|
||||
fi
|
||||
if [ "$first" -eq 1 ]; then
|
||||
first=0
|
||||
else
|
||||
items="${items},"
|
||||
fi
|
||||
items="${items}$(json_string "$value")"
|
||||
done
|
||||
unset IFS
|
||||
|
||||
printf "[%s]" "$items"
|
||||
}
|
||||
|
||||
command_available() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
@@ -40,93 +107,550 @@ dir_available() {
|
||||
[ -d "$1" ]
|
||||
}
|
||||
|
||||
package_readiness_json() {
|
||||
resolve_status() {
|
||||
local root_target="$1"
|
||||
local gate_blocked="$2"
|
||||
shift 2
|
||||
|
||||
if [ "$gate_blocked" -ne 0 ]; then
|
||||
printf "blocked"
|
||||
return
|
||||
fi
|
||||
|
||||
for prereq in "$@"; do
|
||||
if [ "$prereq" -ne 1 ]; then
|
||||
printf "blocked"
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$root_target" -ne 0 ]; then
|
||||
printf "validated"
|
||||
else
|
||||
printf "compile-only"
|
||||
fi
|
||||
}
|
||||
|
||||
append_json_item() {
|
||||
if [ -z "$package_readiness" ]; then
|
||||
package_readiness="$1"
|
||||
else
|
||||
package_readiness="${package_readiness},$1"
|
||||
fi
|
||||
}
|
||||
|
||||
append_result_item() {
|
||||
if [ -z "$android_native_results" ]; then
|
||||
android_native_results="$1"
|
||||
else
|
||||
android_native_results="${android_native_results},$1"
|
||||
fi
|
||||
}
|
||||
|
||||
prerequisite_entry() {
|
||||
local name="$1"
|
||||
local available="$2"
|
||||
local detail="$3"
|
||||
|
||||
printf '{'
|
||||
printf '"name":%s,' "$(json_string "$name")"
|
||||
printf '"available":%s,' "$(json_bool "$available")"
|
||||
printf '"detail":%s' "$(json_string "$detail")"
|
||||
printf '}'
|
||||
}
|
||||
|
||||
artifact_entry() {
|
||||
local name="$1"
|
||||
local path="$2"
|
||||
local path_type="$3"
|
||||
local exists=0
|
||||
|
||||
printf '{'
|
||||
printf '"name":%s,' "$(json_string "$name")"
|
||||
printf '"path":%s,' "$(json_string "$path")"
|
||||
printf '"pathType":%s,' "$(json_string "$path_type")"
|
||||
if [ "$path_type" = "Leaf" ]; then
|
||||
[ -f "$path" ]
|
||||
exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
elif [ "$path_type" = "Container" ]; then
|
||||
[ -d "$path" ]
|
||||
exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
else
|
||||
[ -e "$path" ]
|
||||
exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
fi
|
||||
printf '"exists":%s' "$(json_bool "$exists")"
|
||||
printf '}'
|
||||
}
|
||||
|
||||
check_entry() {
|
||||
local name="$1"
|
||||
local path="$2"
|
||||
local exists="$3"
|
||||
|
||||
printf '{'
|
||||
printf '"name":%s,' "$(json_string "$name")"
|
||||
printf '"path":%s,' "$(json_string "$path")"
|
||||
printf '"exists":%s' "$(json_bool "$exists")"
|
||||
printf '}'
|
||||
}
|
||||
|
||||
is_kind_requested() {
|
||||
case ",${package_kinds}," in
|
||||
*,"$1",*)
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
run_android_native_check() {
|
||||
local packages="$1"
|
||||
local configure_only="$2"
|
||||
local command="powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages $packages"
|
||||
if [ "$configure_only" -ne 0 ]; then
|
||||
command="${command} -ConfigureOnly"
|
||||
fi
|
||||
|
||||
if ! command_available powershell; then
|
||||
android_native_last_exit_code=127
|
||||
printf '{"packages":%s,"configureOnly":%s,"exitCode":%s,"command":%s,"summary":null}' \
|
||||
"$(json_array_from_csv "$packages")" \
|
||||
"$(json_bool "$configure_only")" \
|
||||
"$android_native_last_exit_code" \
|
||||
"$(json_string "$command")"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$configure_only" -ne 0 ]; then
|
||||
output="$(powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages "$packages" -ConfigureOnly 2>&1)"
|
||||
else
|
||||
output="$(powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages "$packages" 2>&1)"
|
||||
fi
|
||||
android_native_last_exit_code=$?
|
||||
|
||||
summary="$(printf '%s\n' "$output" | awk 'BEGIN{line="";} /^\{/{line=$0} END{if (line != "") print line}')"
|
||||
if [ -z "$summary" ]; then
|
||||
summary="null"
|
||||
fi
|
||||
|
||||
printf '{"packages":%s,"configureOnly":%s,"exitCode":%s,"command":%s,"summary":%s}' \
|
||||
"$(json_array_from_csv "$packages")" \
|
||||
"$(json_bool "$configure_only")" \
|
||||
"$android_native_last_exit_code" \
|
||||
"$(json_string "$command")" \
|
||||
"$summary"
|
||||
}
|
||||
|
||||
extract_exit_code() {
|
||||
printf '%s' "$1" | awk -F '"exitCode":' 'NF == 2 { gsub(/[^0-9].*/, "", $2); print $2 }'
|
||||
}
|
||||
|
||||
build_android_native_validation() {
|
||||
local standard_command="powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages standard"
|
||||
local qf_packages=""
|
||||
local qf_command="powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages $qf_packages -ConfigureOnly"
|
||||
|
||||
local request_standard=0
|
||||
local request_qf=0
|
||||
|
||||
if is_kind_requested "android-standard-apk"; then
|
||||
request_standard=1
|
||||
fi
|
||||
if is_kind_requested "android-quest-apk" || is_kind_requested "android-focus-apk"; then
|
||||
request_qf=1
|
||||
if is_kind_requested "android-quest-apk"; then
|
||||
qf_packages="quest"
|
||||
fi
|
||||
if is_kind_requested "android-focus-apk"; then
|
||||
if [ -n "$qf_packages" ]; then
|
||||
qf_packages="${qf_packages},focus"
|
||||
else
|
||||
qf_packages="focus"
|
||||
fi
|
||||
fi
|
||||
qf_command="powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages $qf_packages -ConfigureOnly"
|
||||
fi
|
||||
|
||||
android_native_standard_available=1
|
||||
android_native_quest_available=1
|
||||
android_native_focus_available=1
|
||||
android_native_standard_detail="${standard_command} (not run)"
|
||||
android_native_quest_detail="${qf_command} (not run)"
|
||||
android_native_focus_detail="${qf_command} (not run)"
|
||||
|
||||
local requested="false"
|
||||
local exit_code=0
|
||||
android_native_results=""
|
||||
android_native_last_exit_code=0
|
||||
|
||||
if [ "$android_native_checks" -eq 0 ]; then
|
||||
android_native_validation='{"requested":false,"exitCode":0,"results":[]}'
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$request_standard" -eq 1 ]; then
|
||||
requested="true"
|
||||
standard_result="$(run_android_native_check "standard" 0)"
|
||||
append_result_item "$standard_result"
|
||||
standard_exit_code="$(extract_exit_code "$standard_result")"
|
||||
if [ -z "$standard_exit_code" ]; then
|
||||
standard_exit_code=0
|
||||
fi
|
||||
if [ "$standard_exit_code" -ne 0 ] && [ "$exit_code" -eq 0 ]; then
|
||||
exit_code="$standard_exit_code"
|
||||
fi
|
||||
|
||||
if [ "$standard_exit_code" -eq 0 ]; then
|
||||
android_native_standard_available=1
|
||||
android_native_standard_detail="$standard_command"
|
||||
else
|
||||
android_native_standard_available=0
|
||||
android_native_standard_detail="${standard_command} (exit $standard_exit_code)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$request_qf" -eq 1 ] && [ -n "$qf_packages" ]; then
|
||||
requested="true"
|
||||
qf_result="$(run_android_native_check "$qf_packages" 1)"
|
||||
append_result_item "$qf_result"
|
||||
qf_exit_code="$(extract_exit_code "$qf_result")"
|
||||
if [ -z "$qf_exit_code" ]; then
|
||||
qf_exit_code=0
|
||||
fi
|
||||
if [ "$qf_exit_code" -ne 0 ] && [ "$exit_code" -eq 0 ]; then
|
||||
exit_code="$qf_exit_code"
|
||||
fi
|
||||
|
||||
if [ "$qf_exit_code" -eq 0 ]; then
|
||||
if is_kind_requested "android-quest-apk"; then
|
||||
android_native_quest_available=1
|
||||
android_native_quest_detail="$qf_command"
|
||||
else
|
||||
android_native_quest_detail="$qf_command (not executed)"
|
||||
fi
|
||||
|
||||
if is_kind_requested "android-focus-apk"; then
|
||||
android_native_focus_available=1
|
||||
android_native_focus_detail="$qf_command"
|
||||
else
|
||||
android_native_focus_detail="$qf_command (not executed)"
|
||||
fi
|
||||
else
|
||||
if is_kind_requested "android-quest-apk"; then
|
||||
android_native_quest_available=0
|
||||
android_native_quest_detail="${qf_command} (exit $qf_exit_code)"
|
||||
else
|
||||
android_native_quest_detail="$qf_command (not executed)"
|
||||
fi
|
||||
|
||||
if is_kind_requested "android-focus-apk"; then
|
||||
android_native_focus_available=0
|
||||
android_native_focus_detail="${qf_command} (exit $qf_exit_code)"
|
||||
else
|
||||
android_native_focus_detail="$qf_command (not executed)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
android_native_validation="{\"requested\":$requested,\"exitCode\":$exit_code,\"results\":[${android_native_results}]}"
|
||||
}
|
||||
|
||||
build_package_readiness() {
|
||||
package_readiness=""
|
||||
|
||||
windows_wapproj="$root/PanoPainterPackage/PanoPainterPackage.wapproj"
|
||||
windows_manifest="$root/PanoPainterPackage/Package.appxmanifest"
|
||||
windows_output="$root/PanoPainterPackage/AppPackages"
|
||||
|
||||
android_standard_gradle="$root/android/android/build.gradle"
|
||||
android_standard_manifest="$root/android/android/src/main/AndroidManifest.xml"
|
||||
android_standard_output="$root/android/android/build/outputs/apk"
|
||||
|
||||
android_quest_gradle="$root/android/quest/build.gradle"
|
||||
android_quest_manifest="$root/android/quest/src/main/AndroidManifest.xml"
|
||||
android_quest_output="$root/android/quest/build/outputs/apk"
|
||||
|
||||
android_focus_gradle="$root/android/focus/build.gradle"
|
||||
android_focus_manifest="$root/android/focus/src/main/AndroidManifest.xml"
|
||||
android_focus_output="$root/android/focus/build/outputs/apk"
|
||||
|
||||
apple_project="$root/PanoPainter.xcodeproj/project.pbxproj"
|
||||
apple_output="$root/out/package/apple"
|
||||
|
||||
linux_cmake="$root/linux/CMakeLists.txt"
|
||||
linux_output="$root/out/package/linux/panopainter"
|
||||
|
||||
webgl_cmake="$root/webgl/CMakeLists.txt"
|
||||
webgl_output="$root/out/package/webgl"
|
||||
|
||||
file_available "$windows_wapproj"; windows_wapproj_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
file_available "$windows_manifest"; windows_manifest_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
command_available makeappx; makeappx_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
command_available signtool; signtool_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
dir_available "$windows_output"; windows_output_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
file_available "$windows_wapproj"; windows_wapproj_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
file_available "$windows_manifest"; windows_manifest_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
command_available makeappx; makeappx_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
command_available signtool; signtool_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
dir_available "$windows_output"; windows_output_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
|
||||
file_available "$android_standard_gradle"; android_standard_gradle_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
file_available "$android_standard_manifest"; android_standard_manifest_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
file_available "$android_quest_gradle"; android_quest_gradle_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
file_available "$android_quest_manifest"; android_quest_manifest_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
file_available "$android_focus_gradle"; android_focus_gradle_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
file_available "$android_focus_manifest"; android_focus_manifest_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
command_available gradle; gradle_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
dir_available "$android_standard_output"; android_standard_output_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
dir_available "$android_quest_output"; android_quest_output_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
dir_available "$android_focus_output"; android_focus_output_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
file_available "$android_standard_gradle"; android_standard_gradle_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
file_available "$android_standard_manifest"; android_standard_manifest_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
file_available "$android_quest_gradle"; android_quest_gradle_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
file_available "$android_quest_manifest"; android_quest_manifest_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
file_available "$android_focus_gradle"; android_focus_gradle_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
file_available "$android_focus_manifest"; android_focus_manifest_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
command_available gradle; gradle_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
dir_available "$android_standard_output"; android_standard_output_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
dir_available "$android_quest_output"; android_quest_output_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
dir_available "$android_focus_output"; android_focus_output_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
|
||||
file_available "$apple_project"; apple_project_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
command_available xcodebuild; xcodebuild_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
dir_available "$apple_output"; apple_output_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
file_available "$apple_project"; apple_project_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
command_available xcodebuild; xcodebuild_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
dir_available "$apple_output"; apple_output_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
|
||||
file_available "$linux_cmake"; linux_cmake_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
command_available cmake; cmake_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
file_available "$linux_output"; linux_output_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
file_available "$linux_cmake"; linux_cmake_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
command_available cmake; cmake_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
file_available "$linux_output"; linux_output_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
|
||||
file_available "$webgl_cmake"; webgl_cmake_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
command_available emcc; emcc_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
command_available emcmake; emcmake_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
dir_available "$webgl_output"; webgl_output_exists="$([ "$?" -eq 0 ] && printf 1 || printf 0)"
|
||||
file_available "$webgl_cmake"; webgl_cmake_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
command_available emcc; emcc_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
command_available emcmake; emcmake_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
dir_available "$webgl_output"; webgl_output_exists=$([ $? -eq 0 ] && printf "1" || printf "0")
|
||||
|
||||
printf '['
|
||||
printf '{"kind":"windows-appx","status":"blocked","reason":"legacy-wapproj-present-but-root-cmake-package-target-missing","debt":"DEBT-0011","validationCommand":"msbuild PanoPainterPackage/PanoPainterPackage.wapproj /p:Configuration=%s /p:Platform=x64","prerequisites":[{"name":"legacy-wapproj","available":%s,"detail":%s},{"name":"appx-manifest","available":%s,"detail":%s},{"name":"makeappx","available":%s,"detail":"Windows SDK packaging tool"},{"name":"signtool","available":%s,"detail":"Windows SDK signing tool"},{"name":"root-cmake-package-target","available":false,"detail":"Not migrated yet"}],"artifacts":[{"name":"app-packages","path":%s,"pathType":"Container","exists":%s}]}' "$configuration" "$(json_bool "$windows_wapproj_exists")" "$(json_string "$windows_wapproj")" "$(json_bool "$windows_manifest_exists")" "$(json_string "$windows_manifest")" "$(json_bool "$makeappx_exists")" "$(json_bool "$signtool_exists")" "$(json_string "$windows_output")" "$(json_bool "$windows_output_exists")"
|
||||
printf ',{"kind":"android-standard-apk","status":"blocked","reason":"legacy-gradle-package-not-consuming-root-cmake-targets","debt":"DEBT-0011","validationCommand":"gradle -p android/android assembleDebug","prerequisites":[{"name":"gradle-build","available":%s,"detail":%s},{"name":"android-manifest","available":%s,"detail":%s},{"name":"gradle","available":%s,"detail":"Android package builder"},{"name":"retained-native-cmake-check","available":true,"detail":"powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages standard"},{"name":"root-cmake-preset","available":true,"detail":"android-arm64/android-x64"},{"name":"root-cmake-package-target","available":false,"detail":"Not migrated yet"}],"artifacts":[{"name":"apk-output","path":%s,"pathType":"Container","exists":%s}]}' "$(json_bool "$android_standard_gradle_exists")" "$(json_string "$android_standard_gradle")" "$(json_bool "$android_standard_manifest_exists")" "$(json_string "$android_standard_manifest")" "$(json_bool "$gradle_exists")" "$(json_string "$android_standard_output")" "$(json_bool "$android_standard_output_exists")"
|
||||
printf ',{"kind":"android-quest-apk","status":"blocked","reason":"legacy-gradle-package-not-consuming-root-cmake-targets","debt":"DEBT-0011","validationCommand":"gradle -p android/quest assembleDebug","prerequisites":[{"name":"gradle-build","available":%s,"detail":%s},{"name":"android-manifest","available":%s,"detail":%s},{"name":"gradle","available":%s,"detail":"Android package builder"},{"name":"retained-native-cmake-check","available":true,"detail":"powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages quest -ConfigureOnly"},{"name":"root-cmake-preset","available":true,"detail":"android-quest-arm64"},{"name":"root-cmake-package-target","available":false,"detail":"Not migrated yet"}],"artifacts":[{"name":"apk-output","path":%s,"pathType":"Container","exists":%s}]}' "$(json_bool "$android_quest_gradle_exists")" "$(json_string "$android_quest_gradle")" "$(json_bool "$android_quest_manifest_exists")" "$(json_string "$android_quest_manifest")" "$(json_bool "$gradle_exists")" "$(json_string "$android_quest_output")" "$(json_bool "$android_quest_output_exists")"
|
||||
printf ',{"kind":"android-focus-apk","status":"blocked","reason":"legacy-gradle-package-not-consuming-root-cmake-targets","debt":"DEBT-0011","validationCommand":"gradle -p android/focus assembleDebug","prerequisites":[{"name":"gradle-build","available":%s,"detail":%s},{"name":"android-manifest","available":%s,"detail":%s},{"name":"gradle","available":%s,"detail":"Android package builder"},{"name":"retained-native-cmake-check","available":true,"detail":"powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages focus -ConfigureOnly"},{"name":"root-cmake-preset","available":true,"detail":"android-focus-arm64"},{"name":"root-cmake-package-target","available":false,"detail":"Not migrated yet"}],"artifacts":[{"name":"apk-output","path":%s,"pathType":"Container","exists":%s}]}' "$(json_bool "$android_focus_gradle_exists")" "$(json_string "$android_focus_gradle")" "$(json_bool "$android_focus_manifest_exists")" "$(json_string "$android_focus_manifest")" "$(json_bool "$gradle_exists")" "$(json_string "$android_focus_output")" "$(json_bool "$android_focus_output_exists")"
|
||||
printf ',{"kind":"apple-bundle","status":"blocked","reason":"legacy-xcode-project-and-host-toolchain-not-aligned-with-root-cmake-package-target","debt":"DEBT-0011","validationCommand":"xcodebuild -project PanoPainter.xcodeproj -configuration %s","prerequisites":[{"name":"legacy-xcode-project","available":%s,"detail":%s},{"name":"xcodebuild","available":%s,"detail":"Apple package builder"},{"name":"root-cmake-preset","available":true,"detail":"macos/ios-device/ios-simulator"},{"name":"root-cmake-package-target","available":false,"detail":"Not migrated yet"}],"artifacts":[{"name":"apple-package-output","path":%s,"pathType":"Container","exists":%s}]}' "$configuration" "$(json_bool "$apple_project_exists")" "$(json_string "$apple_project")" "$(json_bool "$xcodebuild_exists")" "$(json_string "$apple_output")" "$(json_bool "$apple_output_exists")"
|
||||
printf ',{"kind":"linux-app","status":"blocked","reason":"retained-linux-cmake-not-consuming-root-cmake-targets","debt":"DEBT-0011","validationCommand":"cmake -S linux -B out/package/linux-retained && cmake --build out/package/linux-retained --target panopainter","prerequisites":[{"name":"retained-linux-cmake","available":%s,"detail":%s},{"name":"cmake","available":%s,"detail":"Linux retained app CMake configure/build tool"},{"name":"retained-platform-cmake-baseline","available":true,"detail":"python scripts/dev/check_retained_platform_cmake.py"},{"name":"root-cmake-preset","available":true,"detail":"linux-clang"},{"name":"root-cmake-package-target","available":false,"detail":"Not migrated yet"}],"artifacts":[{"name":"linux-app-output","path":%s,"pathType":"Leaf","exists":%s}]}' "$(json_bool "$linux_cmake_exists")" "$(json_string "$linux_cmake")" "$(json_bool "$cmake_exists")" "$(json_string "$linux_output")" "$(json_bool "$linux_output_exists")"
|
||||
printf ',{"kind":"webgl","status":"blocked","reason":"retained-webgl-cmake-not-consuming-root-cmake-targets","debt":"DEBT-0011","validationCommand":"emcmake cmake -S webgl -B out/package/webgl-retained && cmake --build out/package/webgl-retained --target panopainter","prerequisites":[{"name":"retained-webgl-cmake","available":%s,"detail":%s},{"name":"emcc","available":%s,"detail":"Emscripten compiler"},{"name":"emcmake","available":%s,"detail":"Emscripten CMake wrapper"},{"name":"retained-platform-cmake-baseline","available":true,"detail":"python scripts/dev/check_retained_platform_cmake.py"},{"name":"root-cmake-preset","available":true,"detail":"emscripten"},{"name":"root-cmake-package-target","available":false,"detail":"Not migrated yet"}],"artifacts":[{"name":"webgl-output","path":%s,"pathType":"Container","exists":%s}]}' "$(json_bool "$webgl_cmake_exists")" "$(json_string "$webgl_cmake")" "$(json_bool "$emcc_exists")" "$(json_bool "$emcmake_exists")" "$(json_string "$webgl_output")" "$(json_bool "$webgl_output_exists")"
|
||||
printf ']'
|
||||
if is_kind_requested "windows-appx"; then
|
||||
windows_status="$(resolve_status 0 1 "$windows_wapproj_exists" "$windows_manifest_exists" "$makeappx_exists" "$signtool_exists")"
|
||||
windows_prerequisites=''
|
||||
windows_prerequisites="${windows_prerequisites}$(prerequisite_entry "legacy-wapproj" "$windows_wapproj_exists" "$windows_wapproj"),"
|
||||
windows_prerequisites="${windows_prerequisites}$(prerequisite_entry "appx-manifest" "$windows_manifest_exists" "$windows_manifest"),"
|
||||
windows_prerequisites="${windows_prerequisites}$(prerequisite_entry "makeappx" "$makeappx_exists" "Windows SDK packaging tool"),"
|
||||
windows_prerequisites="${windows_prerequisites}$(prerequisite_entry "signtool" "$signtool_exists" "Windows SDK signing tool"),"
|
||||
windows_prerequisites="${windows_prerequisites}$(prerequisite_entry "root-cmake-package-target" 0 "Not migrated yet")"
|
||||
windows_entry="{"
|
||||
windows_entry="${windows_entry}\"kind\":\"windows-appx\","
|
||||
windows_entry="${windows_entry}\"status\":\"$windows_status\","
|
||||
windows_entry="${windows_entry}\"reason\":\"legacy-wapproj-present-but-root-cmake-package-target-missing\","
|
||||
windows_entry="${windows_entry}\"debt\":\"DEBT-0011\","
|
||||
windows_entry="${windows_entry}\"validationCommand\":\"msbuild PanoPainterPackage/PanoPainterPackage.wapproj /p:Configuration=$configuration /p:Platform=x64\","
|
||||
windows_entry="${windows_entry}\"prerequisites\":[${windows_prerequisites}],"
|
||||
windows_entry="${windows_entry}\"artifacts\":["
|
||||
windows_entry="${windows_entry}$(artifact_entry "app-packages" "$windows_output" "Container")"
|
||||
windows_entry="${windows_entry}]}"
|
||||
append_json_item "$windows_entry"
|
||||
fi
|
||||
|
||||
if is_kind_requested "android-standard-apk"; then
|
||||
android_standard_status="$(resolve_status 0 0 "$android_standard_gradle_exists" "$android_standard_manifest_exists" "$gradle_exists" "$android_native_standard_available")"
|
||||
android_standard_prerequisites=''
|
||||
android_standard_prerequisites="${android_standard_prerequisites}$(prerequisite_entry "gradle-build" "$android_standard_gradle_exists" "$android_standard_gradle"),"
|
||||
android_standard_prerequisites="${android_standard_prerequisites}$(prerequisite_entry "android-manifest" "$android_standard_manifest_exists" "$android_standard_manifest"),"
|
||||
android_standard_prerequisites="${android_standard_prerequisites}$(prerequisite_entry "gradle" "$gradle_exists" "Android package builder"),"
|
||||
android_standard_prerequisites="${android_standard_prerequisites}$(prerequisite_entry "retained-native-cmake-check" "$android_native_standard_available" "$android_native_standard_detail"),"
|
||||
android_standard_prerequisites="${android_standard_prerequisites}$(prerequisite_entry "root-cmake-preset" 1 "android-arm64/android-x64"),"
|
||||
android_standard_prerequisites="${android_standard_prerequisites}$(prerequisite_entry "root-cmake-package-target" 0 "Not migrated yet")"
|
||||
android_standard_entry="{"
|
||||
android_standard_entry="${android_standard_entry}\"kind\":\"android-standard-apk\","
|
||||
android_standard_entry="${android_standard_entry}\"status\":\"$android_standard_status\","
|
||||
android_standard_entry="${android_standard_entry}\"reason\":\"legacy-gradle-package-not-consuming-root-cmake-targets\","
|
||||
android_standard_entry="${android_standard_entry}\"debt\":\"DEBT-0011\","
|
||||
android_standard_entry="${android_standard_entry}\"validationCommand\":\"gradle -p android/android assembleDebug\","
|
||||
android_standard_entry="${android_standard_entry}\"prerequisites\":[${android_standard_prerequisites}],"
|
||||
android_standard_entry="${android_standard_entry}\"artifacts\":["
|
||||
android_standard_entry="${android_standard_entry}$(artifact_entry "apk-output" "$android_standard_output" "Container")"
|
||||
android_standard_entry="${android_standard_entry}]}"
|
||||
append_json_item "$android_standard_entry"
|
||||
fi
|
||||
|
||||
if is_kind_requested "android-quest-apk"; then
|
||||
android_quest_status="$(resolve_status 0 0 "$android_quest_gradle_exists" "$android_quest_manifest_exists" "$gradle_exists" "$android_native_quest_available")"
|
||||
android_quest_prerequisites=''
|
||||
android_quest_prerequisites="${android_quest_prerequisites}$(prerequisite_entry "gradle-build" "$android_quest_gradle_exists" "$android_quest_gradle"),"
|
||||
android_quest_prerequisites="${android_quest_prerequisites}$(prerequisite_entry "android-manifest" "$android_quest_manifest_exists" "$android_quest_manifest"),"
|
||||
android_quest_prerequisites="${android_quest_prerequisites}$(prerequisite_entry "gradle" "$gradle_exists" "Android package builder"),"
|
||||
android_quest_prerequisites="${android_quest_prerequisites}$(prerequisite_entry "retained-native-cmake-check" "$android_native_quest_available" "$android_native_quest_detail"),"
|
||||
android_quest_prerequisites="${android_quest_prerequisites}$(prerequisite_entry "root-cmake-preset" 1 "android-quest-arm64"),"
|
||||
android_quest_prerequisites="${android_quest_prerequisites}$(prerequisite_entry "root-cmake-package-target" 0 "Not migrated yet")"
|
||||
android_quest_entry="{"
|
||||
android_quest_entry="${android_quest_entry}\"kind\":\"android-quest-apk\","
|
||||
android_quest_entry="${android_quest_entry}\"status\":\"$android_quest_status\","
|
||||
android_quest_entry="${android_quest_entry}\"reason\":\"legacy-gradle-package-not-consuming-root-cmake-targets\","
|
||||
android_quest_entry="${android_quest_entry}\"debt\":\"DEBT-0011\","
|
||||
android_quest_entry="${android_quest_entry}\"validationCommand\":\"gradle -p android/quest assembleDebug\","
|
||||
android_quest_entry="${android_quest_entry}\"prerequisites\":[${android_quest_prerequisites}],"
|
||||
android_quest_entry="${android_quest_entry}\"artifacts\":["
|
||||
android_quest_entry="${android_quest_entry}$(artifact_entry "apk-output" "$android_quest_output" "Container")"
|
||||
android_quest_entry="${android_quest_entry}]}"
|
||||
append_json_item "$android_quest_entry"
|
||||
fi
|
||||
|
||||
if is_kind_requested "android-focus-apk"; then
|
||||
android_focus_status="$(resolve_status 0 0 "$android_focus_gradle_exists" "$android_focus_manifest_exists" "$gradle_exists" "$android_native_focus_available")"
|
||||
android_focus_prerequisites=''
|
||||
android_focus_prerequisites="${android_focus_prerequisites}$(prerequisite_entry "gradle-build" "$android_focus_gradle_exists" "$android_focus_gradle"),"
|
||||
android_focus_prerequisites="${android_focus_prerequisites}$(prerequisite_entry "android-manifest" "$android_focus_manifest_exists" "$android_focus_manifest"),"
|
||||
android_focus_prerequisites="${android_focus_prerequisites}$(prerequisite_entry "gradle" "$gradle_exists" "Android package builder"),"
|
||||
android_focus_prerequisites="${android_focus_prerequisites}$(prerequisite_entry "retained-native-cmake-check" "$android_native_focus_available" "$android_native_focus_detail"),"
|
||||
android_focus_prerequisites="${android_focus_prerequisites}$(prerequisite_entry "root-cmake-preset" 1 "android-focus-arm64"),"
|
||||
android_focus_prerequisites="${android_focus_prerequisites}$(prerequisite_entry "root-cmake-package-target" 0 "Not migrated yet")"
|
||||
android_focus_entry="{"
|
||||
android_focus_entry="${android_focus_entry}\"kind\":\"android-focus-apk\","
|
||||
android_focus_entry="${android_focus_entry}\"status\":\"$android_focus_status\","
|
||||
android_focus_entry="${android_focus_entry}\"reason\":\"legacy-gradle-package-not-consuming-root-cmake-targets\","
|
||||
android_focus_entry="${android_focus_entry}\"debt\":\"DEBT-0011\","
|
||||
android_focus_entry="${android_focus_entry}\"validationCommand\":\"gradle -p android/focus assembleDebug\","
|
||||
android_focus_entry="${android_focus_entry}\"prerequisites\":[${android_focus_prerequisites}],"
|
||||
android_focus_entry="${android_focus_entry}\"artifacts\":["
|
||||
android_focus_entry="${android_focus_entry}$(artifact_entry "apk-output" "$android_focus_output" "Container")"
|
||||
android_focus_entry="${android_focus_entry}]}"
|
||||
append_json_item "$android_focus_entry"
|
||||
fi
|
||||
|
||||
if is_kind_requested "apple-bundle"; then
|
||||
apple_status="$(resolve_status 0 1 "$apple_project_exists" "$xcodebuild_exists")"
|
||||
apple_prerequisites=''
|
||||
apple_prerequisites="${apple_prerequisites}$(prerequisite_entry "legacy-xcode-project" "$apple_project_exists" "$apple_project"),"
|
||||
apple_prerequisites="${apple_prerequisites}$(prerequisite_entry "xcodebuild" "$xcodebuild_exists" "Apple package builder"),"
|
||||
apple_prerequisites="${apple_prerequisites}$(prerequisite_entry "root-cmake-preset" 1 "macos/ios-device/ios-simulator"),"
|
||||
apple_prerequisites="${apple_prerequisites}$(prerequisite_entry "root-cmake-package-target" 0 "Not migrated yet")"
|
||||
apple_entry="{"
|
||||
apple_entry="${apple_entry}\"kind\":\"apple-bundle\","
|
||||
apple_entry="${apple_entry}\"status\":\"$apple_status\","
|
||||
apple_entry="${apple_entry}\"reason\":\"legacy-xcode-project-and-host-toolchain-not-aligned-with-root-cmake-package-target\","
|
||||
apple_entry="${apple_entry}\"debt\":\"DEBT-0011\","
|
||||
apple_entry="${apple_entry}\"validationCommand\":\"xcodebuild -project PanoPainter.xcodeproj -configuration $configuration\","
|
||||
apple_entry="${apple_entry}\"prerequisites\":[${apple_prerequisites}],"
|
||||
apple_entry="${apple_entry}\"artifacts\":["
|
||||
apple_entry="${apple_entry}$(artifact_entry "apple-package-output" "$apple_output" "Container")"
|
||||
apple_entry="${apple_entry}]}"
|
||||
append_json_item "$apple_entry"
|
||||
fi
|
||||
|
||||
if is_kind_requested "linux-app"; then
|
||||
linux_status="$(resolve_status 0 0 "$linux_cmake_exists" "$cmake_exists")"
|
||||
linux_prerequisites=''
|
||||
linux_prerequisites="${linux_prerequisites}$(prerequisite_entry "retained-linux-cmake" "$linux_cmake_exists" "$linux_cmake"),"
|
||||
linux_prerequisites="${linux_prerequisites}$(prerequisite_entry "cmake" "$cmake_exists" "Linux retained app CMake configure/build tool"),"
|
||||
linux_prerequisites="${linux_prerequisites}$(prerequisite_entry "retained-platform-cmake-baseline" 1 "python scripts/dev/check_retained_platform_cmake.py"),"
|
||||
linux_prerequisites="${linux_prerequisites}$(prerequisite_entry "root-cmake-preset" 1 "linux-clang"),"
|
||||
linux_prerequisites="${linux_prerequisites}$(prerequisite_entry "root-cmake-package-target" 0 "Not migrated yet")"
|
||||
linux_entry="{"
|
||||
linux_entry="${linux_entry}\"kind\":\"linux-app\","
|
||||
linux_entry="${linux_entry}\"status\":\"$linux_status\","
|
||||
linux_entry="${linux_entry}\"reason\":\"retained-linux-cmake-not-consuming-root-cmake-targets\","
|
||||
linux_entry="${linux_entry}\"debt\":\"DEBT-0011\","
|
||||
linux_entry="${linux_entry}\"validationCommand\":\"cmake -S linux -B out/package/linux-retained && cmake --build out/package/linux-retained --target panopainter\","
|
||||
linux_entry="${linux_entry}\"prerequisites\":[${linux_prerequisites}],"
|
||||
linux_entry="${linux_entry}\"artifacts\":["
|
||||
linux_entry="${linux_entry}$(artifact_entry "linux-app-output" "$linux_output" "Leaf")"
|
||||
linux_entry="${linux_entry}]}"
|
||||
append_json_item "$linux_entry"
|
||||
fi
|
||||
|
||||
if is_kind_requested "webgl"; then
|
||||
webgl_status="$(resolve_status 0 0 "$webgl_cmake_exists" "$emcc_exists" "$emcmake_exists")"
|
||||
webgl_prerequisites=''
|
||||
webgl_prerequisites="${webgl_prerequisites}$(prerequisite_entry "retained-webgl-cmake" "$webgl_cmake_exists" "$webgl_cmake"),"
|
||||
webgl_prerequisites="${webgl_prerequisites}$(prerequisite_entry "emcc" "$emcc_exists" "Emscripten compiler"),"
|
||||
webgl_prerequisites="${webgl_prerequisites}$(prerequisite_entry "emcmake" "$emcmake_exists" "Emscripten CMake wrapper"),"
|
||||
webgl_prerequisites="${webgl_prerequisites}$(prerequisite_entry "retained-platform-cmake-baseline" 1 "python scripts/dev/check_retained_platform_cmake.py"),"
|
||||
webgl_prerequisites="${webgl_prerequisites}$(prerequisite_entry "root-cmake-preset" 1 "emscripten"),"
|
||||
webgl_prerequisites="${webgl_prerequisites}$(prerequisite_entry "root-cmake-package-target" 0 "Not migrated yet")"
|
||||
webgl_entry="{"
|
||||
webgl_entry="${webgl_entry}\"kind\":\"webgl\","
|
||||
webgl_entry="${webgl_entry}\"status\":\"$webgl_status\","
|
||||
webgl_entry="${webgl_entry}\"reason\":\"retained-webgl-cmake-not-consuming-root-cmake-targets\","
|
||||
webgl_entry="${webgl_entry}\"debt\":\"DEBT-0011\","
|
||||
webgl_entry="${webgl_entry}\"validationCommand\":\"emcmake cmake -S webgl -B out/package/webgl-retained && cmake --build out/package/webgl-retained --target panopainter\","
|
||||
webgl_entry="${webgl_entry}\"prerequisites\":[${webgl_prerequisites}],"
|
||||
webgl_entry="${webgl_entry}\"artifacts\":["
|
||||
webgl_entry="${webgl_entry}$(artifact_entry "webgl-output" "$webgl_output" "Container")"
|
||||
webgl_entry="${webgl_entry}]}"
|
||||
append_json_item "$webgl_entry"
|
||||
fi
|
||||
|
||||
printf "[%s]" "$package_readiness"
|
||||
}
|
||||
|
||||
build_android_native_validation
|
||||
|
||||
if [ "$readiness_only" -eq 1 ]; then
|
||||
end="$(date +%s)"
|
||||
elapsed_ms="$(( (end - start) * 1000 ))"
|
||||
readiness="$(package_readiness_json)"
|
||||
printf '{"command":"package-smoke","preset":"%s","configuration":"%s","target":"%s","stage":"readiness","exitCode":0,"elapsedMs":%s,"packageReadiness":%s}\n' "$preset" "$configuration" "$target" "$elapsed_ms" "$readiness"
|
||||
elapsed_ms="$(( ( $(date +%s) - start ) * 1000 ))"
|
||||
package_readiness="$(build_package_readiness)"
|
||||
printf '{"command":"package-smoke",'
|
||||
printf '"preset":%s,"configuration":%s,"target":%s,' \
|
||||
"$(json_string "$preset")" \
|
||||
"$(json_string "$configuration")" \
|
||||
"$(json_string "$target")"
|
||||
printf '"stage":"readiness","exitCode":0,"elapsedMs":%s,' "$elapsed_ms"
|
||||
printf '"androidNativeValidation":%s,' "$android_native_validation"
|
||||
printf '"packageReadiness":%s}\n' "$package_readiness"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cmake --build --preset "$preset" --config "$configuration" --target "$target"
|
||||
$cmake_command --build --preset "$preset" --config "$configuration" --target "$target"
|
||||
build_exit="$?"
|
||||
if [ "$build_exit" -ne 0 ]; then
|
||||
end="$(date +%s)"
|
||||
elapsed_ms="$(( (end - start) * 1000 ))"
|
||||
readiness="$(package_readiness_json)"
|
||||
printf '{"command":"package-smoke","preset":"%s","configuration":"%s","target":"%s","stage":"build","exitCode":%s,"elapsedMs":%s,"packageReadiness":%s}\n' "$preset" "$configuration" "$target" "$build_exit" "$elapsed_ms" "$readiness"
|
||||
elapsed_ms="$(( ( $(date +%s) - start ) * 1000 ))"
|
||||
package_readiness="$(build_package_readiness)"
|
||||
printf '{"command":"package-smoke",'
|
||||
printf '"preset":%s,"configuration":%s,"target":%s,' \
|
||||
"$(json_string "$preset")" \
|
||||
"$(json_string "$configuration")" \
|
||||
"$(json_string "$target")"
|
||||
printf '"cmakeCommand":%s,' "$(json_string "$cmake_command")"
|
||||
printf '"stage":"build","exitCode":%s,"elapsedMs":%s,' "$build_exit" "$elapsed_ms"
|
||||
printf '"androidNativeValidation":%s,' "$android_native_validation"
|
||||
printf '"packageReadiness":%s}\n' "$package_readiness"
|
||||
exit "$build_exit"
|
||||
fi
|
||||
|
||||
if [ -e "$artifact" ]; then
|
||||
exit_code=0
|
||||
else
|
||||
binary="${root}/out/build/$preset/$configuration/$target.exe"
|
||||
binary_dir="$(printf '%s' "$binary" | sed 's#/[^/]*$##')"
|
||||
data_dir="$binary_dir/data"
|
||||
curl_dll="$(
|
||||
if [ "$configuration" = "Debug" ]; then
|
||||
printf "libcurl_debug.dll"
|
||||
else
|
||||
printf "libcurl.dll"
|
||||
fi
|
||||
)"
|
||||
|
||||
checks=''
|
||||
checks="${checks}$(check_entry "executable" "$binary" "$([ -f "$binary" ] && printf "1" || printf "0")"),"
|
||||
checks="${checks}$(check_entry "data" "$data_dir" "$([ -d "$data_dir" ] && printf "1" || printf "0")"),"
|
||||
checks="${checks}$(check_entry "BugTrapU-x64.dll" "$binary_dir/BugTrapU-x64.dll" "$([ -f "$binary_dir/BugTrapU-x64.dll" ] && printf "1" || printf "0")"),"
|
||||
checks="${checks}$(check_entry "$curl_dll" "$binary_dir/$curl_dll" "$([ -f "$binary_dir/$curl_dll" ] && printf "1" || printf "0")"),"
|
||||
checks="${checks}$(check_entry "libyuv.dll" "$binary_dir/libyuv.dll" "$([ -f "$binary_dir/libyuv.dll" ] && printf "1" || printf "0")"),"
|
||||
checks="${checks}$(check_entry "libmp4v2.dll" "$binary_dir/libmp4v2.dll" "$([ -f "$binary_dir/libmp4v2.dll" ] && printf "1" || printf "0")"),"
|
||||
checks="${checks}$(check_entry "openh264-2.0.0-win64.dll" "$binary_dir/openh264-2.0.0-win64.dll" "$([ -f "$binary_dir/openh264-2.0.0-win64.dll" ] && printf "1" || printf "0")"),"
|
||||
checks="${checks}$(check_entry "openvr_api.dll" "$binary_dir/openvr_api.dll" "$([ -f "$binary_dir/openvr_api.dll" ] && printf "1" || printf "0")")"
|
||||
|
||||
artifact_exists="$( [ -e "$artifact" ] && printf 1 || printf 0 )"
|
||||
exit_code=0
|
||||
if [ "$artifact_exists" -eq 0 ]; then
|
||||
exit_code=2
|
||||
fi
|
||||
if [ "$android_native_checks" -ne 0 ] && [ "$exit_code" -eq 0 ]; then
|
||||
exit_code="$(echo "$android_native_validation" | sed -n 's/.*"exitCode":[[:space:]]*\\([0-9][0-9]*\\).*/\\1/p')"
|
||||
if [ "$exit_code" -eq 0 ]; then
|
||||
exit_code=0
|
||||
else
|
||||
exit_code=1
|
||||
fi
|
||||
fi
|
||||
|
||||
end="$(date +%s)"
|
||||
elapsed_ms="$(( (end - start) * 1000 ))"
|
||||
readiness="$(package_readiness_json)"
|
||||
printf '{"command":"package-smoke","preset":"%s","configuration":"%s","target":"%s","artifact":"%s","exists":%s,"exitCode":%s,"elapsedMs":%s,"packageReadiness":%s}\n' "$preset" "$configuration" "$target" "$artifact" "$([ "$exit_code" -eq 0 ] && printf true || printf false)" "$exit_code" "$elapsed_ms" "$readiness"
|
||||
package_readiness="$(build_package_readiness)"
|
||||
elapsed_ms="$(( ( $(date +%s) - start ) * 1000 ))"
|
||||
|
||||
printf '{"command":"package-smoke",'
|
||||
printf '"preset":%s,"configuration":%s,"target":%s,' \
|
||||
"$(json_string "$preset")" \
|
||||
"$(json_string "$configuration")" \
|
||||
"$(json_string "$target")"
|
||||
printf '"artifact":%s,"exists":%s,"cmakeCommand":%s,' \
|
||||
"$(json_string "$artifact")" \
|
||||
"$(json_bool "$artifact_exists")" \
|
||||
"$(json_string "$cmake_command")"
|
||||
printf '"exitCode":%s,"elapsedMs":%s,' "$exit_code" "$elapsed_ms"
|
||||
printf '"checks":[%s],' "$checks"
|
||||
printf '"androidNativeValidation":%s,' "$android_native_validation"
|
||||
printf '"packageReadiness":%s}\n' "$package_readiness"
|
||||
exit "$exit_code"
|
||||
|
||||
@@ -19,6 +19,7 @@ param(
|
||||
"pp_foundation_parse_tests",
|
||||
"pp_foundation_task_queue_tests",
|
||||
"pp_foundation_trace_tests",
|
||||
"pp_foundation_task_queue_stress_tests",
|
||||
"pp_assets_brush_package_tests",
|
||||
"pp_assets_image_format_tests",
|
||||
"pp_assets_image_metadata_tests",
|
||||
@@ -53,6 +54,7 @@ param(
|
||||
"pp_app_core_app_shutdown_tests",
|
||||
"pp_app_core_app_startup_tests",
|
||||
"pp_app_core_app_status_tests",
|
||||
"pp_app_core_app_thread_stress_tests",
|
||||
"pp_app_core_command_convert_tests",
|
||||
"pp_app_core_brush_package_export_tests",
|
||||
"pp_app_core_brush_package_import_tests",
|
||||
|
||||
@@ -3,7 +3,7 @@ set -u
|
||||
|
||||
presets="${1:-android-arm64 android-x64 android-quest-arm64 android-focus-arm64}"
|
||||
shift || true
|
||||
targets="${*:-pp_foundation pp_assets pp_paint pp_document pp_renderer_api pp_renderer_gl pp_paint_renderer pp_ui_core pp_platform_api pp_app_core pano_cli pp_foundation_binary_stream_tests pp_foundation_event_tests pp_foundation_log_tests pp_foundation_parse_tests pp_foundation_task_queue_tests pp_foundation_trace_tests pp_assets_brush_package_tests pp_assets_image_format_tests pp_assets_image_metadata_tests pp_assets_image_pixels_tests pp_assets_ppi_header_tests pp_assets_settings_document_tests pp_paint_brush_tests pp_paint_blend_tests pp_paint_stroke_tests pp_paint_stroke_script_tests pp_document_tests pp_document_ppi_import_tests pp_document_ppi_export_tests pp_renderer_api_tests pp_renderer_gl_capabilities_tests pp_renderer_gl_command_plan_tests pp_paint_renderer_compositor_tests pp_paint_renderer_stroke_execution_tests pp_renderer_gl_gpu_readback_tests pp_platform_api_tests pp_ui_core_color_tests pp_ui_core_layout_value_tests pp_ui_core_layout_xml_tests pp_ui_core_node_lifetime_tests pp_ui_core_overlay_lifetime_tests pp_app_core_about_menu_tests pp_app_core_app_dialog_tests pp_app_core_app_preferences_tests pp_app_core_app_frame_tests pp_app_core_app_thread_tests pp_app_core_app_input_tests pp_app_core_app_shutdown_tests pp_app_core_app_startup_tests pp_app_core_app_status_tests pp_app_core_command_convert_tests pp_app_core_brush_package_export_tests pp_app_core_brush_package_import_tests pp_app_core_brush_ui_tests pp_app_core_canvas_hotkey_tests pp_app_core_canvas_tool_ui_tests pp_app_core_canvas_view_tests pp_app_core_document_animation_tests pp_app_core_document_canvas_tests pp_app_core_document_cloud_tests pp_app_core_document_export_tests pp_app_core_document_import_tests pp_app_core_document_layer_tests pp_app_core_document_platform_io_tests pp_app_core_document_recording_tests pp_app_core_document_resize_tests pp_app_core_document_route_tests pp_app_core_document_sharing_tests pp_app_core_document_session_tests pp_app_core_file_menu_tests pp_app_core_grid_ui_tests pp_app_core_history_ui_tests pp_app_core_main_toolbar_tests pp_app_core_quick_ui_tests pp_app_core_tools_menu_tests}"
|
||||
targets="${*:-pp_foundation pp_assets pp_paint pp_document pp_renderer_api pp_renderer_gl pp_paint_renderer pp_ui_core pp_platform_api pp_app_core pano_cli pp_foundation_binary_stream_tests pp_foundation_event_tests pp_foundation_log_tests pp_foundation_parse_tests pp_foundation_task_queue_tests pp_foundation_task_queue_stress_tests pp_foundation_trace_tests pp_assets_brush_package_tests pp_assets_image_format_tests pp_assets_image_metadata_tests pp_assets_image_pixels_tests pp_assets_ppi_header_tests pp_assets_settings_document_tests pp_paint_brush_tests pp_paint_blend_tests pp_paint_stroke_tests pp_paint_stroke_script_tests pp_document_tests pp_document_ppi_import_tests pp_document_ppi_export_tests pp_renderer_api_tests pp_renderer_gl_capabilities_tests pp_renderer_gl_command_plan_tests pp_paint_renderer_compositor_tests pp_paint_renderer_stroke_execution_tests pp_renderer_gl_gpu_readback_tests pp_platform_api_tests pp_ui_core_color_tests pp_ui_core_layout_value_tests pp_ui_core_layout_xml_tests pp_ui_core_node_lifetime_tests pp_ui_core_overlay_lifetime_tests pp_app_core_about_menu_tests pp_app_core_app_dialog_tests pp_app_core_app_preferences_tests pp_app_core_app_frame_tests pp_app_core_app_thread_tests pp_app_core_app_thread_stress_tests pp_app_core_app_input_tests pp_app_core_app_shutdown_tests pp_app_core_app_startup_tests pp_app_core_app_status_tests pp_app_core_command_convert_tests pp_app_core_brush_package_export_tests pp_app_core_brush_package_import_tests pp_app_core_brush_ui_tests pp_app_core_canvas_hotkey_tests pp_app_core_canvas_tool_ui_tests pp_app_core_canvas_view_tests pp_app_core_document_animation_tests pp_app_core_document_canvas_tests pp_app_core_document_cloud_tests pp_app_core_document_export_tests pp_app_core_document_import_tests pp_app_core_document_layer_tests pp_app_core_document_platform_io_tests pp_app_core_document_recording_tests pp_app_core_document_resize_tests pp_app_core_document_route_tests pp_app_core_document_sharing_tests pp_app_core_document_session_tests pp_app_core_file_menu_tests pp_app_core_grid_ui_tests pp_app_core_history_ui_tests pp_app_core_main_toolbar_tests pp_app_core_quick_ui_tests pp_app_core_tools_menu_tests}"
|
||||
start="$(date +%s)"
|
||||
|
||||
android_cmake_cmd=""
|
||||
|
||||
246
scripts/dev/check_component_boundaries.py
Normal file
246
scripts/dev/check_component_boundaries.py
Normal file
@@ -0,0 +1,246 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate component boundary rules for pure architectural targets."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
INCLUDE_RE = re.compile(r"""^\s*#\s*include\s+(\"([^\"]+)\"|<([^>]+)>)""")
|
||||
SINGLETON_RE = re.compile(r"\b(?:App::I|Canvas::I)\b")
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
SRC_ROOT = REPO_ROOT / "src"
|
||||
CMAKE_FILE = REPO_ROOT / "CMakeLists.txt"
|
||||
|
||||
COMPONENT_BY_DIR = {
|
||||
"foundation": "pp_foundation",
|
||||
"assets": "pp_assets",
|
||||
"paint": "pp_paint",
|
||||
"document": "pp_document",
|
||||
"renderer_api": "pp_renderer_api",
|
||||
"paint_renderer": "pp_paint_renderer",
|
||||
"ui_core": "pp_ui_core",
|
||||
"app_core": "pp_app_core",
|
||||
}
|
||||
|
||||
PURE_TARGETS = set(COMPONENT_BY_DIR.values())
|
||||
TARGET_INFRA = {"pp_project_options", "pp_project_warnings", "pp_xml_tinyxml2"}
|
||||
|
||||
ALLOWED_LINKS = {
|
||||
"pp_foundation": set(),
|
||||
"pp_assets": {"pp_foundation"},
|
||||
"pp_paint": {"pp_foundation"},
|
||||
"pp_document": {"pp_foundation", "pp_assets", "pp_paint"},
|
||||
"pp_renderer_api": {"pp_foundation"},
|
||||
"pp_paint_renderer": {"pp_foundation", "pp_paint", "pp_document", "pp_renderer_api"},
|
||||
"pp_ui_core": {"pp_foundation", "pp_xml_tinyxml2"},
|
||||
"pp_app_core": {"pp_foundation", "pp_document", "pp_assets", "pp_paint", "pp_ui_core"},
|
||||
}
|
||||
|
||||
ALLOWED_LOCAL_INCLUDES = {
|
||||
"pp_foundation": ("foundation/",),
|
||||
"pp_assets": ("foundation/", "assets/"),
|
||||
"pp_paint": ("foundation/", "paint/"),
|
||||
"pp_document": ("foundation/", "assets/", "paint/", "document/"),
|
||||
"pp_renderer_api": ("foundation/", "renderer_api/"),
|
||||
"pp_paint_renderer": (
|
||||
"assets/",
|
||||
"document/",
|
||||
"foundation/",
|
||||
"paint/",
|
||||
"paint_renderer/",
|
||||
"renderer_api/",
|
||||
),
|
||||
"pp_ui_core": ("foundation/", "ui_core/"),
|
||||
"pp_app_core": ("app_core/", "assets/", "document/", "foundation/", "paint/", "ui_core/"),
|
||||
}
|
||||
|
||||
ALLOWED_EXTERNAL_PREFIXES = (
|
||||
"stb/",
|
||||
)
|
||||
|
||||
FORBIDDEN_INCLUDE_TOKENS = (
|
||||
"platform/windows",
|
||||
"platform/windows",
|
||||
"platform_apple",
|
||||
"platform_legacy",
|
||||
"platform_api/",
|
||||
"platform_legacy/",
|
||||
"platform_apple/",
|
||||
"platform_windows/",
|
||||
"opengl/",
|
||||
"/opengl",
|
||||
"<gl",
|
||||
"glad/",
|
||||
"<GL/",
|
||||
"<openGL/",
|
||||
"vulkan/",
|
||||
"directx",
|
||||
"d3d",
|
||||
"android/",
|
||||
"ios/",
|
||||
"objc/",
|
||||
"metal/",
|
||||
"windows.h",
|
||||
"wingdi.h",
|
||||
"afxwin.h",
|
||||
"App::I",
|
||||
"Canvas::I",
|
||||
)
|
||||
|
||||
|
||||
def repo_root() -> Path:
|
||||
return REPO_ROOT
|
||||
|
||||
|
||||
def component_for_path(path: Path) -> str | None:
|
||||
try:
|
||||
rel = path.relative_to(SRC_ROOT)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
if not rel.parts:
|
||||
return None
|
||||
return COMPONENT_BY_DIR.get(rel.parts[0])
|
||||
|
||||
|
||||
def collect_target_links(cmake_text: str, target: str) -> list[str] | None:
|
||||
pattern = re.compile(rf"target_link_libraries\(\s*{re.escape(target)}\s+(.*?)\)", re.S | re.I)
|
||||
matches = pattern.findall(cmake_text)
|
||||
if not matches:
|
||||
return None
|
||||
|
||||
tokens: list[str] = []
|
||||
for block in matches:
|
||||
block = block.replace("\\\n", " ")
|
||||
for token in re.split(r"\s+", block):
|
||||
token = token.strip()
|
||||
if not token or token.upper() in {"PUBLIC", "PRIVATE", "INTERFACE"}:
|
||||
continue
|
||||
token = token.strip("\"'")
|
||||
if token.startswith("$<") or token.startswith("SHELL:"):
|
||||
continue
|
||||
tokens.append(token)
|
||||
return tokens
|
||||
|
||||
|
||||
def check_link_dependencies(cmake_text: str) -> list[dict[str, Any]]:
|
||||
violations: list[dict[str, Any]] = []
|
||||
for target in sorted(PURE_TARGETS):
|
||||
deps = collect_target_links(cmake_text, target)
|
||||
if deps is None:
|
||||
violations.append(
|
||||
{
|
||||
"target": target,
|
||||
"dependency": None,
|
||||
"kind": "missing-target-link-declaration",
|
||||
"message": "No target_link_libraries block found",
|
||||
}
|
||||
)
|
||||
continue
|
||||
|
||||
allowed = ALLOWED_LINKS[target]
|
||||
for dependency in deps:
|
||||
if dependency in TARGET_INFRA:
|
||||
continue
|
||||
if dependency in allowed:
|
||||
continue
|
||||
if dependency.startswith("pp_"):
|
||||
violations.append(
|
||||
{
|
||||
"target": target,
|
||||
"dependency": dependency,
|
||||
"kind": "invalid-target-edge",
|
||||
"message": f"{target} must not depend on {dependency}",
|
||||
}
|
||||
)
|
||||
return violations
|
||||
|
||||
|
||||
def is_forbidden_include(component: str, include: str) -> tuple[bool, str | None]:
|
||||
include_lower = include.lower()
|
||||
if any(token in include_lower for token in FORBIDDEN_INCLUDE_TOKENS):
|
||||
token = next(token for token in FORBIDDEN_INCLUDE_TOKENS if token in include_lower)
|
||||
return True, token
|
||||
if "/" in include_lower and any(include_lower.startswith(prefix) for prefix in ALLOWED_EXTERNAL_PREFIXES):
|
||||
return False, None
|
||||
|
||||
if "/" in include:
|
||||
allowed_prefixes = ALLOWED_LOCAL_INCLUDES[component]
|
||||
if not any(include_lower.startswith(prefix) for prefix in allowed_prefixes):
|
||||
return True, "component-boundary-crossing-include"
|
||||
return False, None
|
||||
|
||||
|
||||
def check_pure_component_sources() -> list[dict[str, Any]]:
|
||||
violations: list[dict[str, Any]] = []
|
||||
|
||||
for path in SRC_ROOT.rglob("*"):
|
||||
if not path.is_file():
|
||||
continue
|
||||
if path.suffix.lower() not in {".cpp", ".cc", ".c", ".h", ".hpp", ".hh"}:
|
||||
continue
|
||||
|
||||
component = component_for_path(path)
|
||||
if component is None:
|
||||
continue
|
||||
|
||||
for line_no, line in enumerate(path.read_text(encoding="utf-8").splitlines(), start=1):
|
||||
include_match = INCLUDE_RE.match(line)
|
||||
if include_match:
|
||||
include = (include_match.group(2) or include_match.group(3) or "").strip()
|
||||
forbidden, reason = is_forbidden_include(component, include)
|
||||
if forbidden:
|
||||
violations.append(
|
||||
{
|
||||
"file": str(path.relative_to(REPO_ROOT)),
|
||||
"line": line_no,
|
||||
"kind": "forbidden-include",
|
||||
"include": include,
|
||||
"detail": reason,
|
||||
"text": line.strip(),
|
||||
}
|
||||
)
|
||||
|
||||
if SINGLETON_RE.search(line):
|
||||
violations.append(
|
||||
{
|
||||
"file": str(path.relative_to(REPO_ROOT)),
|
||||
"line": line_no,
|
||||
"kind": "legacy-singleton-reference",
|
||||
"detail": "App::I/Canvas::I is not allowed in pure components",
|
||||
"text": line.strip(),
|
||||
}
|
||||
)
|
||||
|
||||
return violations
|
||||
|
||||
|
||||
def main() -> int:
|
||||
source_violations = check_pure_component_sources()
|
||||
cmake_text = CMAKE_FILE.read_text(encoding="utf-8")
|
||||
link_violations = check_link_dependencies(cmake_text)
|
||||
|
||||
all_violations = source_violations + link_violations
|
||||
ok = len(all_violations) == 0
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
"ok": ok,
|
||||
"summary": {
|
||||
"sourceViolationCount": len(source_violations),
|
||||
"linkViolationCount": len(link_violations),
|
||||
},
|
||||
"violations": all_violations,
|
||||
},
|
||||
separators=(",", ":"),
|
||||
)
|
||||
)
|
||||
return 0 if ok else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -22,9 +22,16 @@ EXPECTED_PACKAGE_KINDS = [
|
||||
EXPECTED_CMAKE_PACKAGE_TARGETS = [
|
||||
"panopainter_package_readiness",
|
||||
"panopainter_windows_app_package_smoke",
|
||||
"panopainter_windows_appx_package_readiness",
|
||||
"panopainter_apple_bundle_package_readiness",
|
||||
"panopainter_android_standard_native_package",
|
||||
"panopainter_android_standard_apk_package_readiness",
|
||||
"panopainter_android_quest_apk_package_readiness",
|
||||
"panopainter_android_focus_apk_package_readiness",
|
||||
"panopainter_android_vr_native_package_configure",
|
||||
"panopainter_android_native_package_smoke",
|
||||
"panopainter_linux_app_package_readiness",
|
||||
"panopainter_webgl_package_readiness",
|
||||
"panopainter_linux_webgl_package_readiness",
|
||||
]
|
||||
|
||||
@@ -43,7 +50,15 @@ def powershell_package_kinds(root: Path) -> list[str]:
|
||||
|
||||
def shell_package_kinds(root: Path) -> list[str]:
|
||||
script = (root / "scripts" / "automation" / "package-smoke.sh").read_text(encoding="utf-8")
|
||||
return sorted(set(re.findall(r'"kind":"([^"]+)"', script)))
|
||||
match = re.search(r'package_kinds="([^"]+)"', script)
|
||||
if match:
|
||||
return sorted(set(filter(None, (value.strip() for value in match.group(1).split(",")))))
|
||||
|
||||
quoted_kinds = sorted(set(re.findall(r'"kind":"([^"]+)"', script)))
|
||||
escaped_kinds = sorted(set(re.findall(r'\\"kind\\":\\"([^\\"]+)\\"', script)))
|
||||
if quoted_kinds or escaped_kinds:
|
||||
return sorted(set(quoted_kinds).union(escaped_kinds))
|
||||
raise RuntimeError("Could not find package kinds defaults in package-smoke.sh")
|
||||
|
||||
|
||||
def count_regex(root: Path, patterns: dict[str, str]) -> dict[str, int]:
|
||||
@@ -59,13 +74,29 @@ def main() -> int:
|
||||
expected = sorted(EXPECTED_PACKAGE_KINDS)
|
||||
ps_kinds = powershell_package_kinds(root)
|
||||
sh_kinds = shell_package_kinds(root)
|
||||
script_texts = {
|
||||
"package-smoke.ps1": (root / "scripts" / "automation" / "package-smoke.ps1").read_text(encoding="utf-8"),
|
||||
"package-smoke.sh": (root / "scripts" / "automation" / "package-smoke.sh").read_text(encoding="utf-8"),
|
||||
}
|
||||
debt_counts = count_regex(root, {
|
||||
"package-smoke.ps1": r'debt\s*=\s*"DEBT-0011"',
|
||||
"package-smoke.sh": r'"debt":"DEBT-0011"',
|
||||
"package-smoke.sh": r'\\"debt\\":\\"DEBT-0011\\"',
|
||||
})
|
||||
blocked_counts = count_regex(root, {
|
||||
"package-smoke.ps1": r'-Status\s+"blocked"',
|
||||
"package-smoke.sh": r'"status":"blocked"',
|
||||
status_tokens = ("blocked", "compile-only", "validated")
|
||||
status_modes = {
|
||||
name: [token for token in status_tokens if f'"{token}"' in text]
|
||||
for name, text in script_texts.items()
|
||||
}
|
||||
status_mode_present = {
|
||||
name: {
|
||||
token: f'"{token}"' in script_texts[name]
|
||||
for token in ("blocked", "compile-only")
|
||||
}
|
||||
for name in ("package-smoke.ps1", "package-smoke.sh")
|
||||
}
|
||||
readiness_alignment = count_regex(root, {
|
||||
"package-smoke.ps1": r'androidNativeValidation',
|
||||
"package-smoke.sh": r'androidNativeValidation',
|
||||
})
|
||||
readiness_mode_counts = {
|
||||
"package-smoke.ps1": (root / "scripts" / "automation" / "package-smoke.ps1").read_text(encoding="utf-8").count("ReadinessOnly"),
|
||||
@@ -95,7 +126,10 @@ def main() -> int:
|
||||
"package-smoke.sh": len(expected),
|
||||
}
|
||||
debt_complete = {name: count >= debt_thresholds[name] for name, count in debt_counts.items()}
|
||||
blocked_complete = {name: count >= len(expected) for name, count in blocked_counts.items()}
|
||||
status_gate_complete = {
|
||||
"package-smoke.ps1": status_mode_present["package-smoke.ps1"]["blocked"] and status_mode_present["package-smoke.ps1"]["compile-only"],
|
||||
"package-smoke.sh": status_mode_present["package-smoke.sh"]["blocked"] and status_mode_present["package-smoke.sh"]["compile-only"],
|
||||
}
|
||||
readiness_mode_present = {name: count > 0 for name, count in readiness_mode_counts.items()}
|
||||
retained_android_native_complete = {
|
||||
name: count >= 3 for name, count in retained_android_native_counts.items()
|
||||
@@ -112,7 +146,8 @@ def main() -> int:
|
||||
all(not values for values in missing.values())
|
||||
and all(not values for values in unexpected.values())
|
||||
and all(debt_complete.values())
|
||||
and all(blocked_complete.values())
|
||||
and all(status_gate_complete.values())
|
||||
and all(readiness_alignment.values())
|
||||
and all(readiness_mode_present.values())
|
||||
and all(retained_android_native_complete.values())
|
||||
and all(retained_platform_cmake_complete.values())
|
||||
@@ -130,7 +165,9 @@ def main() -> int:
|
||||
"missing": missing,
|
||||
"unexpected": unexpected,
|
||||
"debtComplete": debt_complete,
|
||||
"blockedComplete": blocked_complete,
|
||||
"statusModes": status_modes,
|
||||
"statusModePresent": status_mode_present,
|
||||
"readinessAlignment": readiness_alignment,
|
||||
"readinessModePresent": readiness_mode_present,
|
||||
"retainedAndroidNativeComplete": retained_android_native_complete,
|
||||
"retainedPlatformCmakeComplete": retained_platform_cmake_complete,
|
||||
|
||||
188
scripts/dev/check_renderer_api_contract.py
Normal file
188
scripts/dev/check_renderer_api_contract.py
Normal file
@@ -0,0 +1,188 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate renderer API contract purity for key rendering components."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
INCLUDE_RE = re.compile(r"""^\s*#\s*include\s+(\"([^\"]+)\"|<([^>]+)>)""")
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
CHECKS = {
|
||||
"renderer_api": {
|
||||
"roots": [REPO_ROOT / "src" / "renderer_api"],
|
||||
"allowed_include_prefixes": ("foundation/", "renderer_api/"),
|
||||
"forbidden_include_tokens": (
|
||||
"renderer_gl/",
|
||||
"platform/",
|
||||
"platform_api/",
|
||||
"platform_",
|
||||
"opengl",
|
||||
"glad",
|
||||
"vulkan",
|
||||
"d3d",
|
||||
"directx",
|
||||
"metal",
|
||||
"appkit",
|
||||
"cocoa",
|
||||
"objc/",
|
||||
"windows.h",
|
||||
"x11/",
|
||||
"wayland-",
|
||||
"android/",
|
||||
),
|
||||
"forbidden_body_tokens": (
|
||||
"OpenGl",
|
||||
"OpenGL",
|
||||
"opengl_",
|
||||
"GL_",
|
||||
"Vulkan",
|
||||
"Vk",
|
||||
"MTL",
|
||||
"D3D",
|
||||
"vulkan",
|
||||
"metal",
|
||||
"renderer_gl",
|
||||
"pp_platform_",
|
||||
),
|
||||
},
|
||||
"paint_renderer": {
|
||||
"roots": [REPO_ROOT / "src" / "paint_renderer"],
|
||||
"allowed_include_prefixes": (
|
||||
"assets/",
|
||||
"document/",
|
||||
"foundation/",
|
||||
"paint/",
|
||||
"paint_renderer/",
|
||||
"renderer_api/",
|
||||
),
|
||||
"forbidden_include_tokens": (
|
||||
"renderer_gl/",
|
||||
"platform/",
|
||||
"platform_api/",
|
||||
"platform_",
|
||||
"opengl",
|
||||
"glad",
|
||||
"vulkan",
|
||||
"d3d",
|
||||
"directx",
|
||||
"metal",
|
||||
"appkit",
|
||||
"cocoa",
|
||||
"objc/",
|
||||
"windows.h",
|
||||
"x11/",
|
||||
"wayland-",
|
||||
"android/",
|
||||
),
|
||||
"forbidden_body_tokens": (
|
||||
"OpenGl",
|
||||
"OpenGL",
|
||||
"opengl_",
|
||||
"GL_",
|
||||
"Vulkan",
|
||||
"Vk",
|
||||
"MTL",
|
||||
"D3D",
|
||||
"vulkan",
|
||||
"metal",
|
||||
"renderer_gl",
|
||||
"pp_platform_",
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
ALLOWED_EXTERNAL_PREFIXES = ("stb/",)
|
||||
|
||||
|
||||
def is_forbidden_include(allowlist: tuple[str, ...], forbidden_tokens: tuple[str, ...], include: str) -> tuple[bool, str | None]:
|
||||
include_lower = include.lower()
|
||||
if any(token in include_lower for token in forbidden_tokens):
|
||||
token = next(token for token in forbidden_tokens if token in include_lower)
|
||||
return True, token
|
||||
|
||||
if "/" in include and include_lower.startswith(ALLOWED_EXTERNAL_PREFIXES):
|
||||
return False, None
|
||||
|
||||
if "/" in include and not any(include_lower.startswith(prefix) for prefix in allowlist):
|
||||
return True, "cross-component-include"
|
||||
return False, None
|
||||
|
||||
|
||||
def scan_component(name: str, config: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
violations: list[dict[str, Any]] = []
|
||||
for root in config["roots"]:
|
||||
for path in root.rglob("*"):
|
||||
if not path.is_file():
|
||||
continue
|
||||
if path.suffix.lower() not in {".cpp", ".cc", ".c", ".h", ".hpp", ".hh"}:
|
||||
continue
|
||||
|
||||
text = path.read_text(encoding="utf-8").splitlines()
|
||||
for line_no, line in enumerate(text, start=1):
|
||||
include_match = INCLUDE_RE.match(line)
|
||||
if include_match:
|
||||
include = (include_match.group(2) or include_match.group(3) or "").strip()
|
||||
forbidden, reason = is_forbidden_include(
|
||||
config["allowed_include_prefixes"],
|
||||
config["forbidden_include_tokens"],
|
||||
include,
|
||||
)
|
||||
if forbidden:
|
||||
violations.append(
|
||||
{
|
||||
"component": name,
|
||||
"file": str(path.relative_to(REPO_ROOT)),
|
||||
"line": line_no,
|
||||
"kind": "forbidden-include",
|
||||
"include": include,
|
||||
"detail": reason,
|
||||
"text": line.strip(),
|
||||
}
|
||||
)
|
||||
|
||||
joined = "\n".join(text)
|
||||
for token in config["forbidden_body_tokens"]:
|
||||
if token in joined:
|
||||
violations.append(
|
||||
{
|
||||
"component": name,
|
||||
"file": str(path.relative_to(REPO_ROOT)),
|
||||
"line": 0,
|
||||
"kind": "forbidden-body-token",
|
||||
"include": token,
|
||||
"detail": "backend- or platform-specific symbol in renderer contract path",
|
||||
"text": "",
|
||||
}
|
||||
)
|
||||
|
||||
return violations
|
||||
|
||||
|
||||
def main() -> int:
|
||||
violations: list[dict[str, Any]] = []
|
||||
for component, config in CHECKS.items():
|
||||
violations.extend(scan_component(component, config))
|
||||
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
"ok": len(violations) == 0,
|
||||
"summary": {
|
||||
"componentCount": len(CHECKS),
|
||||
"violationCount": len(violations),
|
||||
},
|
||||
"violations": violations,
|
||||
},
|
||||
separators=(",", ":"),
|
||||
)
|
||||
)
|
||||
return 0 if not violations else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
119
scripts/dev/check_renderer_conformance_matrix.py
Normal file
119
scripts/dev/check_renderer_conformance_matrix.py
Normal file
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate that renderer conformance fixtures are registered and labeled consistently."""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
TESTS_CMAKE = REPO_ROOT / "tests" / "CMakeLists.txt"
|
||||
|
||||
REQUIRED_TEST_LABELS = {
|
||||
"pp_renderer_api_tests": {"renderer-conformance", "renderer"},
|
||||
}
|
||||
|
||||
OPTIONAL_BACKEND_TEST_LABELS = {
|
||||
"pp_renderer_gl_capabilities_tests": {"renderer-conformance", "renderer"},
|
||||
"pp_renderer_gl_command_plan_tests": {"renderer-conformance", "renderer"},
|
||||
"pp_renderer_gl_gpu_readback_tests": {"renderer-conformance", "renderer", "gpu"},
|
||||
}
|
||||
|
||||
def parse_labels() -> dict[str, set[str]]:
|
||||
labels_by_test: dict[str, set[str]] = {}
|
||||
text = TESTS_CMAKE.read_text(encoding="utf-8").splitlines()
|
||||
i = 0
|
||||
while i < len(text):
|
||||
line = text[i].strip()
|
||||
if not line.startswith("set_tests_properties("):
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if "set_tests_properties(" not in line or "PROPERTIES" not in line:
|
||||
i += 1
|
||||
continue
|
||||
after_paren = line.split("set_tests_properties(", 1)[1]
|
||||
test_name = after_paren.split()[0].strip()
|
||||
test_name = test_name.strip()
|
||||
|
||||
label_value: str | None = None
|
||||
j = i
|
||||
while j < len(text):
|
||||
search = text[j].strip()
|
||||
if search.startswith("LABELS"):
|
||||
colon = search.find("\"")
|
||||
if colon != -1:
|
||||
value = search[colon:].strip()
|
||||
if value.startswith("\"") and value.endswith("\""):
|
||||
label_value = value[1:-1]
|
||||
break
|
||||
# Fallback for multiline values: LABELS "a;b"; split on quotes in line.
|
||||
quotes = re.findall(r'"([^"]+)"', search)
|
||||
if quotes:
|
||||
label_value = quotes[0]
|
||||
break
|
||||
if search == ")" or (search.startswith(")") and "LABELS" not in search):
|
||||
break
|
||||
j += 1
|
||||
|
||||
if label_value is not None:
|
||||
labels_by_test[test_name] = {label.strip() for label in label_value.split(";") if label.strip()}
|
||||
|
||||
i = j + 1
|
||||
|
||||
return labels_by_test
|
||||
|
||||
|
||||
def validate() -> tuple[bool, list[dict[str, Any]]]:
|
||||
labels_by_test = parse_labels()
|
||||
test_names = set(labels_by_test)
|
||||
violations: list[dict[str, Any]] = []
|
||||
|
||||
for test_name, required_labels in REQUIRED_TEST_LABELS.items():
|
||||
actual = labels_by_test.get(test_name)
|
||||
if actual is None:
|
||||
violations.append({"test": test_name, "kind": "missing-test", "detail": "required conformance test not registered"})
|
||||
continue
|
||||
|
||||
missing = sorted(required_labels - actual)
|
||||
if missing:
|
||||
violations.append(
|
||||
{
|
||||
"test": test_name,
|
||||
"kind": "missing-label",
|
||||
"detail": f"required labels missing: {', '.join(missing)}",
|
||||
}
|
||||
)
|
||||
|
||||
for test_name, required_labels in OPTIONAL_BACKEND_TEST_LABELS.items():
|
||||
if test_name not in test_names:
|
||||
continue
|
||||
actual = labels_by_test[test_name]
|
||||
missing = sorted(required_labels - actual)
|
||||
if missing:
|
||||
violations.append(
|
||||
{
|
||||
"test": test_name,
|
||||
"kind": "missing-label",
|
||||
"detail": f"required labels missing: {', '.join(missing)}",
|
||||
}
|
||||
)
|
||||
|
||||
return (len(violations) == 0), violations
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ok, violations = validate()
|
||||
payload = {
|
||||
"ok": ok,
|
||||
"summary": {
|
||||
"requiredTestCount": len(REQUIRED_TEST_LABELS),
|
||||
"violationCount": len(violations),
|
||||
},
|
||||
"violations": violations,
|
||||
}
|
||||
print(payload)
|
||||
return 0 if ok else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user