Loading src/jama/native_libs.py 0 → 100644 +43 −0 Original line number Diff line number Diff line import ctypes.util import os import sys from pathlib import Path from shutil import which def _prepend_env_path(name: str, path: Path) -> None: path_value = str(path) existing = os.environ.get(name) if existing: paths = existing.split(os.pathsep) if path_value in paths: return os.environ[name] = os.pathsep.join([path_value, *paths]) return os.environ[name] = path_value def _homebrew_library_dirs() -> list[Path]: prefixes: list[Path] = [] vips_executable = which("vips") if vips_executable: prefixes.append(Path(vips_executable).resolve().parent.parent) prefixes.extend([Path("/opt/homebrew"), Path("/usr/local")]) lib_dirs: list[Path] = [] for prefix in prefixes: lib_dir = prefix / "lib" if lib_dir not in lib_dirs and (lib_dir / "libvips.42.dylib").exists(): lib_dirs.append(lib_dir) return lib_dirs def configure_macos_homebrew_library_paths() -> None: if sys.platform != "darwin" or ctypes.util.find_library("vips"): return for lib_dir in _homebrew_library_dirs(): _prepend_env_path("DYLD_LIBRARY_PATH", lib_dir) _prepend_env_path("DYLD_FALLBACK_LIBRARY_PATH", lib_dir) configure_macos_homebrew_library_paths() src/resources/management/commands/fusefs.py +20 −1 Original line number Diff line number Diff line import os from django.core.management.base import BaseCommand, CommandError from django.db.models import OuterRef, Subquery from fuse import FUSE, FuseOSError, Operations from dataclasses import dataclass import errno import stat from resources.models import Collection, FileExtension, slugify, File from jama import settings try: from fuse import FUSE, FuseOSError, Operations except OSError as exc: FUSE = None FUSE_IMPORT_ERROR = exc class FuseOSError(OSError): def __init__(self, errno): super().__init__(errno, os.strerror(errno)) class Operations: def __call__(self, op, *args): if not hasattr(self, op): raise FuseOSError(errno.EFAULT) return getattr(self, op)(*args) else: FUSE_IMPORT_ERROR = None STAT_KEYS = ( "st_atime", Loading Loading @@ -376,6 +393,8 @@ class Command(BaseCommand): ).first() if not root_collection: raise CommandError(f"{root_collection_id} is not a valid collection id") if FUSE is None: raise CommandError("Unable to load libfuse") from FUSE_IMPORT_ERROR FUSE( Ops(root_collection), mount_point, Loading src/resources/tests.py +9 −0 Original line number Diff line number Diff line Loading @@ -421,6 +421,15 @@ class FuseFsOpsTestCase(TestCase): fuse.assert_not_called() def test_command_reports_missing_libfuse(self): with TemporaryDirectory() as mount_point: with ( patch.object(fusefs, "FUSE", None), patch.object(fusefs, "FUSE_IMPORT_ERROR", OSError("missing fuse")), self.assertRaises(CommandError), ): call_command("fusefs", mount_point, self.root.pk) class ProjectSnapshotTestCase(TestCase): def setUp(self): Loading src/resources/views.py +1 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ from django.http import ( FileResponse, ) from django.contrib.auth.decorators import login_required import jama.native_libs # noqa: F401 - configures libvips lookup on macOS import pyvips from resources.models import File from resources.acl import UserAccess Loading src/rpc/methods.py +1 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ from glob import glob as _glob from typing import List, Dict, Iterator, Union, Tuple, Optional import cv2 import numpy import jama.native_libs # noqa: F401 - configures libvips lookup on macOS import pyvips import unidecode from django.contrib.auth.models import User Loading Loading
src/jama/native_libs.py 0 → 100644 +43 −0 Original line number Diff line number Diff line import ctypes.util import os import sys from pathlib import Path from shutil import which def _prepend_env_path(name: str, path: Path) -> None: path_value = str(path) existing = os.environ.get(name) if existing: paths = existing.split(os.pathsep) if path_value in paths: return os.environ[name] = os.pathsep.join([path_value, *paths]) return os.environ[name] = path_value def _homebrew_library_dirs() -> list[Path]: prefixes: list[Path] = [] vips_executable = which("vips") if vips_executable: prefixes.append(Path(vips_executable).resolve().parent.parent) prefixes.extend([Path("/opt/homebrew"), Path("/usr/local")]) lib_dirs: list[Path] = [] for prefix in prefixes: lib_dir = prefix / "lib" if lib_dir not in lib_dirs and (lib_dir / "libvips.42.dylib").exists(): lib_dirs.append(lib_dir) return lib_dirs def configure_macos_homebrew_library_paths() -> None: if sys.platform != "darwin" or ctypes.util.find_library("vips"): return for lib_dir in _homebrew_library_dirs(): _prepend_env_path("DYLD_LIBRARY_PATH", lib_dir) _prepend_env_path("DYLD_FALLBACK_LIBRARY_PATH", lib_dir) configure_macos_homebrew_library_paths()
src/resources/management/commands/fusefs.py +20 −1 Original line number Diff line number Diff line import os from django.core.management.base import BaseCommand, CommandError from django.db.models import OuterRef, Subquery from fuse import FUSE, FuseOSError, Operations from dataclasses import dataclass import errno import stat from resources.models import Collection, FileExtension, slugify, File from jama import settings try: from fuse import FUSE, FuseOSError, Operations except OSError as exc: FUSE = None FUSE_IMPORT_ERROR = exc class FuseOSError(OSError): def __init__(self, errno): super().__init__(errno, os.strerror(errno)) class Operations: def __call__(self, op, *args): if not hasattr(self, op): raise FuseOSError(errno.EFAULT) return getattr(self, op)(*args) else: FUSE_IMPORT_ERROR = None STAT_KEYS = ( "st_atime", Loading Loading @@ -376,6 +393,8 @@ class Command(BaseCommand): ).first() if not root_collection: raise CommandError(f"{root_collection_id} is not a valid collection id") if FUSE is None: raise CommandError("Unable to load libfuse") from FUSE_IMPORT_ERROR FUSE( Ops(root_collection), mount_point, Loading
src/resources/tests.py +9 −0 Original line number Diff line number Diff line Loading @@ -421,6 +421,15 @@ class FuseFsOpsTestCase(TestCase): fuse.assert_not_called() def test_command_reports_missing_libfuse(self): with TemporaryDirectory() as mount_point: with ( patch.object(fusefs, "FUSE", None), patch.object(fusefs, "FUSE_IMPORT_ERROR", OSError("missing fuse")), self.assertRaises(CommandError), ): call_command("fusefs", mount_point, self.root.pk) class ProjectSnapshotTestCase(TestCase): def setUp(self): Loading
src/resources/views.py +1 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ from django.http import ( FileResponse, ) from django.contrib.auth.decorators import login_required import jama.native_libs # noqa: F401 - configures libvips lookup on macOS import pyvips from resources.models import File from resources.acl import UserAccess Loading
src/rpc/methods.py +1 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ from glob import glob as _glob from typing import List, Dict, Iterator, Union, Tuple, Optional import cv2 import numpy import jama.native_libs # noqa: F401 - configures libvips lookup on macOS import pyvips import unidecode from django.contrib.auth.models import User Loading