Merge pull request 'feat: added verify scripts' (#3) from furqan into dev
Reviewed-on: https://gitea.maskantech.in/gitea_admin/pdf/pulls/3
This commit is contained in:
@@ -93,6 +93,11 @@ ctest --preset windows-debug
|
||||
The first configure compiles the vcpkg dependencies (freetype, harfbuzz,
|
||||
spdlog, gtest) — slow once, cached after.
|
||||
|
||||
> **Verifying everything at once:** use `scripts/test_phase0.{ps1,sh}` to run
|
||||
> the R2 boundary check, engine, gateway, and WASM smoke test as a single
|
||||
> command and get one pass/fail summary. See
|
||||
> ["Verifying your setup"](#verifying-your-setup--scriptstest_phase0ps1sh) below.
|
||||
|
||||
### Building with PDFium
|
||||
|
||||
PDFium is built separately from source (Task 2):
|
||||
@@ -190,6 +195,76 @@ broken `ninja` for the engine build. Two fixes:
|
||||
`PATH`. `third_party/pdfium/build_pdfium.ps1` already prepends it
|
||||
per-run, so the PDFium build still works.
|
||||
|
||||
## Verifying your setup — `scripts/test_phase0.{ps1,sh}`
|
||||
|
||||
After bootstrap, this aggregator runs every Phase 0 check in sequence and
|
||||
prints one pass/fail summary. It is the local mirror of
|
||||
[.github/workflows/ci.yml](../.github/workflows/ci.yml) — new teammates should
|
||||
use it as the "did I set everything up right?" one-liner.
|
||||
|
||||
Pieces it runs, in order:
|
||||
|
||||
1. **Rule R2 boundary** — `scripts/check_pdfium_boundary.*`
|
||||
2. **Engine** — `cmake --preset … --build --preset … ctest --preset …`
|
||||
3. **Gateway** — `pip install -e .[dev]` + ruff (lint + format check) + pytest
|
||||
4. **WASM hello-world** — `cmake --preset wasm` + `node wasm/hello.test.mjs`
|
||||
|
||||
A piece **skips** (not fails) when its toolchain is absent — no Emscripten on
|
||||
`PATH` skips WASM, no `python` skips the gateway, etc. Each piece is
|
||||
independent: one failure does not abort later pieces. Exit code is non-zero
|
||||
only if a piece genuinely **failed**, so you can pipe it into CI.
|
||||
|
||||
### Windows
|
||||
|
||||
`vcvars64.bat` must be active in the shell (or use *Developer PowerShell for
|
||||
VS*) and `VCPKG_ROOT` must be set:
|
||||
|
||||
```powershell
|
||||
./scripts/test_phase0.ps1 -Preset win-local # debug, no PDFium - fastest
|
||||
./scripts/test_phase0.ps1 -Preset win-local-pdfium # release + PDFium - full
|
||||
```
|
||||
|
||||
Both presets live in your local `CMakeUserPresets.json` (template in the
|
||||
"Windows + PDFium" section above), with `binaryDir` pointed outside OneDrive on
|
||||
a space-free path.
|
||||
|
||||
Other useful flags: `-BinaryDir <path>` (override the preset's binaryDir),
|
||||
`-SkipEngine` / `-SkipGateway` / `-SkipWasm` (skip a piece explicitly).
|
||||
|
||||
### Linux / macOS
|
||||
|
||||
```sh
|
||||
./scripts/test_phase0.sh # auto-picks linux-debug or macos-debug
|
||||
./scripts/test_phase0.sh linux-asan # different preset
|
||||
SKIP_WASM=1 ./scripts/test_phase0.sh # if Emscripten not installed
|
||||
PHASE0_BINARY_DIR=/tmp/build ./scripts/test_phase0.sh # override binaryDir
|
||||
```
|
||||
|
||||
Compatible with bash 3.2 (macOS default), so no `brew install bash` needed.
|
||||
|
||||
### Gotcha: stale build dir after a triplet switch
|
||||
|
||||
If a build dir was previously configured against the dynamic
|
||||
(`x64-windows`) vcpkg triplet and you re-run against the static
|
||||
(`x64-windows-static`) one — which is what the `windows-base` preset now pins
|
||||
for the static-CRT story — vcpkg correctly purges the old libs, but ninja's
|
||||
build graph still references them. You will see:
|
||||
|
||||
```
|
||||
ninja: error: 'vcpkg_installed/x64-windows/debug/lib/harfbuzz.lib' ... missing
|
||||
```
|
||||
|
||||
Fix by regenerating from scratch:
|
||||
|
||||
```powershell
|
||||
cmake --preset win-local --fresh # or whichever preset
|
||||
./scripts/test_phase0.ps1 -Preset win-local
|
||||
```
|
||||
|
||||
`--fresh` is the cleanest option (CMake ≥ 3.24); it preserves the build dir
|
||||
but invalidates the cache so all targets are re-resolved. Alternatively, delete
|
||||
the build dir and reconfigure.
|
||||
|
||||
## Dependency pinning
|
||||
|
||||
The blueprint rule is *"pin all dependency versions on Day 1, never track
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
#requires -Version 5.1
|
||||
# Phase 0 aggregator - runs every check in .github/workflows/ci.yml locally and
|
||||
# reports a single pass/fail summary. Use this as the "did I set everything up
|
||||
# right?" one-liner for new teammates.
|
||||
#
|
||||
# Pieces run, in order:
|
||||
# 1. Rule R2 boundary (scripts/check_pdfium_boundary.ps1)
|
||||
# 2. Engine (cmake configure + build + ctest)
|
||||
# 3. Gateway (pip install -e [dev] + ruff + pytest, in gateway/)
|
||||
# 4. WASM hello-world (cmake configure + build + node hello.test.mjs)
|
||||
#
|
||||
# Skips (not failures) are reported when a toolchain isn't present - e.g. no
|
||||
# Emscripten on PATH skips WASM. Each piece runs independently; a failure in
|
||||
# one does not abort later pieces.
|
||||
#
|
||||
# Examples:
|
||||
# pwsh scripts/test_phase0.ps1
|
||||
# pwsh scripts/test_phase0.ps1 -Preset win-local-pdfium
|
||||
# pwsh scripts/test_phase0.ps1 -BinaryDir C:/Users/me/pdfeng-build/windows-debug
|
||||
# pwsh scripts/test_phase0.ps1 -SkipWasm
|
||||
#
|
||||
# OneDrive note: on this repo's spaced/OneDrive-synced path the default in-tree
|
||||
# binaryDir breaks the engine build (see docs/phase0.md "OneDrive warning").
|
||||
# Pass -BinaryDir to redirect, or use a CMakeUserPresets preset that already
|
||||
# does so (e.g. win-local-pdfium).
|
||||
param(
|
||||
[string]$Preset = '',
|
||||
[string]$BinaryDir = '',
|
||||
[switch]$SkipEngine,
|
||||
[switch]$SkipGateway,
|
||||
[switch]$SkipWasm
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$RepoRoot = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
||||
Set-Location $RepoRoot
|
||||
|
||||
if (-not $Preset) {
|
||||
if ($env:OS -eq 'Windows_NT') { $Preset = 'windows-debug' }
|
||||
elseif ($IsMacOS) { $Preset = 'macos-debug' }
|
||||
else { $Preset = 'linux-debug' }
|
||||
}
|
||||
|
||||
$script:results = [ordered]@{}
|
||||
|
||||
function Invoke-Step {
|
||||
param([string]$Name, [scriptblock]$Body)
|
||||
Write-Host ''
|
||||
Write-Host ">> [$Name]"
|
||||
$global:LASTEXITCODE = 0
|
||||
try {
|
||||
& $Body
|
||||
$rc = $LASTEXITCODE
|
||||
if ($rc -and $rc -ne 0) {
|
||||
$script:results[$Name] = 'FAIL'
|
||||
Write-Host " [$Name] FAILED (exit $rc)"
|
||||
} else {
|
||||
$script:results[$Name] = 'PASS'
|
||||
Write-Host " [$Name] OK"
|
||||
}
|
||||
} catch {
|
||||
$script:results[$Name] = 'FAIL'
|
||||
Write-Host " [$Name] FAILED: $_"
|
||||
}
|
||||
}
|
||||
|
||||
function Skip-Step {
|
||||
param([string]$Name, [string]$Reason)
|
||||
Write-Host ''
|
||||
Write-Host ">> [$Name] SKIPPED: $Reason"
|
||||
$script:results[$Name] = 'SKIP'
|
||||
}
|
||||
|
||||
Write-Host "Phase 0 aggregator - preset='$Preset'$(if ($BinaryDir) { " binaryDir='$BinaryDir'" })"
|
||||
|
||||
# --- 1. Rule R2 boundary -----------------------------------------------------
|
||||
Invoke-Step 'R2 boundary' {
|
||||
& (Join-Path $RepoRoot 'scripts/check_pdfium_boundary.ps1')
|
||||
}
|
||||
|
||||
# --- 2. Engine ---------------------------------------------------------------
|
||||
if ($SkipEngine) {
|
||||
Skip-Step 'engine' 'requested via -SkipEngine'
|
||||
} elseif (-not $env:VCPKG_ROOT) {
|
||||
Skip-Step 'engine' 'VCPKG_ROOT not set - run scripts/bootstrap.ps1 first (and re-open the shell, or set $env:VCPKG_ROOT)'
|
||||
} else {
|
||||
Invoke-Step 'engine configure' {
|
||||
if ($BinaryDir) { cmake --preset $Preset -B $BinaryDir } else { cmake --preset $Preset }
|
||||
}
|
||||
if ($script:results['engine configure'] -eq 'PASS') {
|
||||
Invoke-Step 'engine build' {
|
||||
if ($BinaryDir) { cmake --build $BinaryDir } else { cmake --build --preset $Preset }
|
||||
}
|
||||
if ($script:results['engine build'] -eq 'PASS') {
|
||||
Invoke-Step 'engine test' {
|
||||
if ($BinaryDir) { ctest --test-dir $BinaryDir --output-on-failure } else { ctest --preset $Preset }
|
||||
}
|
||||
} else {
|
||||
Skip-Step 'engine test' 'build failed'
|
||||
}
|
||||
} else {
|
||||
Skip-Step 'engine build' 'configure failed'
|
||||
Skip-Step 'engine test' 'configure failed'
|
||||
}
|
||||
}
|
||||
|
||||
# --- 3. Gateway --------------------------------------------------------------
|
||||
if ($SkipGateway) {
|
||||
Skip-Step 'gateway' 'requested via -SkipGateway'
|
||||
} elseif (-not (Get-Command python -ErrorAction SilentlyContinue)) {
|
||||
Skip-Step 'gateway' 'python not found on PATH'
|
||||
} else {
|
||||
Push-Location (Join-Path $RepoRoot 'gateway')
|
||||
try {
|
||||
Invoke-Step 'gateway install' { python -m pip install --quiet -e ".[dev]" }
|
||||
if ($script:results['gateway install'] -eq 'PASS') {
|
||||
Invoke-Step 'gateway lint' { python -m ruff check . }
|
||||
Invoke-Step 'gateway format' { python -m ruff format --check . }
|
||||
Invoke-Step 'gateway pytest' { python -m pytest }
|
||||
}
|
||||
} finally { Pop-Location }
|
||||
}
|
||||
|
||||
# --- 4. WASM hello-world -----------------------------------------------------
|
||||
if ($SkipWasm) {
|
||||
Skip-Step 'wasm' 'requested via -SkipWasm'
|
||||
} elseif (-not (Get-Command emcc -ErrorAction SilentlyContinue)) {
|
||||
Skip-Step 'wasm' 'emcc not on PATH - activate emsdk (emsdk_env.ps1) first'
|
||||
} elseif (-not (Get-Command node -ErrorAction SilentlyContinue)) {
|
||||
Skip-Step 'wasm' 'node not on PATH'
|
||||
} else {
|
||||
Invoke-Step 'wasm configure' { cmake --preset wasm }
|
||||
if ($script:results['wasm configure'] -eq 'PASS') {
|
||||
Invoke-Step 'wasm build' { cmake --build --preset wasm }
|
||||
if ($script:results['wasm build'] -eq 'PASS') {
|
||||
Invoke-Step 'wasm test' { node wasm/hello.test.mjs }
|
||||
} else {
|
||||
Skip-Step 'wasm test' 'build failed'
|
||||
}
|
||||
} else {
|
||||
Skip-Step 'wasm build' 'configure failed'
|
||||
Skip-Step 'wasm test' 'configure failed'
|
||||
}
|
||||
}
|
||||
|
||||
# --- Summary ----------------------------------------------------------------
|
||||
Write-Host ''
|
||||
Write-Host '================ Phase 0 summary ================'
|
||||
$pad = 0
|
||||
foreach ($k in $script:results.Keys) { if ($k.Length -gt $pad) { $pad = $k.Length } }
|
||||
$fmt = ' {0,-' + $pad + '} {1}'
|
||||
$anyFail = $false
|
||||
foreach ($name in $script:results.Keys) {
|
||||
$status = $script:results[$name]
|
||||
Write-Host ($fmt -f $name, $status)
|
||||
if ($status -eq 'FAIL') { $anyFail = $true }
|
||||
}
|
||||
Write-Host '================================================='
|
||||
|
||||
if ($anyFail) {
|
||||
Write-Host 'Phase 0: FAIL'
|
||||
exit 1
|
||||
}
|
||||
Write-Host 'Phase 0: PASS'
|
||||
exit 0
|
||||
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env bash
|
||||
# Phase 0 aggregator — runs every check in .github/workflows/ci.yml locally and
|
||||
# reports a single pass/fail summary. Use this as the "did I set everything up
|
||||
# right?" one-liner for new teammates.
|
||||
#
|
||||
# Pieces run, in order:
|
||||
# 1. Rule R2 boundary (scripts/check_pdfium_boundary.sh)
|
||||
# 2. Engine (cmake configure + build + ctest)
|
||||
# 3. Gateway (pip install -e [dev] + ruff + pytest, in gateway/)
|
||||
# 4. WASM hello-world (cmake configure + build + node hello.test.mjs)
|
||||
#
|
||||
# Skips (not failures) are reported when a toolchain isn't present — e.g. no
|
||||
# Emscripten on PATH skips WASM. Each piece runs independently; a failure in
|
||||
# one does not abort later pieces.
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/test_phase0.sh # auto-pick preset by OS
|
||||
# ./scripts/test_phase0.sh linux-asan # override preset
|
||||
# PHASE0_BINARY_DIR=/tmp/build ./scripts/test_phase0.sh
|
||||
# SKIP_WASM=1 ./scripts/test_phase0.sh
|
||||
#
|
||||
# Compatible with bash 3.2 (macOS default) — uses parallel indexed arrays
|
||||
# instead of associative arrays.
|
||||
set -uo pipefail # NOT -e: we want to collect failures, not abort on first
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "${REPO_ROOT}"
|
||||
|
||||
PRESET="${1:-}"
|
||||
if [[ -z "${PRESET}" ]]; then
|
||||
case "$(uname -s)" in
|
||||
Darwin*) PRESET=macos-debug ;;
|
||||
*) PRESET=linux-debug ;;
|
||||
esac
|
||||
fi
|
||||
BINARY_DIR="${PHASE0_BINARY_DIR:-}"
|
||||
|
||||
STEPS=()
|
||||
STATUSES=()
|
||||
LAST_STATUS=PASS
|
||||
|
||||
record() {
|
||||
STEPS+=("$1")
|
||||
STATUSES+=("$2")
|
||||
LAST_STATUS="$2"
|
||||
}
|
||||
|
||||
run_step() {
|
||||
local name="$1"; shift
|
||||
echo
|
||||
echo ">> [${name}]"
|
||||
if "$@"; then
|
||||
record "${name}" PASS
|
||||
echo " [${name}] OK"
|
||||
else
|
||||
local rc=$?
|
||||
record "${name}" FAIL
|
||||
echo " [${name}] FAILED (exit ${rc})"
|
||||
fi
|
||||
}
|
||||
|
||||
skip_step() {
|
||||
local name="$1"
|
||||
local reason="$2"
|
||||
echo
|
||||
echo ">> [${name}] SKIPPED: ${reason}"
|
||||
record "${name}" SKIP
|
||||
}
|
||||
|
||||
echo "Phase 0 aggregator — preset='${PRESET}'${BINARY_DIR:+ binaryDir='${BINARY_DIR}'}"
|
||||
|
||||
# --- 1. Rule R2 boundary -----------------------------------------------------
|
||||
run_step 'R2 boundary' bash "${REPO_ROOT}/scripts/check_pdfium_boundary.sh"
|
||||
|
||||
# --- 2. Engine ---------------------------------------------------------------
|
||||
engine_configure() {
|
||||
if [[ -n "${BINARY_DIR}" ]]; then cmake --preset "${PRESET}" -B "${BINARY_DIR}";
|
||||
else cmake --preset "${PRESET}"; fi
|
||||
}
|
||||
engine_build() {
|
||||
if [[ -n "${BINARY_DIR}" ]]; then cmake --build "${BINARY_DIR}";
|
||||
else cmake --build --preset "${PRESET}"; fi
|
||||
}
|
||||
engine_test() {
|
||||
if [[ -n "${BINARY_DIR}" ]]; then ctest --test-dir "${BINARY_DIR}" --output-on-failure;
|
||||
else ctest --preset "${PRESET}"; fi
|
||||
}
|
||||
|
||||
if [[ "${SKIP_ENGINE:-0}" == "1" ]]; then
|
||||
skip_step 'engine' 'requested via SKIP_ENGINE=1'
|
||||
elif [[ -z "${VCPKG_ROOT:-}" ]]; then
|
||||
skip_step 'engine' 'VCPKG_ROOT not set — run scripts/bootstrap.sh first (and re-source your shell rc)'
|
||||
else
|
||||
run_step 'engine configure' engine_configure
|
||||
if [[ "${LAST_STATUS}" == PASS ]]; then
|
||||
run_step 'engine build' engine_build
|
||||
if [[ "${LAST_STATUS}" == PASS ]]; then
|
||||
run_step 'engine test' engine_test
|
||||
else
|
||||
skip_step 'engine test' 'build failed'
|
||||
fi
|
||||
else
|
||||
skip_step 'engine build' 'configure failed'
|
||||
skip_step 'engine test' 'configure failed'
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- 3. Gateway --------------------------------------------------------------
|
||||
PY=""
|
||||
if command -v python3 >/dev/null 2>&1; then PY="$(command -v python3)";
|
||||
elif command -v python >/dev/null 2>&1; then PY="$(command -v python)"; fi
|
||||
|
||||
if [[ "${SKIP_GATEWAY:-0}" == "1" ]]; then
|
||||
skip_step 'gateway' 'requested via SKIP_GATEWAY=1'
|
||||
elif [[ -z "${PY}" ]]; then
|
||||
skip_step 'gateway' 'python/python3 not on PATH'
|
||||
else
|
||||
pushd gateway >/dev/null
|
||||
run_step 'gateway install' "${PY}" -m pip install --quiet -e ".[dev]"
|
||||
if [[ "${LAST_STATUS}" == PASS ]]; then
|
||||
run_step 'gateway lint' "${PY}" -m ruff check .
|
||||
run_step 'gateway format' "${PY}" -m ruff format --check .
|
||||
run_step 'gateway pytest' "${PY}" -m pytest
|
||||
fi
|
||||
popd >/dev/null
|
||||
fi
|
||||
|
||||
# --- 4. WASM hello-world -----------------------------------------------------
|
||||
if [[ "${SKIP_WASM:-0}" == "1" ]]; then
|
||||
skip_step 'wasm' 'requested via SKIP_WASM=1'
|
||||
elif ! command -v emcc >/dev/null 2>&1; then
|
||||
skip_step 'wasm' 'emcc not on PATH — source emsdk_env.sh first'
|
||||
elif ! command -v node >/dev/null 2>&1; then
|
||||
skip_step 'wasm' 'node not on PATH'
|
||||
else
|
||||
run_step 'wasm configure' cmake --preset wasm
|
||||
if [[ "${LAST_STATUS}" == PASS ]]; then
|
||||
run_step 'wasm build' cmake --build --preset wasm
|
||||
if [[ "${LAST_STATUS}" == PASS ]]; then
|
||||
run_step 'wasm test' node wasm/hello.test.mjs
|
||||
else
|
||||
skip_step 'wasm test' 'build failed'
|
||||
fi
|
||||
else
|
||||
skip_step 'wasm build' 'configure failed'
|
||||
skip_step 'wasm test' 'configure failed'
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Summary ----------------------------------------------------------------
|
||||
echo
|
||||
echo '================ Phase 0 summary ================'
|
||||
pad=0
|
||||
for s in "${STEPS[@]}"; do
|
||||
if (( ${#s} > pad )); then pad=${#s}; fi
|
||||
done
|
||||
any_fail=0
|
||||
for i in "${!STEPS[@]}"; do
|
||||
printf " %-${pad}s %s\n" "${STEPS[$i]}" "${STATUSES[$i]}"
|
||||
if [[ "${STATUSES[$i]}" == FAIL ]]; then any_fail=1; fi
|
||||
done
|
||||
echo '================================================='
|
||||
|
||||
if [[ "${any_fail}" -ne 0 ]]; then
|
||||
echo 'Phase 0: FAIL'
|
||||
exit 1
|
||||
fi
|
||||
echo 'Phase 0: PASS'
|
||||
exit 0
|
||||
Reference in New Issue
Block a user