You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by ro...@apache.org on 2020/12/29 13:35:23 UTC

[buildstream] 01/01: Depend on fusepy package instead internal copy

This is an automated email from the ASF dual-hosted git repository.

root pushed a commit to branch jjardon/fusepy
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit 2df43fa5b3ce2f9858a83c09e72071d0657e2cb3
Author: Javier Jardón <jj...@gnome.org>
AuthorDate: Tue Aug 28 17:45:50 2018 +0100

    Depend on fusepy package instead internal copy
---
 .gitlab-ci.yml                 |    3 +
 buildstream/_fuse/fuse.py      | 1006 ----------------------------------------
 buildstream/_fuse/hardlinks.py |    2 +-
 buildstream/_fuse/mount.py     |    2 +-
 setup.cfg                      |    1 -
 setup.py                       |    1 +
 6 files changed, 6 insertions(+), 1009 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 02a803d..9f43209 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -57,6 +57,7 @@ source_dist:
   variables:
     PYTEST_ADDOPTS: "--color=yes"
   script:
+  - pip3 install 'fusepy>=3.0.0'
   # Diagnostics
   - mount
   - df -h
@@ -118,6 +119,7 @@ tests-unix:
     # disappear unless we mark it as user-installed.
     - dnf mark install fuse-libs
     - dnf erase -y bubblewrap ostree
+    - pip3 install 'fusepy>=3.0.0'
 
     # Unpack and get into dist/buildstream
     - cd dist && ./unpack.sh && cd buildstream
@@ -145,6 +147,7 @@ docs:
   stage: test
   script:
   - export BST_SOURCE_CACHE="$(pwd)/cache/integration-cache/sources"
+  - pip3 install 'fusepy>=3.0.0'
   # Currently sphinx_rtd_theme does not support Sphinx >1.8, this breaks search functionality
   - pip3 install sphinx==1.7.9
   - pip3 install sphinx-click
diff --git a/buildstream/_fuse/fuse.py b/buildstream/_fuse/fuse.py
deleted file mode 100644
index 4ff6b99..0000000
--- a/buildstream/_fuse/fuse.py
+++ /dev/null
@@ -1,1006 +0,0 @@
-# This is an embedded copy of fuse.py taken from the following upstream commit:
-#
-#   https://github.com/terencehonles/fusepy/commit/0eafeb557e0e70926ed9450008ef17057d302391
-#
-# Our local modifications are recorded in the Git history of this repo.
-
-# Copyright (c) 2012 Terence Honles <te...@honles.com> (maintainer)
-# Copyright (c) 2008 Giorgos Verigakis <ve...@gmail.com> (author)
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-# pylint: skip-file
-
-from __future__ import print_function, absolute_import, division
-
-from ctypes import *
-from ctypes.util import find_library
-from errno import *
-from os import strerror
-from platform import machine, system
-from signal import signal, SIGINT, SIG_DFL
-from stat import S_IFDIR
-from traceback import print_exc
-
-import logging
-
-try:
-    from functools import partial
-except ImportError:
-    # http://docs.python.org/library/functools.html#functools.partial
-    def partial(func, *args, **keywords):
-        def newfunc(*fargs, **fkeywords):
-            newkeywords = keywords.copy()
-            newkeywords.update(fkeywords)
-            return func(*(args + fargs), **newkeywords)
-
-        newfunc.func = func
-        newfunc.args = args
-        newfunc.keywords = keywords
-        return newfunc
-
-try:
-    basestring
-except NameError:
-    basestring = str
-
-class c_timespec(Structure):
-    _fields_ = [('tv_sec', c_long), ('tv_nsec', c_long)]
-
-class c_utimbuf(Structure):
-    _fields_ = [('actime', c_timespec), ('modtime', c_timespec)]
-
-class c_stat(Structure):
-    pass    # Platform dependent
-
-_system = system()
-_machine = machine()
-
-if _system == 'Darwin':
-    _libiconv = CDLL(find_library('iconv'), RTLD_GLOBAL) # libfuse dependency
-    _libfuse_path = (find_library('fuse4x') or find_library('osxfuse') or
-                     find_library('fuse'))
-else:
-    _libfuse_path = find_library('fuse')
-
-if not _libfuse_path:
-    raise EnvironmentError('Unable to find libfuse')
-else:
-    _libfuse = CDLL(_libfuse_path)
-
-if _system == 'Darwin' and hasattr(_libfuse, 'macfuse_version'):
-    _system = 'Darwin-MacFuse'
-
-
-if _system in ('Darwin', 'Darwin-MacFuse', 'FreeBSD'):
-    ENOTSUP = 45
-    c_dev_t = c_int32
-    c_fsblkcnt_t = c_ulong
-    c_fsfilcnt_t = c_ulong
-    c_gid_t = c_uint32
-    c_mode_t = c_uint16
-    c_off_t = c_int64
-    c_pid_t = c_int32
-    c_uid_t = c_uint32
-    setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
-        c_size_t, c_int, c_uint32)
-    getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
-        c_size_t, c_uint32)
-    if _system == 'Darwin':
-        c_stat._fields_ = [
-            ('st_dev', c_dev_t),
-            ('st_mode', c_mode_t),
-            ('st_nlink', c_uint16),
-            ('st_ino', c_uint64),
-            ('st_uid', c_uid_t),
-            ('st_gid', c_gid_t),
-            ('st_rdev', c_dev_t),
-            ('st_atimespec', c_timespec),
-            ('st_mtimespec', c_timespec),
-            ('st_ctimespec', c_timespec),
-            ('st_birthtimespec', c_timespec),
-            ('st_size', c_off_t),
-            ('st_blocks', c_int64),
-            ('st_blksize', c_int32),
-            ('st_flags', c_int32),
-            ('st_gen', c_int32),
-            ('st_lspare', c_int32),
-            ('st_qspare', c_int64)]
-    else:
-        c_stat._fields_ = [
-            ('st_dev', c_dev_t),
-            ('st_ino', c_uint32),
-            ('st_mode', c_mode_t),
-            ('st_nlink', c_uint16),
-            ('st_uid', c_uid_t),
-            ('st_gid', c_gid_t),
-            ('st_rdev', c_dev_t),
-            ('st_atimespec', c_timespec),
-            ('st_mtimespec', c_timespec),
-            ('st_ctimespec', c_timespec),
-            ('st_size', c_off_t),
-            ('st_blocks', c_int64),
-            ('st_blksize', c_int32)]
-elif _system == 'Linux':
-    ENOTSUP = 95
-    c_dev_t = c_ulonglong
-    c_fsblkcnt_t = c_ulonglong
-    c_fsfilcnt_t = c_ulonglong
-    c_gid_t = c_uint
-    c_mode_t = c_uint
-    c_off_t = c_longlong
-    c_pid_t = c_int
-    c_uid_t = c_uint
-    setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
-                           c_size_t, c_int)
-
-    getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
-                           c_size_t)
-
-    if _machine == 'x86_64':
-        c_stat._fields_ = [
-            ('st_dev', c_dev_t),
-            ('st_ino', c_ulong),
-            ('st_nlink', c_ulong),
-            ('st_mode', c_mode_t),
-            ('st_uid', c_uid_t),
-            ('st_gid', c_gid_t),
-            ('__pad0', c_int),
-            ('st_rdev', c_dev_t),
-            ('st_size', c_off_t),
-            ('st_blksize', c_long),
-            ('st_blocks', c_long),
-            ('st_atimespec', c_timespec),
-            ('st_mtimespec', c_timespec),
-            ('st_ctimespec', c_timespec)]
-    elif _machine == 'mips':
-        c_stat._fields_ = [
-            ('st_dev', c_dev_t),
-            ('__pad1_1', c_ulong),
-            ('__pad1_2', c_ulong),
-            ('__pad1_3', c_ulong),
-            ('st_ino', c_ulong),
-            ('st_mode', c_mode_t),
-            ('st_nlink', c_ulong),
-            ('st_uid', c_uid_t),
-            ('st_gid', c_gid_t),
-            ('st_rdev', c_dev_t),
-            ('__pad2_1', c_ulong),
-            ('__pad2_2', c_ulong),
-            ('st_size', c_off_t),
-            ('__pad3', c_ulong),
-            ('st_atimespec', c_timespec),
-            ('__pad4', c_ulong),
-            ('st_mtimespec', c_timespec),
-            ('__pad5', c_ulong),
-            ('st_ctimespec', c_timespec),
-            ('__pad6', c_ulong),
-            ('st_blksize', c_long),
-            ('st_blocks', c_long),
-            ('__pad7_1', c_ulong),
-            ('__pad7_2', c_ulong),
-            ('__pad7_3', c_ulong),
-            ('__pad7_4', c_ulong),
-            ('__pad7_5', c_ulong),
-            ('__pad7_6', c_ulong),
-            ('__pad7_7', c_ulong),
-            ('__pad7_8', c_ulong),
-            ('__pad7_9', c_ulong),
-            ('__pad7_10', c_ulong),
-            ('__pad7_11', c_ulong),
-            ('__pad7_12', c_ulong),
-            ('__pad7_13', c_ulong),
-            ('__pad7_14', c_ulong)]
-    elif _machine == 'ppc':
-        c_stat._fields_ = [
-            ('st_dev', c_dev_t),
-            ('st_ino', c_ulonglong),
-            ('st_mode', c_mode_t),
-            ('st_nlink', c_uint),
-            ('st_uid', c_uid_t),
-            ('st_gid', c_gid_t),
-            ('st_rdev', c_dev_t),
-            ('__pad2', c_ushort),
-            ('st_size', c_off_t),
-            ('st_blksize', c_long),
-            ('st_blocks', c_longlong),
-            ('st_atimespec', c_timespec),
-            ('st_mtimespec', c_timespec),
-            ('st_ctimespec', c_timespec)]
-    elif _machine == 'ppc64' or _machine == 'ppc64le':
-        c_stat._fields_ = [
-            ('st_dev', c_dev_t),
-            ('st_ino', c_ulong),
-            ('st_nlink', c_ulong),
-            ('st_mode', c_mode_t),
-            ('st_uid', c_uid_t),
-            ('st_gid', c_gid_t),
-            ('__pad', c_uint),
-            ('st_rdev', c_dev_t),
-            ('st_size', c_off_t),
-            ('st_blksize', c_long),
-            ('st_blocks', c_long),
-            ('st_atimespec', c_timespec),
-            ('st_mtimespec', c_timespec),
-            ('st_ctimespec', c_timespec)]
-    elif _machine == 'aarch64':
-        c_stat._fields_ = [
-            ('st_dev', c_dev_t),
-            ('st_ino', c_ulong),
-            ('st_mode', c_mode_t),
-            ('st_nlink', c_uint),
-            ('st_uid', c_uid_t),
-            ('st_gid', c_gid_t),
-            ('st_rdev', c_dev_t),
-            ('__pad1', c_ulong),
-            ('st_size', c_off_t),
-            ('st_blksize', c_int),
-            ('__pad2', c_int),
-            ('st_blocks', c_long),
-            ('st_atimespec', c_timespec),
-            ('st_mtimespec', c_timespec),
-            ('st_ctimespec', c_timespec)]
-    else:
-        # i686, use as fallback for everything else
-        c_stat._fields_ = [
-            ('st_dev', c_dev_t),
-            ('__pad1', c_ushort),
-            ('__st_ino', c_ulong),
-            ('st_mode', c_mode_t),
-            ('st_nlink', c_uint),
-            ('st_uid', c_uid_t),
-            ('st_gid', c_gid_t),
-            ('st_rdev', c_dev_t),
-            ('__pad2', c_ushort),
-            ('st_size', c_off_t),
-            ('st_blksize', c_long),
-            ('st_blocks', c_longlong),
-            ('st_atimespec', c_timespec),
-            ('st_mtimespec', c_timespec),
-            ('st_ctimespec', c_timespec),
-            ('st_ino', c_ulonglong)]
-else:
-    raise NotImplementedError('{} is not supported.'.format(_system))
-
-
-class c_statvfs(Structure):
-    _fields_ = [
-        ('f_bsize', c_ulong),
-        ('f_frsize', c_ulong),
-        ('f_blocks', c_fsblkcnt_t),
-        ('f_bfree', c_fsblkcnt_t),
-        ('f_bavail', c_fsblkcnt_t),
-        ('f_files', c_fsfilcnt_t),
-        ('f_ffree', c_fsfilcnt_t),
-        ('f_favail', c_fsfilcnt_t),
-        ('f_fsid', c_ulong),
-        #('unused', c_int),
-        ('f_flag', c_ulong),
-        ('f_namemax', c_ulong)]
-
-if _system == 'FreeBSD':
-    c_fsblkcnt_t = c_uint64
-    c_fsfilcnt_t = c_uint64
-    setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
-                           c_size_t, c_int)
-
-    getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
-                           c_size_t)
-
-    class c_statvfs(Structure):
-        _fields_ = [
-            ('f_bavail', c_fsblkcnt_t),
-            ('f_bfree', c_fsblkcnt_t),
-            ('f_blocks', c_fsblkcnt_t),
-            ('f_favail', c_fsfilcnt_t),
-            ('f_ffree', c_fsfilcnt_t),
-            ('f_files', c_fsfilcnt_t),
-            ('f_bsize', c_ulong),
-            ('f_flag', c_ulong),
-            ('f_frsize', c_ulong)]
-
-class fuse_file_info(Structure):
-    _fields_ = [
-        ('flags', c_int),
-        ('fh_old', c_ulong),
-        ('writepage', c_int),
-        ('direct_io', c_uint, 1),
-        ('keep_cache', c_uint, 1),
-        ('flush', c_uint, 1),
-        ('padding', c_uint, 29),
-        ('fh', c_uint64),
-        ('lock_owner', c_uint64)]
-
-class fuse_context(Structure):
-    _fields_ = [
-        ('fuse', c_voidp),
-        ('uid', c_uid_t),
-        ('gid', c_gid_t),
-        ('pid', c_pid_t),
-        ('private_data', c_voidp)]
-
-_libfuse.fuse_get_context.restype = POINTER(fuse_context)
-
-
-class fuse_operations(Structure):
-    _fields_ = [
-        ('getattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_stat))),
-        ('readlink', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t)),
-        ('getdir', c_voidp),    # Deprecated, use readdir
-        ('mknod', CFUNCTYPE(c_int, c_char_p, c_mode_t, c_dev_t)),
-        ('mkdir', CFUNCTYPE(c_int, c_char_p, c_mode_t)),
-        ('unlink', CFUNCTYPE(c_int, c_char_p)),
-        ('rmdir', CFUNCTYPE(c_int, c_char_p)),
-        ('symlink', CFUNCTYPE(c_int, c_char_p, c_char_p)),
-        ('rename', CFUNCTYPE(c_int, c_char_p, c_char_p)),
-        ('link', CFUNCTYPE(c_int, c_char_p, c_char_p)),
-        ('chmod', CFUNCTYPE(c_int, c_char_p, c_mode_t)),
-        ('chown', CFUNCTYPE(c_int, c_char_p, c_uid_t, c_gid_t)),
-        ('truncate', CFUNCTYPE(c_int, c_char_p, c_off_t)),
-        ('utime', c_voidp),     # Deprecated, use utimens
-        ('open', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
-
-        ('read', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t,
-                           c_off_t, POINTER(fuse_file_info))),
-
-        ('write', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t,
-                            c_off_t, POINTER(fuse_file_info))),
-
-        ('statfs', CFUNCTYPE(c_int, c_char_p, POINTER(c_statvfs))),
-        ('flush', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
-        ('release', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
-        ('fsync', CFUNCTYPE(c_int, c_char_p, c_int, POINTER(fuse_file_info))),
-        ('setxattr', setxattr_t),
-        ('getxattr', getxattr_t),
-        ('listxattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t)),
-        ('removexattr', CFUNCTYPE(c_int, c_char_p, c_char_p)),
-        ('opendir', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
-
-        ('readdir', CFUNCTYPE(c_int, c_char_p, c_voidp,
-                              CFUNCTYPE(c_int, c_voidp, c_char_p,
-                                        POINTER(c_stat), c_off_t),
-                              c_off_t, POINTER(fuse_file_info))),
-
-        ('releasedir', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
-
-        ('fsyncdir', CFUNCTYPE(c_int, c_char_p, c_int,
-                               POINTER(fuse_file_info))),
-
-        ('init', CFUNCTYPE(c_voidp, c_voidp)),
-        ('destroy', CFUNCTYPE(c_voidp, c_voidp)),
-        ('access', CFUNCTYPE(c_int, c_char_p, c_int)),
-
-        ('create', CFUNCTYPE(c_int, c_char_p, c_mode_t,
-                             POINTER(fuse_file_info))),
-
-        ('ftruncate', CFUNCTYPE(c_int, c_char_p, c_off_t,
-                                POINTER(fuse_file_info))),
-
-        ('fgetattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_stat),
-                               POINTER(fuse_file_info))),
-
-        ('lock', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info),
-                           c_int, c_voidp)),
-
-        ('utimens', CFUNCTYPE(c_int, c_char_p, POINTER(c_utimbuf))),
-        ('bmap', CFUNCTYPE(c_int, c_char_p, c_size_t, POINTER(c_ulonglong))),
-        ('flag_nullpath_ok', c_uint, 1),
-        ('flag_nopath', c_uint, 1),
-        ('flag_utime_omit_ok', c_uint, 1),
-        ('flag_reserved', c_uint, 29),
-    ]
-
-
-def time_of_timespec(ts):
-    return ts.tv_sec + ts.tv_nsec / 10 ** 9
-
-def set_st_attrs(st, attrs):
-    for key, val in attrs.items():
-        if key in ('st_atime', 'st_mtime', 'st_ctime', 'st_birthtime'):
-            timespec = getattr(st, key + 'spec', None)
-            if timespec is None:
-                continue
-            timespec.tv_sec = int(val)
-            timespec.tv_nsec = int((val - timespec.tv_sec) * 10 ** 9)
-        elif hasattr(st, key):
-            setattr(st, key, val)
-
-
-def fuse_get_context():
-    'Returns a (uid, gid, pid) tuple'
-
-    ctxp = _libfuse.fuse_get_context()
-    ctx = ctxp.contents
-    return ctx.uid, ctx.gid, ctx.pid
-
-
-class FuseOSError(OSError):
-    def __init__(self, errno):
-        super(FuseOSError, self).__init__(errno, strerror(errno))
-
-
-class FUSE(object):
-    '''
-    This class is the lower level interface and should not be subclassed under
-    normal use. Its methods are called by fuse.
-
-    Assumes API version 2.6 or later.
-    '''
-
-    OPTIONS = (
-        ('foreground', '-f'),
-        ('debug', '-d'),
-        ('nothreads', '-s'),
-    )
-
-    def __init__(self, operations, mountpoint, raw_fi=False, encoding='utf-8',
-                 **kwargs):
-
-        '''
-        Setting raw_fi to True will cause FUSE to pass the fuse_file_info
-        class as is to Operations, instead of just the fh field.
-
-        This gives you access to direct_io, keep_cache, etc.
-        '''
-
-        self.operations = operations
-        self.raw_fi = raw_fi
-        self.encoding = encoding
-
-        args = ['fuse']
-
-        args.extend(flag for arg, flag in self.OPTIONS
-                    if kwargs.pop(arg, False))
-
-        kwargs.setdefault('fsname', operations.__class__.__name__)
-        args.append('-o')
-        args.append(','.join(self._normalize_fuse_options(**kwargs)))
-        args.append(mountpoint)
-
-        args = [arg.encode(encoding) for arg in args]
-        argv = (c_char_p * len(args))(*args)
-
-        fuse_ops = fuse_operations()
-        for ent in fuse_operations._fields_:
-            name, prototype = ent[:2]
-
-            val = getattr(operations, name, None)
-            if val is None:
-                continue
-
-            # Function pointer members are tested for using the
-            # getattr(operations, name) above but are dynamically
-            # invoked using self.operations(name)
-            if hasattr(prototype, 'argtypes'):
-                val = prototype(partial(self._wrapper, getattr(self, name)))
-
-            setattr(fuse_ops, name, val)
-
-        try:
-            old_handler = signal(SIGINT, SIG_DFL)
-        except ValueError:
-            old_handler = SIG_DFL
-
-        err = _libfuse.fuse_main_real(len(args), argv, pointer(fuse_ops),
-                                      sizeof(fuse_ops), None)
-
-        try:
-            signal(SIGINT, old_handler)
-        except ValueError:
-            pass
-
-        del self.operations     # Invoke the destructor
-        if err:
-            raise RuntimeError(err)
-
-    @staticmethod
-    def _normalize_fuse_options(**kargs):
-        for key, value in kargs.items():
-            if isinstance(value, bool):
-                if value is True: yield key
-            else:
-                yield '{}={}'.format(key, value)
-
-    @staticmethod
-    def _wrapper(func, *args, **kwargs):
-        'Decorator for the methods that follow'
-
-        try:
-            return func(*args, **kwargs) or 0
-        except OSError as e:
-            return -(e.errno or EFAULT)
-        except:
-            print_exc()
-            return -EFAULT
-
-    def _decode_optional_path(self, path):
-        # NB: this method is intended for fuse operations that
-        #     allow the path argument to be NULL,
-        #     *not* as a generic path decoding method
-        if path is None:
-            return None
-        return path.decode(self.encoding)
-
-    def getattr(self, path, buf):
-        return self.fgetattr(path, buf, None)
-
-    def readlink(self, path, buf, bufsize):
-        ret = self.operations('readlink', path.decode(self.encoding)) \
-                  .encode(self.encoding)
-
-        # copies a string into the given buffer
-        # (null terminated and truncated if necessary)
-        data = create_string_buffer(ret[:bufsize - 1])
-        memmove(buf, data, len(data))
-        return 0
-
-    def mknod(self, path, mode, dev):
-        return self.operations('mknod', path.decode(self.encoding), mode, dev)
-
-    def mkdir(self, path, mode):
-        return self.operations('mkdir', path.decode(self.encoding), mode)
-
-    def unlink(self, path):
-        return self.operations('unlink', path.decode(self.encoding))
-
-    def rmdir(self, path):
-        return self.operations('rmdir', path.decode(self.encoding))
-
-    def symlink(self, source, target):
-        'creates a symlink `target -> source` (e.g. ln -s source target)'
-
-        return self.operations('symlink', target.decode(self.encoding),
-                                          source.decode(self.encoding))
-
-    def rename(self, old, new):
-        return self.operations('rename', old.decode(self.encoding),
-                                         new.decode(self.encoding))
-
-    def link(self, source, target):
-        'creates a hard link `target -> source` (e.g. ln source target)'
-
-        return self.operations('link', target.decode(self.encoding),
-                                       source.decode(self.encoding))
-
-    def chmod(self, path, mode):
-        return self.operations('chmod', path.decode(self.encoding), mode)
-
-    def chown(self, path, uid, gid):
-        # Check if any of the arguments is a -1 that has overflowed
-        if c_uid_t(uid + 1).value == 0:
-            uid = -1
-        if c_gid_t(gid + 1).value == 0:
-            gid = -1
-
-        return self.operations('chown', path.decode(self.encoding), uid, gid)
-
-    def truncate(self, path, length):
-        return self.operations('truncate', path.decode(self.encoding), length)
-
-    def open(self, path, fip):
-        fi = fip.contents
-        if self.raw_fi:
-            return self.operations('open', path.decode(self.encoding), fi)
-        else:
-            fi.fh = self.operations('open', path.decode(self.encoding),
-                                            fi.flags)
-
-            return 0
-
-    def read(self, path, buf, size, offset, fip):
-        if self.raw_fi:
-          fh = fip.contents
-        else:
-          fh = fip.contents.fh
-
-        ret = self.operations('read', self._decode_optional_path(path), size,
-                                      offset, fh)
-
-        if not ret: return 0
-
-        retsize = len(ret)
-        assert retsize <= size, \
-            'actual amount read {:d} greater than expected {:d}'.format(retsize, size)
-
-        data = create_string_buffer(ret, retsize)
-        memmove(buf, data, retsize)
-        return retsize
-
-    def write(self, path, buf, size, offset, fip):
-        data = string_at(buf, size)
-
-        if self.raw_fi:
-            fh = fip.contents
-        else:
-            fh = fip.contents.fh
-
-        return self.operations('write', self._decode_optional_path(path), data,
-                                        offset, fh)
-
-    def statfs(self, path, buf):
-        stv = buf.contents
-        attrs = self.operations('statfs', path.decode(self.encoding))
-        for key, val in attrs.items():
-            if hasattr(stv, key):
-                setattr(stv, key, val)
-
-        return 0
-
-    def flush(self, path, fip):
-        if self.raw_fi:
-            fh = fip.contents
-        else:
-            fh = fip.contents.fh
-
-        return self.operations('flush', self._decode_optional_path(path), fh)
-
-    def release(self, path, fip):
-        if self.raw_fi:
-          fh = fip.contents
-        else:
-          fh = fip.contents.fh
-
-        return self.operations('release', self._decode_optional_path(path), fh)
-
-    def fsync(self, path, datasync, fip):
-        if self.raw_fi:
-            fh = fip.contents
-        else:
-            fh = fip.contents.fh
-
-        return self.operations('fsync', self._decode_optional_path(path), datasync,
-                                        fh)
-
-    def setxattr(self, path, name, value, size, options, *args):
-        return self.operations('setxattr', path.decode(self.encoding),
-                               name.decode(self.encoding),
-                               string_at(value, size), options, *args)
-
-    def getxattr(self, path, name, value, size, *args):
-        ret = self.operations('getxattr', path.decode(self.encoding),
-                                          name.decode(self.encoding), *args)
-
-        retsize = len(ret)
-        # allow size queries
-        if not value: return retsize
-
-        # do not truncate
-        if retsize > size: return -ERANGE
-
-        buf = create_string_buffer(ret, retsize)    # Does not add trailing 0
-        memmove(value, buf, retsize)
-
-        return retsize
-
-    def listxattr(self, path, namebuf, size):
-        attrs = self.operations('listxattr', path.decode(self.encoding)) or ''
-        ret = '\x00'.join(attrs).encode(self.encoding)
-        if len(ret) > 0:
-            ret += '\x00'.encode(self.encoding)
-
-        retsize = len(ret)
-        # allow size queries
-        if not namebuf: return retsize
-
-        # do not truncate
-        if retsize > size: return -ERANGE
-
-        buf = create_string_buffer(ret, retsize)
-        memmove(namebuf, buf, retsize)
-
-        return retsize
-
-    def removexattr(self, path, name):
-        return self.operations('removexattr', path.decode(self.encoding),
-                                              name.decode(self.encoding))
-
-    def opendir(self, path, fip):
-        # Ignore raw_fi
-        fip.contents.fh = self.operations('opendir',
-                                          path.decode(self.encoding))
-
-        return 0
-
-    def readdir(self, path, buf, filler, offset, fip):
-        # Ignore raw_fi
-        for item in self.operations('readdir', self._decode_optional_path(path),
-                                               fip.contents.fh):
-
-            if isinstance(item, basestring):
-                name, st, offset = item, None, 0
-            else:
-                name, attrs, offset = item
-                if attrs:
-                    st = c_stat()
-                    set_st_attrs(st, attrs)
-                else:
-                    st = None
-
-            if filler(buf, name.encode(self.encoding), st, offset) != 0:
-                break
-
-        return 0
-
-    def releasedir(self, path, fip):
-        # Ignore raw_fi
-        return self.operations('releasedir', self._decode_optional_path(path),
-                                             fip.contents.fh)
-
-    def fsyncdir(self, path, datasync, fip):
-        # Ignore raw_fi
-        return self.operations('fsyncdir', self._decode_optional_path(path),
-                                           datasync, fip.contents.fh)
-
-    def init(self, conn):
-        return self.operations('init', '/')
-
-    def destroy(self, private_data):
-        return self.operations('destroy', '/')
-
-    def access(self, path, amode):
-        return self.operations('access', path.decode(self.encoding), amode)
-
-    def create(self, path, mode, fip):
-        fi = fip.contents
-        path = path.decode(self.encoding)
-
-        if self.raw_fi:
-            return self.operations('create', path, mode, fi)
-        else:
-            # This line is different from upstream to fix issues
-            # reading file opened with O_CREAT|O_RDWR.
-            # See issue #143.
-            fi.fh = self.operations('create', path, mode, fi.flags)
-            # END OF MODIFICATION
-            return 0
-
-    def ftruncate(self, path, length, fip):
-        if self.raw_fi:
-            fh = fip.contents
-        else:
-            fh = fip.contents.fh
-
-        return self.operations('truncate', self._decode_optional_path(path),
-                                           length, fh)
-
-    def fgetattr(self, path, buf, fip):
-        memset(buf, 0, sizeof(c_stat))
-
-        st = buf.contents
-        if not fip:
-            fh = fip
-        elif self.raw_fi:
-            fh = fip.contents
-        else:
-            fh = fip.contents.fh
-
-        attrs = self.operations('getattr', self._decode_optional_path(path), fh)
-        set_st_attrs(st, attrs)
-        return 0
-
-    def lock(self, path, fip, cmd, lock):
-        if self.raw_fi:
-            fh = fip.contents
-        else:
-            fh = fip.contents.fh
-
-        return self.operations('lock', self._decode_optional_path(path), fh, cmd,
-                                       lock)
-
-    def utimens(self, path, buf):
-        if buf:
-            atime = time_of_timespec(buf.contents.actime)
-            mtime = time_of_timespec(buf.contents.modtime)
-            times = (atime, mtime)
-        else:
-            times = None
-
-        return self.operations('utimens', path.decode(self.encoding), times)
-
-    def bmap(self, path, blocksize, idx):
-        return self.operations('bmap', path.decode(self.encoding), blocksize,
-                                       idx)
-
-
-class Operations(object):
-    '''
-    This class should be subclassed and passed as an argument to FUSE on
-    initialization. All operations should raise a FuseOSError exception on
-    error.
-
-    When in doubt of what an operation should do, check the FUSE header file
-    or the corresponding system call man page.
-    '''
-
-    def __call__(self, op, *args):
-        if not hasattr(self, op):
-            raise FuseOSError(EFAULT)
-        return getattr(self, op)(*args)
-
-    def access(self, path, amode):
-        return 0
-
-    bmap = None
-
-    def chmod(self, path, mode):
-        raise FuseOSError(EROFS)
-
-    def chown(self, path, uid, gid):
-        raise FuseOSError(EROFS)
-
-    def create(self, path, mode, fi=None):
-        '''
-        When raw_fi is False (default case), fi is None and create should
-        return a numerical file handle.
-
-        When raw_fi is True the file handle should be set directly by create
-        and return 0.
-        '''
-
-        raise FuseOSError(EROFS)
-
-    def destroy(self, path):
-        'Called on filesystem destruction. Path is always /'
-
-        pass
-
-    def flush(self, path, fh):
-        return 0
-
-    def fsync(self, path, datasync, fh):
-        return 0
-
-    def fsyncdir(self, path, datasync, fh):
-        return 0
-
-    def getattr(self, path, fh=None):
-        '''
-        Returns a dictionary with keys identical to the stat C structure of
-        stat(2).
-
-        st_atime, st_mtime and st_ctime should be floats.
-
-        NOTE: There is an incombatibility between Linux and Mac OS X
-        concerning st_nlink of directories. Mac OS X counts all files inside
-        the directory, while Linux counts only the subdirectories.
-        '''
-
-        if path != '/':
-            raise FuseOSError(ENOENT)
-        return dict(st_mode=(S_IFDIR | 0o755), st_nlink=2)
-
-    def getxattr(self, path, name, position=0):
-        raise FuseOSError(ENOTSUP)
-
-    def init(self, path):
-        '''
-        Called on filesystem initialization. (Path is always /)
-
-        Use it instead of __init__ if you start threads on initialization.
-        '''
-
-        pass
-
-    def link(self, target, source):
-        'creates a hard link `target -> source` (e.g. ln source target)'
-
-        raise FuseOSError(EROFS)
-
-    def listxattr(self, path):
-        return []
-
-    lock = None
-
-    def mkdir(self, path, mode):
-        raise FuseOSError(EROFS)
-
-    def mknod(self, path, mode, dev):
-        raise FuseOSError(EROFS)
-
-    def open(self, path, flags):
-        '''
-        When raw_fi is False (default case), open should return a numerical
-        file handle.
-
-        When raw_fi is True the signature of open becomes:
-            open(self, path, fi)
-
-        and the file handle should be set directly.
-        '''
-
-        return 0
-
-    def opendir(self, path):
-        'Returns a numerical file handle.'
-
-        return 0
-
-    def read(self, path, size, offset, fh):
-        'Returns a string containing the data requested.'
-
-        raise FuseOSError(EIO)
-
-    def readdir(self, path, fh):
-        '''
-        Can return either a list of names, or a list of (name, attrs, offset)
-        tuples. attrs is a dict as in getattr.
-        '''
-
-        return ['.', '..']
-
-    def readlink(self, path):
-        raise FuseOSError(ENOENT)
-
-    def release(self, path, fh):
-        return 0
-
-    def releasedir(self, path, fh):
-        return 0
-
-    def removexattr(self, path, name):
-        raise FuseOSError(ENOTSUP)
-
-    def rename(self, old, new):
-        raise FuseOSError(EROFS)
-
-    def rmdir(self, path):
-        raise FuseOSError(EROFS)
-
-    def setxattr(self, path, name, value, options, position=0):
-        raise FuseOSError(ENOTSUP)
-
-    def statfs(self, path):
-        '''
-        Returns a dictionary with keys identical to the statvfs C structure of
-        statvfs(3).
-
-        On Mac OS X f_bsize and f_frsize must be a power of 2
-        (minimum 512).
-        '''
-
-        return {}
-
-    def symlink(self, target, source):
-        'creates a symlink `target -> source` (e.g. ln -s source target)'
-
-        raise FuseOSError(EROFS)
-
-    def truncate(self, path, length, fh=None):
-        raise FuseOSError(EROFS)
-
-    def unlink(self, path):
-        raise FuseOSError(EROFS)
-
-    def utimens(self, path, times=None):
-        'Times is a (atime, mtime) tuple. If None use current time.'
-
-        return 0
-
-    def write(self, path, data, offset, fh):
-        raise FuseOSError(EROFS)
-
-
-class LoggingMixIn:
-    log = logging.getLogger('fuse.log-mixin')
-
-    def __call__(self, op, path, *args):
-        self.log.debug('-> %s %s %s', op, path, repr(args))
-        ret = '[Unhandled Exception]'
-        try:
-            ret = getattr(self, op)(path, *args)
-            return ret
-        except OSError as e:
-            ret = str(e)
-            raise
-        finally:
-            self.log.debug('<- %s %s', op, repr(ret))
diff --git a/buildstream/_fuse/hardlinks.py b/buildstream/_fuse/hardlinks.py
index ff2e81e..8408de4 100644
--- a/buildstream/_fuse/hardlinks.py
+++ b/buildstream/_fuse/hardlinks.py
@@ -27,7 +27,7 @@ import shutil
 import stat
 import tempfile
 
-from .fuse import FuseOSError, Operations
+from fuse import FuseOSError, Operations
 
 from .mount import Mount
 
diff --git a/buildstream/_fuse/mount.py b/buildstream/_fuse/mount.py
index e316841..c8d6076 100644
--- a/buildstream/_fuse/mount.py
+++ b/buildstream/_fuse/mount.py
@@ -24,7 +24,7 @@ import sys
 
 from contextlib import contextmanager
 from multiprocessing import Process
-from .fuse import FUSE
+from fuse import FUSE
 
 from .._exceptions import ImplError
 from .. import _signals
diff --git a/setup.cfg b/setup.cfg
index 7d40c3d..ceb4507 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -22,7 +22,6 @@ pep8ignore =
     tmp/* ALL
     */lib/python3* ALL
     */bin/* ALL
-    buildstream/_fuse/fuse.py ALL
     .eggs/* ALL
     *_pb2.py ALL
     *_pb2_grpc.py ALL
diff --git a/setup.py b/setup.py
index 76610f0..0d3d314 100755
--- a/setup.py
+++ b/setup.py
@@ -343,6 +343,7 @@ setup(name='BuildStream',
           'jinja2 >= 2.10',
           'protobuf >= 3.5',
           'grpcio >= 1.10',
+          'fusepy >= 3.0.0',
       ],
       entry_points=bst_install_entry_points,
       tests_require=dev_requires,