Skip to content

Workaround Fuse-T behavior on macOS #109

Workaround Fuse-T behavior on macOS

Workaround Fuse-T behavior on macOS #109

Workflow file for this run

name: Build and Test
on: [push, pull_request]
jobs:
ubuntu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: sudo apt-get install ccache libfuse3-dev build-essential flex bison gperf libncurses5-dev libncursesw5-dev gawk libmpfr-dev libgpm-dev zlib1g-dev yasm graphviz
- run: pip3 install sh
- run: ./bootstrap.sh
- run: cd test && ./test.sh --keep-going
macos:
runs-on: macos-latest
env:
PKG_CONFIG_PATH: /usr/local/lib/pkgconfig
steps:
- uses: actions/checkout@v4
- name: Install FUSE-T and dependencies
run: |
# FUSE-T: kext-free FUSE for macOS using NFS v4 local server.
# API-compatible with macFUSE, no kernel extension needed.
# https://github.com/macos-fuse-t/fuse-t
brew tap macos-fuse-t/homebrew-cask
brew install fuse-t
brew install pkg-config pcre2 ccache cmake
pip3 install --break-system-packages sh
- name: Create macFUSE-compatible header symlinks
run: |
# FUSE-T puts headers in a framework; tup expects /usr/local/include/fuse/
sudo mkdir -p /usr/local/include/fuse
sudo ln -sf /Library/Frameworks/fuse_t.framework/Headers/* /usr/local/include/fuse/
- name: Build patched libfuse for FUSE-T
run: |
# FUSE-T's libfuse has an unmount teardown bug that causes non-zero
# exit after every successful FUSE operation. We build from a patched
# fork until the fix is merged upstream.
# Fix: https://github.com/macos-fuse-t/libfuse/pull/11
git clone https://github.com/petemoore/libfuse.git /tmp/libfuse-src \
--branch fix/recv-eof-and-attrcache --depth 1
cd /tmp/libfuse-src && mkdir build && cd build
cmake .. && make -j$(sysctl -n hw.ncpu)
# Install patched library over FUSE-T's version
install_name_tool -id /usr/local/lib/libfuse-t.dylib lib/libfuse-t.dylib
sudo cp lib/libfuse-t.dylib /usr/local/lib/libfuse-t.dylib
sudo cp lib/libfuse-t.a /usr/local/lib/libfuse-t.a
# Create fuse.pc (FUSE-T doesn't ship one)
sudo mkdir -p /usr/local/lib/pkgconfig
sudo tee /usr/local/lib/pkgconfig/fuse.pc > /dev/null << 'EOF'
prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: fuse
Description: FUSE-T libfuse
Version: 2.9.9
Libs: -L${libdir} -lfuse-t -pthread
Cflags: -I${includedir}/fuse -D_FILE_OFFSET_BITS=64
EOF
- name: Build (bootstrap)
run: ./bootstrap.sh
- name: Run tests
run: |
cd test
# Skip tests that consistently fail on macOS.
#
# macOS platform issues (fail with both macFUSE and FUSE-T):
# t3083 — gcc --coverage gcno naming differs on macOS
# t6082 — utimens() on non-job directory (macOS restriction)
#
# FUSE-T deterministic failures (fail every run, not flaky):
# t2094, t2128, t2135 — run-script deps not tracked via NFS
# t5074 — process management timeout under NFS latency
# t6017 — input dependency missed by NFS client
# t8079 — run-script in variant not tracked via NFS
# t9006 — input dependency missed by NFS client
skip="t2094-run4.sh t2128-run-preload.sh t2135-preload6.sh t3083-extra-outputs-bang3.sh t5074-tup-dies.sh t6017-broken-update8.sh t6082-broken-update61.sh t8079-run-variant.sh t9006-gitignore-without-glob.sh"
tests=""
for t in t[0-9]*.sh; do
if echo " $skip " | grep -q " $t "; then
echo "SKIP (macOS platform issue): $t"
else
tests="$tests $t"
fi
done
# FUSE-T uses an NFS v4 backend instead of a kernel module.
# Under CI load, the macOS NFS client occasionally drops or
# delays FUSE callbacks, causing tup to miss file accesses.
# This affects ~1-4 random tests per run out of ~980 (all
# pass locally and pass with macFUSE). Retry failed tests
# up to 3 times to distinguish NFS flakes from genuine
# regressions. See: https://github.com/macos-fuse-t/fuse-t/issues/91
for attempt in 1 2 3 4; do
if [ $attempt -gt 1 ]; then
echo ""
echo "=== Attempt $attempt/4: retrying failed tests ==="
echo ""
tests="$failed_tests"
# Clean up leftover test directories from previous attempt
for t in $tests; do
rm -rf "tuptesttmp-${t%.sh}" 2>/dev/null || true
done
fi
./test.sh --keep-going $tests 2>&1 | tee /tmp/test-attempt-${attempt}.log
rc=${PIPESTATUS[0]}
if [ $rc -eq 0 ]; then
break
fi
# Extract failed test script names (format: " *** t1234-name.sh failed")
failed_tests=$(grep -oE 't[0-9]+-[a-zA-Z0-9_-]+\.sh failed' /tmp/test-attempt-${attempt}.log | sed 's/ failed$//' | sort -u | tr '\n' ' ')
if [ -z "$failed_tests" ]; then
break
fi
echo "Failed tests: $failed_tests"
done
exit $rc