pkgsrc-WIP-changes archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

py-mfusepy: Cherry-pick upstream PRs



Module Name:	pkgsrc-wip
Committed By:	Greg Troxel <gdt%lexort.com@localhost>
Pushed By:	gdt
Date:		Wed Sep 30 10:15:30 2026 -0400
Changeset:	c2bcdd3accae399dd23662956c943c035ba16f04

Modified Files:
	py-mfusepy/Makefile
	py-mfusepy/TODO
	py-mfusepy/distinfo
	py-mfusepy/patches/patch-mfusepy.py
Added Files:
	py-mfusepy/patches/patch-tests_test__examples.py
	py-mfusepy/patches/patch-tests_test__struct__layout.py

Log Message:
py-mfusepy: Cherry-pick upstream PRs

This commit moves to a new version of "support librefuse", and adds a
version of "avoid ioctl_opt".

To see a diff of this commit:
https://wip.pkgsrc.org/cgi-bin/gitweb.cgi?p=pkgsrc-wip.git;a=commitdiff;h=c2bcdd3accae399dd23662956c943c035ba16f04

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

diffstat:
 py-mfusepy/Makefile                                |   9 ++
 py-mfusepy/TODO                                    |   6 +-
 py-mfusepy/distinfo                                |   4 +-
 py-mfusepy/patches/patch-mfusepy.py                | 163 +++++++++++++++++++--
 py-mfusepy/patches/patch-tests_test__examples.py   |  30 ++++
 .../patches/patch-tests_test__struct__layout.py    |  38 +++++
 6 files changed, 234 insertions(+), 16 deletions(-)

diffs:
diff --git a/py-mfusepy/Makefile b/py-mfusepy/Makefile
index ebd39a8e9e..a8b6e5cb86 100644
--- a/py-mfusepy/Makefile
+++ b/py-mfusepy/Makefile
@@ -2,6 +2,7 @@
 
 DISTNAME=	mfusepy-3.1.1
 PKGNAME=	${PYPKGPREFIX}-${DISTNAME}
+PKGREVISION=	1
 CATEGORIES=	filesystems python
 MASTER_SITES=	${MASTER_SITE_PYPI:=m/mfusepy/}
 
@@ -12,6 +13,14 @@ LICENSE=	isc
 
 USE_LANGUAGES=	# none
 
+TOOL_DEPENDS+=	${PYPKGPREFIX}-setuptools>=77:../../devel/py-setuptools
+
+# Upstream has many test dependencies, not expressed in pyproject.toml.
+# At least:
+#   loopback
+#   memory
+# https://github.com/mxmlnkn/mfusepy/issues/61
+
 .include "../../lang/python/wheel.mk"
 .include "../../mk/fuse.buildlink3.mk"
 .include "../../mk/bsd.pkg.mk"
diff --git a/py-mfusepy/TODO b/py-mfusepy/TODO
index 16158f56fe..24066003ad 100644
--- a/py-mfusepy/TODO
+++ b/py-mfusepy/TODO
@@ -1,3 +1,5 @@
   - prepare COMMIT_MSG
-  - resolve ioctl test failure
-  - test more
+  - some patches are from upstream pending PRs; address them upstream.
+  - add missing test dependencies
+  - run tests
+
diff --git a/py-mfusepy/distinfo b/py-mfusepy/distinfo
index 6447d6058d..e88b625c51 100644
--- a/py-mfusepy/distinfo
+++ b/py-mfusepy/distinfo
@@ -3,4 +3,6 @@ $NetBSD$
 BLAKE2s (mfusepy-3.1.1.tar.gz) = a72506eb624ee8750863452c0c8c493f9ce40ddb0c27f2a196270d6f7953eece
 SHA512 (mfusepy-3.1.1.tar.gz) = 3d2b2d7531998bccd2b218e31983efd0b1d0854c9f4af3a88922fb89a55cd5c4e6972fa50031cae29f553b599686ad9dd1cb84134989fb876a9fa3b34f64547f
 Size (mfusepy-3.1.1.tar.gz) = 34549 bytes
-SHA1 (patch-mfusepy.py) = 35cb85c125ea95264e8fbabf88409870e6901d3d
+SHA1 (patch-mfusepy.py) = 4069b5c6efd150a116d182a7251dd2aa79675bc3
+SHA1 (patch-tests_test__examples.py) = 3ce125d03050c7d152d6f764de9eb071e9381c69
+SHA1 (patch-tests_test__struct__layout.py) = b982f1593550c9cff006f01a88313a77c94c404e
diff --git a/py-mfusepy/patches/patch-mfusepy.py b/py-mfusepy/patches/patch-mfusepy.py
index d4eb5fc980..34512a6c95 100644
--- a/py-mfusepy/patches/patch-mfusepy.py
+++ b/py-mfusepy/patches/patch-mfusepy.py
@@ -1,27 +1,36 @@
 $NetBSD$
 
-From upstream pending PR:
+From upstream pending PR, less CI hunk and hunk for code added
+since 3.1.1:
 
-  https://github.com/mxmlnkn/mfusepy/pull/42
-
-with additional debugging/kludging of the refuse path.  Hence this is in wip :-)
+  https://github.com/mxmlnkn/mfusepy/pull/59
 
 --- mfusepy.py.orig	2026-03-13 00:36:12.000000000 +0000
 +++ mfusepy.py
-@@ -99,6 +99,12 @@ if not _libfuse_path:
+@@ -99,6 +99,11 @@ if not _libfuse_path:
          _libfuse_path = (
              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')
-+        print(f"_libfuse_path 001 is {_libfuse_path}")
-+        _libfuse_path = 'librefuse.so.2'
-+        print(f"_libfuse_path 002 is {_libfuse_path}")
++        # On NetBSD 10+ librefuse implements FUSE 3, targeting 3.10 compatibility.
++        # On NetBSD, find_library only works if a C compiler or ld is in PATH (and e.g. not within pkgsrc builds,
++        # where the compiler wrappers drop -lrefuse), so fall back to the soname of the base system library.
++        _libfuse_path = find_library('refuse') or 'librefuse.so.2'
      elif _system == 'Windows':
          # pytype: disable=module-attr
          try:
-@@ -155,7 +161,7 @@ if fuse_version_major == 2 and fuse_vers
+@@ -139,6 +144,10 @@ _libfuse = ctypes.CDLL(_libfuse_path)
+ if _system == 'Darwin' and hasattr(_libfuse, 'macfuse_version'):
+     _system = 'Darwin-MacFuse'
+ 
++# NetBSD's librefuse is a FUSE reimplementation on top of puffs (no perfused daemon needed).
++# Its struct layouts differ from libfuse and are fixed, i.e. independent of the FUSE API version.
++_librefuse = _system == 'NetBSD' and hasattr(_libfuse, '__fuse_main')
++
+ 
+ def get_fuse_version(libfuse):
+     version = libfuse.fuse_version()
+@@ -155,7 +164,7 @@ if fuse_version_major == 2 and fuse_vers
          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!"
      )
@@ -30,7 +39,135 @@ with additional debugging/kludging of the refuse path.  Hence this is in wip :-)
      raise AttributeError(
          f"Found library {_libfuse_path} has wrong major version: {fuse_version_major}. Expected FUSE 2!"
      )
-@@ -1379,7 +1385,8 @@ class FUSE:
+@@ -747,56 +756,25 @@ _fuse_int32 = ctypes.c_int32 if (fuse_ve
+ _fuse_uint32 = ctypes.c_uint32 if (fuse_version_major, fuse_version_minor) >= (3, 17) else ctypes.c_uint
+ _fuse_file_info_fields_: list[FieldsEntry] = []
+ _fuse_file_info_fields_bitfield: list[BitFieldsEntry] = []
+-# Bogus check. It fixes the struct for NetBSD, but it makes the examples not run anymore!
+-if _system == 'NetBSD_False':
+-    # NetBSD has its own FUSE library reimplementation with mismatching struct layouts!
+-    # writepage is a bitfield (as in libFUSE 3.x), but the fh_old member still exists and the reported version is 2.9!
+-    # https://www.netbsd.org/docs/puffs/
++if _librefuse:
++    # librefuse has one fuse_file_info layout for all API versions: fh_old still exists (removed in FUSE 3),
++    # writepage is a bitfield and poll_events exists (both as in FUSE 3).
+     # https://github.com/NetBSD/src/blob/netbsd-11/lib/librefuse/fuse.h#L100-L129
+-    # https://github.com/NetBSD/src/blob/netbsd-10/lib/librefuse/fuse.h#L100-L129
+-    #  - fuse_file_info is unchanged between 10 and 11
+-    #  - FUSE_USE_VERSION is not set, but is set to _REFUSE_VERSION_ (3.10) with a warning if not set!
+-    #  - However, the CI prints FUSE version 2.9?!
+-    #  - Seems there is no sane way to get the correct compiled version! This is again an absolute shit show!
+-    # https://github.com/NetBSD/src/blob/netbsd-9/lib/librefuse/fuse.h#L51-L61
+-    #  - fuse_file_info looks quite different and version is specified as 2.6!
+-    #  - #define FUSE_USE_VERSION 26
+-    fuse_version = (fuse_version_major, fuse_version_minor)
+     _fuse_file_info_fields_ = [
+         ('flags', ctypes.c_int32),
+         ('fh_old', ctypes.c_uint32),
+-    ]
+-
+-    if fuse_version >= (2, 9):
+-        _fuse_file_info_fields_bitfield += [('writepage', ctypes.c_int32, 1)]
+-    else:
+-        _fuse_file_info_fields_ += [('writepage', ctypes.c_int32)]
+-
+-    _fuse_file_info_fields_bitfield += [
+-        ('direct_io', ctypes.c_uint32, 1),  # Introduced in FUSE 2.4
+-        ('keep_cache', ctypes.c_uint32, 1),  # Introduced in FUSE 2.4
+-        ('flush', ctypes.c_uint32, 1),  # Introduced in FUSE 2.6
+-    ]
+-    if fuse_version >= (2, 9):
+-        _fuse_file_info_fields_bitfield += [
+-            ('nonseekable', ctypes.c_uint, 1),  # Introduced in FUSE 2.8
+-            ('flock_release', ctypes.c_uint, 1),  # Introduced in FUSE 2.9
+-            ('cache_readdir', ctypes.c_uint, 1),  # Introduced in FUSE 3.5
+-        ]
+-
+-    _fuse_file_info_flag_count = sum(x[2] for x in _fuse_file_info_fields_bitfield)
+-    assert _fuse_file_info_flag_count < ctypes.sizeof(_fuse_uint32) * 8
+-
+-    _fuse_file_info_fields_ += _fuse_file_info_fields_bitfield
+-    _fuse_file_info_fields_ += [
+-        ('padding', _fuse_uint32, ctypes.sizeof(_fuse_uint32) * 8 - _fuse_file_info_flag_count),
++        ('writepage', ctypes.c_uint32, 1),
++        ('direct_io', ctypes.c_uint32, 1),
++        ('keep_cache', ctypes.c_uint32, 1),
++        ('flush', ctypes.c_uint32, 1),
++        ('nonseekable', ctypes.c_uint32, 1),
++        ('flock_release', ctypes.c_uint32, 1),
++        ('cache_readdir', ctypes.c_uint32, 1),
++        ('padding', ctypes.c_uint32, 25),
+         ('fh', ctypes.c_uint64),
+         ('lock_owner', ctypes.c_uint64),
++        ('poll_events', ctypes.c_uint32),
+     ]
+-
+-    if fuse_version >= (2, 9):
+-        _fuse_file_info_fields_ += [('poll_events', ctypes.c_uint32)]
+-
+ elif fuse_version_major == 2:
+     _fh_old_type = ctypes.c_uint if _system == 'OpenBSD' else ctypes.c_ulong
+     _fuse_file_info_fields_ = [
+@@ -937,14 +915,12 @@ _fuse_conn_info_fields: list[FieldsEntry
+     ('proto_major', ctypes.c_uint),
+     ('proto_minor', ctypes.c_uint),
+ ]
+-# For some reason, NetBSD return 2.9 even though the API is 3.10!
+-# The correct version is important for the struct layout!
+-# https://github.com/NetBSD/src/blob/netbsd-10/lib/librefuse/fuse.h#L58-L59
+-# However, the fuse_operations layout probably fits the advertised version because I had segfaults from utimens!
+-if fuse_version_major == 2 or _system == 'NetBSD':  # No idea why NetBSD did not remove it -.-
++# librefuse has one fuse_conn_info layout for all API versions, containing the FUSE 2 and FUSE 3 members.
++# https://github.com/NetBSD/src/blob/netbsd-11/lib/librefuse/fuse.h
++if fuse_version_major == 2 or _librefuse:
+     _fuse_conn_info_fields += [('async_read', _fuse_uint32)]
+ _fuse_conn_info_fields += [('max_write', _fuse_uint32)]
+-if fuse_version_major == 3 or _system == 'NetBSD':
++if fuse_version_major == 3 or _librefuse:
+     _fuse_conn_info_fields += [('max_read', _fuse_uint32)]
+ _fuse_conn_info_fields += [('max_readahead', _fuse_uint32)]
+ if _system == 'Darwin':
+@@ -955,11 +931,11 @@ _fuse_conn_info_fields += [
+     ('max_background', _fuse_uint32),  # Added in 2.9
+     ('congestion_threshold', _fuse_uint32),  # Added in 2.9
+ ]
+-if fuse_version_major == 2 and _system != 'NetBSD':
++if fuse_version_major == 2 and not _librefuse:
+     _fuse_conn_info_fields += [('reserved', _fuse_uint32 * (22 if _system == 'Darwin' else 23))]
+-elif fuse_version_major == 3 or _system == 'NetBSD':
++elif fuse_version_major == 3 or _librefuse:
+     _fuse_conn_info_fields += [('time_gran', _fuse_uint32)]
+-    if fuse_version_minor < 17 or _system == 'NetBSD':
++    if fuse_version_minor < 17 or _librefuse:
+         _fuse_conn_info_fields += [('reserved', _fuse_uint32 * 22)]
+     else:
+         _fuse_conn_info_fields += [
+@@ -1037,7 +1013,7 @@ if fuse_version_major == 3:
+     if fuse_version_minor >= 15 and fuse_version_minor < 17:
+         _fuse_config_fields_ += [('parallel_direct_writes', ctypes.c_int)]
+ 
+-    if _system != 'NetBSD':
++    if not _librefuse:
+         _fuse_config_fields_ += [
+             ('show_help', _fuse_int32),
+             ('modules', ctypes.c_char_p),
+@@ -1243,6 +1219,15 @@ if _system == "OpenBSD":
+     def fuse_main_real(argc, argv, fuse_ops_v, sizeof_fuse_ops, ctx_p):
+         return _libfuse.fuse_main(argc, argv, fuse_ops_v, ctx_p)
+ 
++elif _librefuse:
++    # librefuse's fuse_main_real is only a shim for binaries built against FUSE 2.6: it always interprets
++    # the operations as struct fuse_operations_v26. __fuse_main takes the layout version instead of the size.
++    # The FUSE 3 fuse_operations defined above is struct fuse_operations_v38 (used for FUSE_USE_VERSION 38..310).
++    _REFUSE_OP_VERSION = 38
++
++    def fuse_main_real(argc, argv, fuse_ops_v, sizeof_fuse_ops, ctx_p):
++        return getattr(_libfuse, '__fuse_main')(argc, argv, fuse_ops_v, _REFUSE_OP_VERSION, ctx_p)
++
+ else:
+     fuse_main_real = _libfuse.fuse_main_real
+ 
+@@ -1379,7 +1364,8 @@ class FUSE:
          }
  
          argsb = [arg.encode(encoding, self.errors) for arg in args]
@@ -40,7 +177,7 @@ with additional debugging/kludging of the refuse path.  Hence this is in wip :-)
  
          alternative_callbacks = {
              "readdir": ["readdir_with_offset"],
-@@ -1443,7 +1450,7 @@ class FUSE:
+@@ -1443,7 +1429,7 @@ class FUSE:
          except ValueError:
              old_handler = SIG_DFL
  
diff --git a/py-mfusepy/patches/patch-tests_test__examples.py b/py-mfusepy/patches/patch-tests_test__examples.py
new file mode 100644
index 0000000000..bd09193db9
--- /dev/null
+++ b/py-mfusepy/patches/patch-tests_test__examples.py
@@ -0,0 +1,30 @@
+$NetBSD$
+
+Tests depend on ioctl_opt, not documented:
+  https://github.com/mxmlnkn/mfusepy/issues/48
+  https://github.com/mxmlnkn/mfusepy/pull/60
+
+Reimplementation of PR patch, less continuing to run the tests on
+Linux.  Filed upstream as a comment in the PR.
+
+--- tests/test_examples.py.orig	2026-09-30 13:47:39.350361831 +0000
++++ tests/test_examples.py
+@@ -19,7 +19,8 @@ from types import ModuleType
+ from typing import Optional
+ 
+ import pytest
+-from ioctl_opt import IOWR
++#from ioctl_opt import IOWR
++ioctl_opt=None
+ 
+ pwd: Optional[ModuleType]
+ try:
+@@ -248,7 +249,7 @@ def test_read_write_file_system(cli, tmp
+             with open(path, 'rb') as file:
+                 # Test a simple ioctl command that returns the argument incremented by one.
+                 argument = 123
+-                iowr_m = IOWR(ord('M'), 1, ctypes.c_uint32)
++                iowr_m = ioctl_opt.IOWR(ord('M'), 1, ctypes.c_uint32)
+                 result = fcntl.ioctl(file, iowr_m, struct.pack('I', argument))
+                 assert struct.unpack('I', result)[0] == argument + 1
+ 
diff --git a/py-mfusepy/patches/patch-tests_test__struct__layout.py b/py-mfusepy/patches/patch-tests_test__struct__layout.py
new file mode 100644
index 0000000000..e856af22d6
--- /dev/null
+++ b/py-mfusepy/patches/patch-tests_test__struct__layout.py
@@ -0,0 +1,38 @@
+$NetBSD$
+
+Logically part of mfusepy.py patch.
+
+--- tests/test_struct_layout.py.orig	2026-03-13 00:36:12.000000000 +0000
++++ tests/test_struct_layout.py
+@@ -1,6 +1,5 @@
+ import ctypes
+ import os
+-import platform
+ import pprint
+ import shutil
+ import subprocess
+@@ -82,8 +81,7 @@ STRUCT_NAMES = {
+     ],
+ }
+ 
+-if platform.system() != 'NetBSD':
+-    STRUCT_NAMES['fuse_file_info'] = ['flags', 'fh', 'lock_owner']
++STRUCT_NAMES['fuse_file_info'] = ['flags', 'fh', 'lock_owner']
+ 
+ if mfusepy.fuse_version_major == 3:
+     STRUCT_NAMES['fuse_config'] = [
+@@ -188,10 +186,12 @@ def c_run(name: str, source: str) -> str
+             f'-DFUSE_USE_VERSION={mfusepy.fuse_version_major}{mfusepy.fuse_version_minor}',
+             '-D_FILE_OFFSET_BITS=64',
+         ]
+-        cflags += [f'-I{path}' for path in include_paths if os.path.exists(path)]
++        # librefuse's fuse.h is in the default include path, do not pick up the headers of a libfuse package.
++        if not mfusepy._librefuse:
++            cflags += [f'-I{path}' for path in include_paths if os.path.exists(path)]
+ 
+         # Add possible pkg-config flags if available
+-        for fuse_lib in ("fuse", "fuse3"):
++        for fuse_lib in () if mfusepy._librefuse else ("fuse", "fuse3"):
+             try:
+                 pkg_config_flags = subprocess.check_output(['pkg-config', '--cflags', fuse_lib], text=True).split()
+                 cflags.extend(pkg_config_flags)


Home | Main Index | Thread Index | Old Index