Compile and Test CAT Standalone #12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Compile and Test CAT Standalone | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| source: | |
| description: "Source of standalone binaries" | |
| required: false | |
| default: "build" | |
| type: choice | |
| options: | |
| - build | |
| - release | |
| release_tag: | |
| description: "Release tag (only for release source)" | |
| required: false | |
| type: string | |
| env: | |
| MLM_LICENSE_TOKEN: ${{ secrets.MATLAB_BATCH_TOKEN }} | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | |
| jobs: | |
| # ──────────────────────────────────────────────────── | |
| # Job 1: Download release standalone (if source == release) | |
| # ──────────────────────────────────────────────────── | |
| download_release_standalone: | |
| name: Download Release Standalone | |
| if: inputs.source == 'release' | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| standalone_os: [Linux, Mac, Mac_arm64, Win] | |
| steps: | |
| - name: Download release asset | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| TAG="${{ inputs.release_tag }}" | |
| OS="${{ matrix.standalone_os }}" | |
| ASSET_NAME="CAT_R2023b_MCR_${OS}.zip" | |
| echo "Downloading $ASSET_NAME from release $TAG" | |
| gh release download "$TAG" --repo ${{ github.repository }} --pattern "$ASSET_NAME" | |
| - name: Upload as artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: cat-standalone-${{ matrix.standalone_os }} | |
| path: CAT_R2023b_MCR_${{ matrix.standalone_os }}.zip | |
| retention-days: 1 | |
| # ──────────────────────────────────────────────────── | |
| # Job 2: Build standalone (if source == build or default) | |
| # ──────────────────────────────────────────────────── | |
| build_standalone: | |
| name: Build Standalone on ${{ matrix.os_name }} | |
| if: inputs.source == 'build' || inputs.source == '' | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| version: ["R2023b"] | |
| os: ["ubuntu-22.04", "macos-15-intel", "macos-latest", "windows-latest"] | |
| include: | |
| - os: ubuntu-22.04 | |
| os_name: Linux | |
| standalone_os: Linux | |
| mex_ext: mexa64 | |
| - os: macos-15-intel | |
| os_name: macOS_Intel | |
| standalone_os: Mac | |
| mex_ext: mexmaci64 | |
| - os: macos-latest | |
| os_name: macOS_ARM64 | |
| standalone_os: Mac_arm64 | |
| mex_ext: mexmaca64 | |
| - os: windows-latest | |
| os_name: Windows | |
| standalone_os: Win | |
| mex_ext: mexw64 | |
| steps: | |
| - name: Checkout CAT | |
| uses: actions/checkout@v5 | |
| - name: Update | |
| run: make update | |
| - name: Install rsync | |
| if: runner.os == 'Windows' | |
| run: choco install -y rsync | |
| - name: Checkout SPM | |
| uses: actions/checkout@v5 | |
| with: | |
| repository: spm/spm | |
| path: spm | |
| - name: Install CAT in SPM toolbox | |
| shell: bash | |
| run: | | |
| mkdir -p spm/toolbox/CAT | |
| rsync -a --exclude='.git' \ | |
| --exclude='spm/toolbox/CAT/' \ | |
| --exclude='batches/' \ | |
| --exclude='catQC/' \ | |
| --exclude='check_pipeline/' \ | |
| --exclude='development/' \ | |
| --exclude='html/' \ | |
| --exclude='internal/' \ | |
| --exclude='mexmaca/' \ | |
| --exclude='mexmaci/' \ | |
| --exclude='spm/' \ | |
| --exclude='Makefile' \ | |
| ./ spm/toolbox/CAT/ | |
| - name: Cleanup (Linux/Mac) | |
| if: runner.os != 'Windows' | |
| run: rm -rf standalone | |
| - name: Cleanup (Windows) | |
| if: runner.os == 'Windows' | |
| run: Remove-Item -Recurse -Force standalone | |
| - name: Install zip on Windows | |
| if: runner.os == 'Windows' | |
| run: choco install zip -y | |
| shell: bash | |
| - name: Set up MATLAB | |
| uses: matlab-actions/setup-matlab@v2 | |
| with: | |
| release: ${{ matrix.version }} | |
| products: MATLAB_Compiler | |
| - name: Set environment variable with MATLAB version | |
| shell: bash | |
| run: | | |
| echo "MATLAB_VERSION=R2023b" >> $GITHUB_ENV | |
| - name: Compile CAT mex-files | |
| uses: matlab-actions/run-command@v2 | |
| with: | |
| command: | | |
| addpath('spm'); | |
| cd('spm/toolbox/CAT') | |
| compile | |
| # Decompress .nii.gz templates so they are available as .nii in the compiled standalone. | |
| # Without this, atlas config (cat_conf_ROI.m) fails because it checks exist(...'.nii','file'). | |
| - name: Decompress NII.GZ templates | |
| shell: bash | |
| run: | | |
| echo "Decompressing .nii.gz files in CAT templates..." | |
| find spm/toolbox/CAT/templates_MNI152NLin2009cAsym -name '*.nii.gz' -exec gunzip -f {} \; | |
| find spm/toolbox/CAT/templates_surfaces -name '*.nii.gz' -exec gunzip -f {} \; | |
| find spm/toolbox/CAT/templates_surfaces_32k -name '*.nii.gz' -exec gunzip -f {} \; | |
| echo "Decompression complete" | |
| # Build SPM standalone (which includes CAT as toolbox) | |
| - name: Build MATLAB standalone | |
| uses: matlab-actions/run-command@v2 | |
| with: | |
| command: | | |
| cd('spm'); | |
| addpath(genpath('.')); | |
| savepath; | |
| cd('config'); | |
| spm_make_standalone | |
| - name: Compress standalone to ZIP | |
| shell: bash | |
| run: | | |
| mv spm/toolbox/CAT/standalone standalone/ | |
| mv standalone cat_standalone | |
| zip -r CAT_${{ env.MATLAB_VERSION }}_MCR_${{ matrix.standalone_os }}.zip cat_standalone/* | |
| - name: Upload standalone artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: cat-standalone-${{ matrix.standalone_os }} | |
| path: CAT_*.zip | |
| retention-days: 7 | |
| # ──────────────────────────────────────────────────── | |
| # Job 3: Test standalone on Linux | |
| # ──────────────────────────────────────────────────── | |
| test_standalone: | |
| name: Test Standalone on ${{ matrix.os_name }} | |
| needs: [build_standalone, download_release_standalone] | |
| if: | | |
| always() && | |
| (needs.build_standalone.result == 'success' || needs.download_release_standalone.result == 'success') | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: ["ubuntu-22.04"] | |
| include: | |
| - os: ubuntu-22.04 | |
| os_name: Linux | |
| standalone_os: Linux | |
| steps: | |
| - name: Download standalone artifact | |
| uses: actions/download-artifact@v5 | |
| with: | |
| name: cat-standalone-${{ matrix.standalone_os }} | |
| path: . | |
| - name: Extract standalone | |
| shell: bash | |
| run: | | |
| unzip -q CAT_*_MCR_${{ matrix.standalone_os }}.zip | |
| echo "Contents of cat_standalone:" | |
| ls -la cat_standalone | |
| # ── Install MATLAB Runtime ── | |
| - name: Install MATLAB Runtime (Linux) | |
| if: runner.os == 'Linux' | |
| shell: bash | |
| run: | | |
| # Download MCR R2023b | |
| echo "Downloading MATLAB Runtime R2023b for Linux..." | |
| wget -q https://ssd.mathworks.com/supportfiles/downloads/R2023b/Release/10/deployment_files/installer/complete/glnxa64/MATLAB_Runtime_R2023b_Update_10_glnxa64.zip -O mcr.zip | |
| unzip -q mcr.zip -d mcr_installer | |
| echo "Installing MATLAB Runtime..." | |
| sudo ./mcr_installer/install -agreeToLicense yes -destinationFolder /usr/local/MATLAB/MATLAB_Runtime 2>&1 | |
| echo "MCRROOT=/usr/local/MATLAB/MATLAB_Runtime/R2023b" >> $GITHUB_ENV | |
| echo "LD_LIBRARY_PATH=/usr/local/MATLAB/MATLAB_Runtime/R2023b/runtime/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/R2023b/bin/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/R2023b/sys/os/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/R2023b/sys/opengl/lib/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/R2023b/extern/bin/glnxa64" >> $GITHUB_ENV | |
| echo "MCR_INHIBIT_CTF_LOCK=1" >> $GITHUB_ENV | |
| echo "SPM_HTML_BROWSER=0" >> $GITHUB_ENV | |
| rm -rf mcr.zip mcr_installer | |
| echo "MATLAB Runtime installed at /usr/local/MATLAB/MATLAB_Runtime/R2023b" | |
| # ── Setup and extract CTF ── | |
| - name: Setup CAT standalone (Linux) | |
| if: runner.os == 'Linux' | |
| shell: bash | |
| run: | | |
| chmod +x cat_standalone/spm25 | |
| echo "Extracting CTF archive..." | |
| cat_standalone/spm25 function exit || true | |
| echo "CAT standalone setup complete" | |
| # ── Find test data (single_subj_T1.nii from SPM canonical directory) ── | |
| - name: Locate test data | |
| shell: bash | |
| run: | | |
| echo "Searching for single_subj_T1.nii inside standalone..." | |
| T1=$(find cat_standalone -name "single_subj_T1.nii" -type f 2>/dev/null | head -n 1) | |
| # If not found as .nii, try .nii.gz and decompress | |
| if [ -z "$T1" ]; then | |
| T1GZ=$(find cat_standalone -name "single_subj_T1.nii.gz" -type f 2>/dev/null | head -n 1) | |
| if [ -n "$T1GZ" ]; then | |
| echo "Found compressed: $T1GZ — decompressing..." | |
| gunzip -k "$T1GZ" | |
| T1="${T1GZ%.gz}" | |
| fi | |
| fi | |
| if [ -z "$T1" ]; then | |
| echo "ERROR: single_subj_T1.nii not found in standalone" | |
| echo "Listing all directories:" | |
| find cat_standalone -maxdepth 4 -type d 2>/dev/null | |
| echo "Listing all .nii and .nii.gz files:" | |
| find cat_standalone -name "*.nii" -o -name "*.nii.gz" 2>/dev/null | head -30 | |
| exit 1 | |
| fi | |
| echo "Found test data: $T1" | |
| # Copy to working directory so output goes there | |
| cp "$T1" ./single_subj_T1.nii | |
| echo "Test data ready: ./single_subj_T1.nii" | |
| # ── Run CAT segmentation test ── | |
| - name: Test CAT segmentation (Linux) | |
| timeout-minutes: 60 | |
| shell: bash | |
| run: | | |
| SPMROOT=$(pwd)/cat_standalone | |
| BATCH=$(find cat_standalone -name "cat_standalone_segment.m" -type f | head -n 1) | |
| CAT_SH=$(find cat_standalone -name "cat_standalone.sh" -type f | head -n 1) | |
| if [ -z "$BATCH" ]; then | |
| echo "ERROR: cat_standalone_segment.m not found" | |
| exit 1 | |
| fi | |
| if [ -z "$CAT_SH" ]; then | |
| echo "ERROR: cat_standalone.sh not found" | |
| exit 1 | |
| fi | |
| chmod +x "$CAT_SH" | |
| echo "Using batch file: $BATCH" | |
| echo "Using launcher: $CAT_SH" | |
| echo "Running CAT segmentation on single_subj_T1.nii..." | |
| "$CAT_SH" -b "$BATCH" -m "$MCRROOT" -s "$SPMROOT" "$(pwd)/single_subj_T1.nii" | |
| # ── Verify outputs ── | |
| - name: Verify segmentation outputs | |
| shell: bash | |
| run: | | |
| echo "Checking for segmentation output files..." | |
| # Look for typical CAT output files | |
| found=0 | |
| for pattern in "mri/mwp1*" "mri/p0*" "report/cat_*" "surf/lh.thickness*"; do | |
| matches=$(find . -path "./$pattern" 2>/dev/null) | |
| if [ -n "$matches" ]; then | |
| echo "Found: $matches" | |
| found=1 | |
| fi | |
| done | |
| if [ "$found" -eq 0 ]; then | |
| echo "WARNING: No standard CAT output files found in current directory" | |
| echo "Checking all nii files created:" | |
| find . -name "*.nii" -newer single_subj_T1.nii 2>/dev/null || echo "No new .nii files" | |
| find . -name "*.gii" 2>/dev/null || echo "No .gii files" | |
| find . -name "*.xml" -path "*/report/*" 2>/dev/null || echo "No report XMLs" | |
| fi | |
| echo "Test completed successfully" |