diff --git a/.github/actions/base/action.yml b/.github/actions/base/action.yml index a94fcf94f..9c42892fe 100644 --- a/.github/actions/base/action.yml +++ b/.github/actions/base/action.yml @@ -41,6 +41,16 @@ runs: shell: bash run: cp cabal.project.ci cabal.project + - name: Windows quirks - Configure environment for libclang + shell: bash + if: ${{ startsWith(inputs.runner, 'windows') }} + run: | + # Set library path for linker to find import libraries (.lib files) + echo "LIBRARY_PATH=$LLVM_PATH/lib" >> "$GITHUB_ENV" + + echo "$LLVM_PATH/lib" >> "$GITHUB_PATH" + echo "$LLVM_PATH/bin" >> "$GITHUB_PATH" + - name: Dry build (for cache key) shell: bash run: cabal build all --dry-run @@ -85,14 +95,6 @@ runs: if: runner.os == 'Linux' uses: ./.github/actions/build-manual-ubuntu - - name: Windows quirks - Manual requires Clang version coming with GHC - shell: bash - if: ${{ startsWith(inputs.runner, 'windows') }} - run: | - echo '### ls "C:\tools\ghc-${{ inputs.ghc }}\mingw\bin"' - ls "C:\tools\ghc-${{ inputs.ghc }}\mingw\bin" - echo "C:\tools\ghc-${{ inputs.ghc }}\mingw\bin" >> "$GITHUB_PATH" - - name: Build manual (Windows) if: runner.os == 'Windows' uses: ./.github/actions/build-manual-windows diff --git a/.github/actions/setup-llvm/action.yml b/.github/actions/setup-llvm/action.yml index b7126cd2b..c4bc08b7d 100644 --- a/.github/actions/setup-llvm/action.yml +++ b/.github/actions/setup-llvm/action.yml @@ -48,4 +48,6 @@ runs: echo '### ls $LLVM_PATH' ls "$LLVM_PATH" echo '### ls $LLVM_PATH/bin' - ls "$LLVM_PATH/bin" \ No newline at end of file + ls "$LLVM_PATH/bin" + echo '### ls $LLVM_PATH/lib' + ls "$LLVM_PATH/lib" || echo "lib directory not found or empty" \ No newline at end of file diff --git a/.github/workflows/compile-fixtures.yml b/.github/workflows/compile-and-generate-haddocks-fixtures.yml similarity index 77% rename from .github/workflows/compile-fixtures.yml rename to .github/workflows/compile-and-generate-haddocks-fixtures.yml index 2bd214668..91fd4815f 100644 --- a/.github/workflows/compile-fixtures.yml +++ b/.github/workflows/compile-and-generate-haddocks-fixtures.yml @@ -1,4 +1,4 @@ -name: Compile Fixtures +name: Compile and Generate Haddocks for Fixtures on: push: @@ -23,8 +23,8 @@ defaults: shell: bash jobs: - compile-fixtures: - name: Compile Fixtures (${{ matrix.runner }}, GHC ${{ matrix.ghc-version }}, Cabal ${{ matrix.cabal-version }}, LLVM ${{matrix.llvm-version }}) + compile-and-generate-haddocks-fixtures: + name: Compile & Generate Haddocks for Fixtures (${{ matrix.runner }}, GHC ${{ matrix.ghc-version }}, Cabal ${{ matrix.cabal-version }}, LLVM ${{matrix.llvm-version }}) runs-on: ${{ matrix.runner }} timeout-minutes: 30 @@ -33,6 +33,10 @@ jobs: # We run the workflow only once, but using a matrix makes it easy to # change these settings in the future. As an added benefit, we can refer # to the matrix entries in the job name. + # + # NOTE: This workflow both compiles fixtures AND generates Haddock documentation. + # Since Haddock compiles files internally, this single pass validates both + # compilation and documentation in one efficient step. matrix: runner: ['ubuntu-latest'] ghc-version: ['9.4'] @@ -57,7 +61,7 @@ jobs: - name: ๐Ÿ› ๏ธ Configure run: | - cabal configure --disable-test --disable-benchmark --disable-documentation --ghc-options="-Werror" + cp cabal.project.base.ci cabal.project.local cat "cabal.project.local" - name: ๐Ÿ’พ Generate Cabal plan @@ -89,7 +93,7 @@ jobs: - name: ๐Ÿ—๏ธ Build hs-bindgen run: cabal build hs-bindgen-runtime c-expr-runtime - - name: ๐Ÿงช Compile fixtures + - name: ๐Ÿงช Compile and generate Haddocks for fixtures run: | - chmod +x scripts/ci/compile-fixtures.sh - scripts/ci/compile-fixtures.sh + chmod +x scripts/ci/compile-and-generate-haddocks-fixtures.sh + scripts/ci/compile-and-generate-haddocks-fixtures.sh diff --git a/.github/workflows/comprehensive-ci.yml b/.github/workflows/comprehensive-ci.yml new file mode 100644 index 000000000..f9a1b3c20 --- /dev/null +++ b/.github/workflows/comprehensive-ci.yml @@ -0,0 +1,190 @@ +name: Comprehensive CI "Release" flow + +# Manual trigger only - for pre-release validation and comprehensive testing +# on: +# workflow_dispatch: + +on: + push: + branches: + - main + pull_request: + branches: + - main + merge_group: + branches: + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + # Test all LLVM versions (14-21) on recommended configuration + test-all-llvm-and-ghc-versions: + name: Test All LLVM and GHC Versions (${{ matrix.runner }}, GHC ${{ matrix.ghc-version }}, LLVM ${{ matrix.llvm-version }}) + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + # runner: [windows-latest, ubuntu-latest, macos-latest] + runner: [windows-latest] + ghc-version: ['9.2.8', '9.4.8', '9.6.7', '9.8.4', '9.10.3', '9.12.2'] + llvm-version: ['14', '16', '18', '20', '21'] + exclude: + # LLVM 21 not available on macOS ARM64 + - runner: macos-latest + llvm-version: '21' + + steps: + - name: Set git to use LF + run: | + git config --global core.autocrlf false + git config --global core.eol lf + + - name: Checkout + uses: actions/checkout@v4 + + - name: Build and test `hs-bindgen` and manual + uses: ./.github/actions/base + with: + runner: ${{ matrix.runner }} + ghc: ${{ matrix.ghc-version }} + llvm: ${{ matrix.llvm-version }} + + cabal-check: + name: Cabal check (${{ matrix.package }}) + runs-on: ubuntu-latest + strategy: + matrix: + package: + - ansi-diff + - c-expr-runtime + - c-expr-dsl + - hs-bindgen + - hs-bindgen-runtime + - hs-bindgen-test-runtime + cabal-version: ['3.16'] + ghc-version: ['9.4.8'] + steps: + - name: ๐Ÿ“ฅ Checkout repository + uses: actions/checkout@v5 + + - name: ๐Ÿ› ๏ธ Setup Haskell + id: setup-haskell + uses: haskell-actions/setup@v2 + with: + ghc-version: ${{ matrix.ghc-version }} + cabal-version: ${{ matrix.cabal-version }} + + - name: ๐Ÿ’พ Run cabal check + run: | + cd ${{ matrix.package }} + cabal check + + sdist-build: + name: Build from sdist (ubuntu-latest, GHC ${{ matrix.ghc }}, LLVM ${{ matrix.llvm }}) + runs-on: ubuntu-latest + strategy: + matrix: + cabal-version: ['3.16'] + ghc-version: ['9.2.8', '9.4.8', '9.6.7', '9.8.4', '9.10.3', '9.12.2'] + llvm-version: ['14', '16', '18', '20', '21'] + steps: + - name: ๐Ÿ“ฅ Checkout repository + uses: actions/checkout@v5 + + - name: ๐Ÿ› ๏ธ Setup Haskell + id: setup-haskell + uses: haskell-actions/setup@v2 + with: + ghc-version: ${{ matrix.ghc-version }} + cabal-version: ${{ matrix.cabal-version }} + + - name: ๐Ÿ› ๏ธ Setup LLVM/Clang + uses: ./.github/actions/setup-llvm + with: + version: ${{ matrix.llvm-version }} + + - name: ๐Ÿ› ๏ธ cabal.project + run: cp cabal.project.ci cabal.project + + - name: ๐Ÿ’พ Generate all sdists + run: cabal sdist all + + - name: ๐Ÿ’พ Test all sdists can be built + run: | + TEMP_DIR=$(mktemp -d) + + # Extract all sdists + for SDIST_FILE in dist-newstyle/sdist/*.tar.gz; do + tar xzf "$SDIST_FILE" -C "$TEMP_DIR" + done + + cd "$TEMP_DIR" + + # Create cabal.project with all extracted packages + echo "packages:" > cabal.project + for dir in */; do + echo " ${dir%/}" >> cabal.project + done + + cabal build all + + # Build Haddock documentation for all packages + build-haddock: + name: Build Haddock (ubuntu-latest, GHC ${{ matrix.ghc-version }}, LLVM ${{ matrix.llvm-version }}) + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: true + matrix: + cabal-version: ['3.16'] + # Doesn't run GHC 9.2.8 due to a haddock bug + # + ghc-version: [ '9.4.8', '9.6.7', '9.8.4', '9.10.3', '9.12.2'] + llvm-version: ['14', '16', '18', '20', '21'] + steps: + - name: ๐Ÿ“ฅ Checkout repository + uses: actions/checkout@v5 + + - name: ๐Ÿ› ๏ธ Setup Haskell + id: setup-haskell + uses: haskell-actions/setup@v2 + with: + ghc-version: ${{ matrix.ghc-version }} + cabal-version: ${{ matrix.cabal-version }} + + - name: ๐Ÿ› ๏ธ Setup LLVM/Clang + uses: ./.github/actions/setup-llvm + with: + version: ${{ matrix.llvm-version }} + + - name: ๐Ÿ› ๏ธ cabal.project + run: cp cabal.project.ci cabal.project + + - name: ๐Ÿ’พ Generate Cabal plan + run: cabal build all --dry-run + + - name: ๐Ÿ’พ Restore Cabal dependencies + id: cache-cabal-restore + uses: actions/cache/restore@v4 + env: + key: haddock-${{ runner.os }}-ghc-${{ steps.setup-haskell.outputs.ghc-version }}-cabal-${{ steps.setup-haskell.outputs.cabal-version }}-llvm-${{ matrix.llvm-version }} + with: + path: ${{ steps.setup-haskell.outputs.cabal-store }} + key: ${{ env.key }}-plan-${{ hashFiles('./dist-newstyle/cache/plan.json') }} + restore-keys: ${{ env.key }}- + + - name: ๐Ÿ› ๏ธ Build dependencies with Haddock + run: cabal build all --only-dependencies --enable-documentation + + - name: ๐Ÿ’พ Save Cabal dependencies + uses: actions/cache/save@v4 + if: ${{ steps.cache-cabal-restore.outputs.cache-hit != 'true' }} + with: + path: ${{ steps.setup-haskell.outputs.cabal-store }} + key: ${{ steps.cache-cabal-restore.outputs.cache-primary-key }} + + - name: ๐Ÿ—๏ธ Build Haddock for all packages + run: cabal haddock all --haddock-for-hackage diff --git a/hs-bindgen/hs-bindgen.cabal b/hs-bindgen/hs-bindgen.cabal index 31a413fde..a8e1aeb04 100644 --- a/hs-bindgen/hs-bindgen.cabal +++ b/hs-bindgen/hs-bindgen.cabal @@ -428,8 +428,8 @@ test-suite test-th test-suite test-pp type: exitcode-stdio-1.0 - main-is: ../th/test-th.hs - hs-source-dirs: test/pp + main-is: test-th.hs + hs-source-dirs: test/pp test/th include-dirs: examples default-language: GHC2021 other-modules: diff --git a/scripts/ci/compile-and-generate-haddocks-fixtures.sh b/scripts/ci/compile-and-generate-haddocks-fixtures.sh new file mode 100755 index 000000000..32cb8a763 --- /dev/null +++ b/scripts/ci/compile-and-generate-haddocks-fixtures.sh @@ -0,0 +1,375 @@ +#!/usr/bin/env bash +# +# compile-and-generate-haddocks-fixtures.sh +# +# This script serves a DUAL PURPOSE: +# 1. COMPILES all fixture files (validating they produce valid Haskell code) +# 2. GENERATES Haddock documentation with full dependency cross-referencing +# +# Since Haddock internally compiles the source files before generating documentation, +# running this script validates both compilation AND documentation generation in a +# single pass. This is more efficient than running separate compile and haddock passes. +# + +set -euo pipefail + +usage() { + cat <&2 + exit 1 + ;; + esac +done +shift $((OPTIND - 1)) + +# Detect script location and set up paths +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +HS_BINDGEN_DIR="$REPO_ROOT/hs-bindgen" +FIXTURES_DIR="$HS_BINDGEN_DIR/fixtures" +EXAMPLES_DIR="$HS_BINDGEN_DIR/examples" + +# Verify directories exist +if [[ ! -d "$FIXTURES_DIR" || ! -f "$FIXTURES_DIR/adios.pp.hs" ]]; then + echo "Error: Fixtures not found at $FIXTURES_DIR" >&2 + exit 1 +fi + +# Function to check if a file is in the known failures list +is_known_failure() { + local file="$1" + local basename_file + basename_file=$(basename "$file") + + for failure in "${KNOWN_FAILURES[@]}"; do + if [[ "$basename_file" == "$failure" ]]; then + return 0 + fi + done + return 1 +} + +# Function to compile and generate haddock for a single fixture +process_fixture() { + local file="$1" + local basename_file + basename_file=$(basename "$file") + + # Extract fixture name without .pp.hs extension for output directory + local fixture_name + fixture_name=$(basename "$file" .pp.hs) + + # Use a persistent output directory so documentation can be browsed + # This allows users to view all fixture haddocks together + local output_dir + output_dir="$HADDOCK_OUTPUT_DIR/$fixture_name" + mkdir -p "$output_dir" + + # Compile the fixture and generate Haddock documentation with full dependency linking + # Haddock will: + # 1. Compile the source file using GHC (validates Haskell code) + # 2. Generate HTML documentation (validates Haddock markup) + # 3. Cross-reference with dependency packages (validates imports) + # + # --html: Generate HTML documentation + # --odir: Output directory + # --read-interface: Read dependency interface files for cross-referencing + # Format: , + # --optghc: Pass options to the GHC that haddock uses internally for compilation + # -package: Make package available for import + # -optc: Pass the following flag to the C compiler + # -I: Add include directory for C headers + # -std=gnu2x: Use GNU C23 standard (supports C23 bool type + GNU extensions like asm) + # -Wno-deprecated-declarations: Suppress warnings about deprecated functions + # -Wno-attributes: Suppress warnings about unrecognized or ignored attributes + # + if (cd "$HS_BINDGEN_DIR" && cabal exec -- haddock \ + --html \ + --odir="$output_dir" \ + --optghc="-package hs-bindgen-runtime" \ + --optghc="-package c-expr-runtime" \ + --optghc="-optc -I$EXAMPLES_DIR" \ + --optghc="-optc -I$EXAMPLES_DIR/golden" \ + --optghc="-optc -std=gnu2x" \ + --optghc="-optc -Wno-deprecated-declarations" \ + --optghc="-optc -Wno-attributes" \ + "$file" &>"$output_dir/haddock.log"); then + echo "โœ“ $basename_file" + return 0 + else + echo "โœ— $basename_file" + if [[ -s "$output_dir/haddock.log" ]]; then + echo " Haddock error log:" + sed 's/^/ /' "$output_dir/haddock.log" + fi + return 1 + fi +} + +# Function to generate an index page for browsing all fixture haddocks +generate_index() { + local index_file="$HADDOCK_OUTPUT_DIR/index.html" + local processed_count="${#FIXTURES_TO_PROCESS[@]}" + local skipped_count="${#FIXTURES_SKIPPED[@]}" + + cat > "$index_file" <<'EOF' + + + + + Fixture Haddock Documentation + + + +

Fixture Haddock Documentation

+ +
+ Statistics:
+EOF + + echo " Total fixtures: $((processed_count + skipped_count))
" >> "$index_file" + echo " Processed: $processed_count
" >> "$index_file" + echo " Skipped: $skipped_count" >> "$index_file" + + cat >> "$index_file" <<'EOF' +
+ +

Fixture Documentation

+
+EOF + + # Add links to all processed fixtures + for file in "${FIXTURES_TO_PROCESS[@]}"; do + local fixture_name + fixture_name=$(basename "$file" .pp.hs) + + if [[ -f "$HADDOCK_OUTPUT_DIR/$fixture_name/index.html" ]]; then + echo " " >> "$index_file" + else + echo "
$fixture_name (failed)
" >> "$index_file" + fi + done + + cat >> "$index_file" <<'EOF' +
+EOF + + # Add skipped fixtures if any + if [[ ${#FIXTURES_SKIPPED[@]} -gt 0 ]]; then + cat >> "$index_file" <<'EOF' + +

Skipped Fixtures

+
+EOF + for file in "${FIXTURES_SKIPPED[@]}"; do + local fixture_name + fixture_name=$(basename "$file" .pp.hs) + echo "
$fixture_name
" >> "$index_file" + done + + echo "
" >> "$index_file" + fi + + cat >> "$index_file" < + Generated by compile-and-generate-haddocks-fixtures.sh
+ $(date) + + + +EOF + + echo "๐Ÿ“š Generated index at: $index_file" +} + +# Create persistent output directory for haddock documentation +HADDOCK_OUTPUT_DIR="$REPO_ROOT/dist-newstyle/haddock-fixtures" +mkdir -p "$HADDOCK_OUTPUT_DIR" + +# Make these functions and variables available to child processes (subshells) +export -f process_fixture +export -f is_known_failure +export KNOWN_FAILURES +export HS_BINDGEN_DIR +export EXAMPLES_DIR +export HADDOCK_OUTPUT_DIR + +# Collect fixtures to process +echo "Collecting fixtures..." +FIXTURES_TO_PROCESS=() +FIXTURES_SKIPPED=() + +# Use find to recursively search for all .pp.hs files +while IFS= read -r -d '' file; do + if [[ "$FORCE_ALL" == "false" ]] && is_known_failure "$file"; then + FIXTURES_SKIPPED+=("$file") + else + FIXTURES_TO_PROCESS+=("$file") + fi +done < <(find "$FIXTURES_DIR" -type f -name "*.pp.hs" -print0 | sort -z) + +echo "" +echo "=========================================" +echo "Fixture Compilation & Haddock Report" +echo "=========================================" +echo "Total fixtures: $(find "$FIXTURES_DIR" -type f -name "*.pp.hs" | wc -l)" +echo "To process: ${#FIXTURES_TO_PROCESS[@]}" +echo "Skipped (known failures): ${#FIXTURES_SKIPPED[@]}" +echo "Parallel jobs: $JOBS" +echo "=========================================" +echo "" + +if [[ ${#FIXTURES_SKIPPED[@]} -gt 0 ]]; then + echo "Skipped fixtures (use -f to force):" + for file in "${FIXTURES_SKIPPED[@]}"; do + echo " - $file" + done + echo "" +fi + +if [[ ${#FIXTURES_TO_PROCESS[@]} -eq 0 ]]; then + echo "No fixtures to process!" + exit 0 +fi + +echo "Compiling and generating Haddock for ${#FIXTURES_TO_PROCESS[@]} fixtures with $JOBS parallel jobs..." +echo "" + +# Process fixtures in parallel using xargs +FAILED=0 +if printf '%s\n' "${FIXTURES_TO_PROCESS[@]}" | xargs -P "$JOBS" -I {} bash -c 'process_fixture "$@"' _ {}; then + : +else + FAILED=1 +fi + +echo "" +echo "=========================================" +if [[ $FAILED -eq 0 ]]; then + echo "โœ“ All fixtures processed successfully!" +else + echo "โœ— Some fixtures failed to process" +fi +echo "=========================================" +echo "" + +# Generate index page for browsing all fixture haddocks +generate_index + +echo "" +echo "๐Ÿ“š Browse fixture documentation at:" +echo " $HADDOCK_OUTPUT_DIR/index.html" +echo "" + +if [[ $FAILED -eq 0 ]]; then + exit 0 +else + exit 1 +fi diff --git a/scripts/ci/compile-fixtures.sh b/scripts/ci/compile-fixtures.sh deleted file mode 100755 index 71a4e3c46..000000000 --- a/scripts/ci/compile-fixtures.sh +++ /dev/null @@ -1,194 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -usage() { - cat <&2 - exit 1 - ;; - esac -done -shift $((OPTIND - 1)) - -# Detect script location and set up paths -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" -HS_BINDGEN_DIR="$REPO_ROOT/hs-bindgen" -FIXTURES_DIR="$HS_BINDGEN_DIR/fixtures" -EXAMPLES_DIR="$HS_BINDGEN_DIR/examples" - -# Verify directories exist -if [[ ! -d "$FIXTURES_DIR" || ! -f "$FIXTURES_DIR/adios.pp.hs" ]]; then - echo "Error: Fixtures not found at $FIXTURES_DIR" >&2 - exit 1 -fi - -# Function to check if a file is in the known failures list -is_known_failure() { - local file="$1" - local basename_file - basename_file=$(basename "$file") - - for failure in "${KNOWN_FAILURES[@]}"; do - if [[ "$basename_file" == "$failure" ]]; then - return 0 - fi - done - return 1 -} - -# Function to compile a single fixture -compile_fixture() { - local file="$1" - local basename_file - basename_file=$(basename "$file") - - # Use a temporary output file to avoid polluting the fixtures directory - local output_dir - output_dir=$(mktemp -d) - - # Compile the fixture with GHC - # -c: Compile only (no linking) - # -fforce-recomp: Always recompile - # -package: Make package available for import - # -outputdir: Where to put build artifacts - # -optc: Pass the following flag to the C compiler - # -I: Add include directory for C headers - # -std=gnu2x: Use GNU C23 standard (supports C23 bool type + GNU extensions like asm) - # -Wno-deprecated-declarations: Suppress warnings about deprecated functions - # -Wno-attributes: Suppress warnings about unrecognized or ignored attributes - if (cd "$HS_BINDGEN_DIR" && cabal exec -- ghc \ - -c \ - -fforce-recomp \ - -outputdir "$output_dir" \ - -package hs-bindgen-runtime \ - -package c-expr-runtime \ - -optc -I"$EXAMPLES_DIR" \ - -optc -I"$EXAMPLES_DIR/golden" \ - -optc -std=gnu2x \ - -optc -Wno-deprecated-declarations \ - -optc -Wno-attributes \ - "$file" &>"$output_dir/compile.log"); then - echo "โœ“ $basename_file" - rm -rf "$output_dir" - return 0 - else - echo "โœ— $basename_file" - if [[ -s "$output_dir/compile.log" ]]; then - echo " Error log:" - sed 's/^/ /' "$output_dir/compile.log" - fi - rm -rf "$output_dir" - return 1 - fi -} - -# Make these functions and variables available to child processes (subshells) -export -f compile_fixture -export -f is_known_failure -export KNOWN_FAILURES -export HS_BINDGEN_DIR -export EXAMPLES_DIR - -# Collect fixtures to compile -echo "Collecting fixtures..." -FIXTURES_TO_COMPILE=() -FIXTURES_SKIPPED=() - -# Use find to recursively search for all .pp.hs files -while IFS= read -r -d '' file; do - if [[ "$FORCE_ALL" == "false" ]] && is_known_failure "$file"; then - FIXTURES_SKIPPED+=("$file") - else - FIXTURES_TO_COMPILE+=("$file") - fi -done < <(find "$FIXTURES_DIR" -type f -name "*.pp.hs" -print0 | sort -z) - -echo "" -echo "=========================================" -echo "Fixture Compilation Report" -echo "=========================================" -echo "Total fixtures: $(find "$FIXTURES_DIR" -type f -name "*.pp.hs" | wc -l)" -echo "To compile: ${#FIXTURES_TO_COMPILE[@]}" -echo "Skipped (known failures): ${#FIXTURES_SKIPPED[@]}" -echo "Parallel jobs: $JOBS" -echo "=========================================" -echo "" - -if [[ ${#FIXTURES_SKIPPED[@]} -gt 0 ]]; then - echo "Skipped fixtures (use -f to force):" - for file in "${FIXTURES_SKIPPED[@]}"; do - echo " - $file" - done - echo "" -fi - -if [[ ${#FIXTURES_TO_COMPILE[@]} -eq 0 ]]; then - echo "No fixtures to compile!" - exit 0 -fi - -echo "Compiling ${#FIXTURES_TO_COMPILE[@]} fixtures with $JOBS parallel jobs..." -echo "" - -# Compile fixtures in parallel using xargs -FAILED=0 -if printf '%s\n' "${FIXTURES_TO_COMPILE[@]}" | xargs -P "$JOBS" -I {} bash -c 'compile_fixture "$@"' _ {}; then - : -else - FAILED=1 -fi - -echo "" -echo "=========================================" -if [[ $FAILED -eq 0 ]]; then - echo "โœ“ All fixtures compiled successfully!" - echo "=========================================" - exit 0 -else - echo "โœ— Some fixtures failed to compile" - echo "=========================================" - exit 1 -fi