From d5d1479189d214c0a83c29ead6e63905f5ebc6fe Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 23 Dec 2025 01:38:20 +0100 Subject: [PATCH 1/7] temp: remove most test jobs --- .github/workflows/tests.yml | 77 +------------------------------------ 1 file changed, 1 insertion(+), 76 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e4582c7..57c972a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,91 +7,16 @@ on: pull_request: jobs: - Static-Code-Checks: - runs-on: ubuntu-slim - - steps: - - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.10' - - - name: Install Dependencies - run: | - python3 -m pip install ioctl-opt paramiko types-paramiko pytest - - - name: Style Check With Ruff - run: | - python3 -m pip install ruff - ruff check --config tests/.ruff.toml -- $( git ls-tree -r --name-only HEAD | 'grep' -E '[.]py$' ) - - - name: Style Check With Black - run: | - python3 -m pip install black - black -q --diff --line-length 120 --skip-string-normalization $( git ls-tree -r --name-only HEAD | 'grep' -E '[.]py$' ) > black.diff - if [ -s black.diff ]; then - cat black.diff - exit 123 - fi - - - name: Lint With Codespell - run: | - python3 -m pip install codespell - codespell $( git ls-tree -r --name-only HEAD | 'grep' -E '[.](py|md|txt|sh|yml)$' ) - - - name: Lint With Flake8 - run: | - python3 -m pip install flake8 - flake8 --config tests/.flake8 $( git ls-tree -r --name-only HEAD | 'grep' -E '[.]py$' ) - - - name: Lint With Pylint - run: | - python3 -m pip install pylint - pylint --rcfile tests/.pylintrc $( git ls-tree -r --name-only HEAD | 'grep' -E '[.]py$' ) | tee pylint.log - ! 'egrep' ': E[0-9]{4}: ' pylint.log - - - name: Lint With Pytype - run: | - python3 -m pip install pytype - pytype -d import-error $( git ls-tree -r --name-only HEAD | 'grep' -E '[.]py$' ) - - - name: Lint With Mypy - run: | - yes | python3 -m pip install --upgrade-strategy eager --upgrade types-dataclasses mypy - mypy --config-file tests/.mypy.ini $( git ls-tree -r --name-only HEAD | 'grep' -E '[.]py$' ) Tests: runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: # https://endoflife.date/python include: - - os: ubuntu-22.04 - python-version: '3.9' - - os: ubuntu-22.04-arm - python-version: '3.10' - - os: ubuntu-22.04 - python-version: '3.11' - - os: ubuntu-24.04-arm - python-version: '3.12' - os: ubuntu-24.04 - python-version: '3.13' - - os: ubuntu-24.04 - python-version: '3.14' - - os: macos-15 - python-version: '3.9' - - os: macos-14 - python-version: '3.10' - - os: macos-15-intel - python-version: '3.11' - - os: macos-14 - python-version: '3.12' - - os: macos-15-intel - python-version: '3.13' - - os: macos-15 python-version: '3.14' env: From b9c0117f77560ead6c5d1b2d8e9b05f4ee6fe18b Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 23 Dec 2025 01:36:58 +0100 Subject: [PATCH 2/7] [fix] directly talk to librefuse We can avoid the perfuse daemon that way. --- .github/workflows/tests.yml | 5 +---- mfusepy.py | 4 +++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 57c972a..12e0dfb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -218,7 +218,7 @@ jobs: # Packages sudo -E pkgin -y update - sudo -E pkgin -y install git fuse perfuse python311 py311-pip + sudo -E pkgin -y install git pkgconf python311 py311-pip sudo -E ln -sf /usr/pkg/bin/python3.11 /usr/pkg/bin/python3 # Fix PATH @@ -229,9 +229,6 @@ jobs: sudo sysctl -w kern.sbmax=4194304 sudo chmod 666 /dev/puffs - # avoid permissions issue for perfused trace file: - sudo chmod 777 /var/run - # Install pip Dependencies python3 -m pip install pytest pytest-order ioctl-opt diff --git a/mfusepy.py b/mfusepy.py index 88b55b9..7181c4d 100644 --- a/mfusepy.py +++ b/mfusepy.py @@ -99,6 +99,8 @@ class c_utimbuf(ctypes.Structure): _libfuse_path = ( find_library('fuse4x') or find_library('osxfuse') or find_library('fuse') or find_library('fuse-t') ) + elif _system == 'NetBSD': + _libfuse_path = find_library('refuse') elif _system == 'Windows': # pytype: disable=module-attr try: @@ -155,7 +157,7 @@ def get_fuse_version(libfuse): f"Found library {_libfuse_path} is too old: {fuse_version_major}.{fuse_version_minor}. " "There have been several ABI breaks in each version. Libfuse < 2.6 is not supported!" ) -if fuse_version_major != 2 and not (fuse_version_major == 3 and _system == 'Linux'): +if fuse_version_major != 2 and not (fuse_version_major == 3 and _system in ('Linux', 'NetBSD')): raise AttributeError( f"Found library {_libfuse_path} has wrong major version: {fuse_version_major}. Expected FUSE 2!" ) From 89b9a378c551756c52e9ae0c08997bea8a9bacda Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 23 Dec 2025 02:40:56 +0100 Subject: [PATCH 3/7] add librefuse comment --- mfusepy.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mfusepy.py b/mfusepy.py index 7181c4d..645f091 100644 --- a/mfusepy.py +++ b/mfusepy.py @@ -100,6 +100,7 @@ class c_utimbuf(ctypes.Structure): find_library('fuse4x') or find_library('osxfuse') or find_library('fuse') or find_library('fuse-t') ) elif _system == 'NetBSD': + # On NetBSD 10+ librefuse implements FUSE 3, targetting 3.10 compatibility. _libfuse_path = find_library('refuse') elif _system == 'Windows': # pytype: disable=module-attr From 92ef4e7daa0b8e6f7054cc75461b28d40cc4d060 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 23 Dec 2025 02:51:40 +0100 Subject: [PATCH 4/7] temp: less spam --- tests/test_struct_layout.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_struct_layout.py b/tests/test_struct_layout.py index 142a92a..1446407 100644 --- a/tests/test_struct_layout.py +++ b/tests/test_struct_layout.py @@ -147,7 +147,7 @@ } """ -print(C_CHECKER) +# print(C_CHECKER) def get_compiler(): @@ -219,10 +219,10 @@ def c_run(name: str, source: str) -> str: print(f"Compiler stderr:\n{e.stderr}") assert e.returncode == 0, "Could not compile C program to verify sizes." - for line in Path(preprocessed_file).read_text().split('\n'): - if not line.startswith('#') and line: - print(line) - print(preprocessed_file) + #for line in Path(preprocessed_file).read_text().split('\n'): + # if not line.startswith('#') and line: + # print(line) + #print(preprocessed_file) output = subprocess.check_output([exe_file], text=True) return output @@ -232,7 +232,7 @@ def c_run(name: str, source: str) -> str: def test_struct_layout(): output = c_run("verify_structs", C_CHECKER) c_infos = {line.split(':', 1)[0]: int(line.split(':', 1)[1]) for line in output.strip().split('\n')} - pprint.pprint(c_infos) + #pprint.pprint(c_infos) fail = False for struct_name, member_names in STRUCT_NAMES.items(): From 2484a86053345fc671653f33a9abe4bd43b41315 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 23 Dec 2025 03:05:57 +0100 Subject: [PATCH 5/7] do not run struct_layout test twice --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 12e0dfb..a91bd00 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -239,7 +239,7 @@ jobs: rc=0 python3 -m pytest -s -v -rs tests/test_struct_layout.py # for now, run the tests as root, too many PermissionErrors: - sudo -E python3 -m pytest -s -v -rs tests || rc=$? + sudo -E python3 -m pytest -s -v -rs -k "not struct_layout" tests || rc=$? exit "$rc" ;; esac From 30820cc9663b90425e01e1e83d79e86ec2986d95 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 23 Dec 2025 03:09:47 +0100 Subject: [PATCH 6/7] omit memory fs --- tests/test_examples.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_examples.py b/tests/test_examples.py index 35a2be5..663d529 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -209,7 +209,8 @@ def unmount(self): time.sleep(0.1) -@pytest.mark.parametrize('cli', [cli_loopback, cli_memory, cli_memory_nullpath]) +#@pytest.mark.parametrize('cli', [cli_loopback, cli_memory, cli_memory_nullpath]) +@pytest.mark.parametrize('cli', [cli_loopback]) def test_read_write_file_system(cli, tmp_path): if cli == cli_loopback: mount_source = tmp_path / "folder" From e3b235010c5d18c3625272a527a2f86b43f9e1ff Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 23 Dec 2025 03:47:51 +0100 Subject: [PATCH 7/7] NULL terminate argv --- mfusepy.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mfusepy.py b/mfusepy.py index 645f091..cf6f2c5 100644 --- a/mfusepy.py +++ b/mfusepy.py @@ -1382,7 +1382,8 @@ class as is to Operations, instead of just the fh field. } argsb = [arg.encode(encoding, self.errors) for arg in args] - argv = (ctypes.c_char_p * len(argsb))(*argsb) + argc = len(argsb) + argv = (ctypes.c_char_p * (argc + 1))(*argsb, None) # Null terminate explicitly alternative_callbacks = { "readdir": ["readdir_with_offset"], @@ -1446,7 +1447,7 @@ class as is to Operations, instead of just the fh field. except ValueError: old_handler = SIG_DFL - err = fuse_main_real(len(argsb), argv, ctypes.pointer(fuse_ops), ctypes.sizeof(fuse_ops), None) + err = fuse_main_real(argc, argv, ctypes.pointer(fuse_ops), ctypes.sizeof(fuse_ops), None) try: signal(SIGINT, old_handler)