fuse: adjust for python 3 and test there
authorRob Browning <rlb@defaultvalue.org>
Thu, 2 Jan 2020 21:30:28 +0000 (15:30 -0600)
committerRob Browning <rlb@defaultvalue.org>
Sun, 2 Feb 2020 19:30:12 +0000 (13:30 -0600)
The python 3 version could have issues until the fuse module supports
binary data more completely (e.g. bytes paths), or until we switch to
some other foundation, but it may be OK even so (with some
inefficiency) given our bup-python iso-8859-1 hack.

Signed-off-by: Rob Browning <rlb@defaultvalue.org>
Tested-by: Rob Browning <rlb@defaultvalue.org>
Makefile
cmd/fuse-cmd.py
lib/bup/compat.py
t/test-fuse.sh

index 4c232f40b80d5fd8cb985335e4125026f686521c..50a34a9352b042022c88c77dbf24e7de07870f1a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -175,6 +175,7 @@ cmdline_tests := \
   t/test-compression.sh \
   t/test-drecurse.sh \
   t/test-fsck.sh \
+  t/test-fuse.sh \
   t/test-ftp \
   t/test-gc.sh \
   t/test-import-duplicity.sh \
@@ -205,7 +206,6 @@ cmdline_tests := \
 ifeq "2" "$(bup_python_majver)"
   cmdline_tests += \
     t/test-web.sh \
-    t/test-fuse.sh \
     t/test-index-check-device.sh \
     t/test-restore-map-owner.sh \
     t/test-xdev.sh
index 8e57ab6f937dab330f4f7fd6e5c4618e1812dfe6..dbc0cd1f8db5d6a5738c08f2a2f3f25c87b29b40 100755 (executable)
@@ -5,24 +5,44 @@ exec "$bup_python" "$0" ${1+"$@"}
 """
 # end of bup preamble
 
-from __future__ import absolute_import
+from __future__ import absolute_import, print_function
 import sys, os, errno
 
 try:
     import fuse
 except ImportError:
-    log('error: cannot find the python "fuse" module; please install it\n')
-    sys.exit(1)
+    print('error: cannot find the python "fuse" module; please install it',
+          file=sys.stderr)
+    sys.exit(2)
 if not hasattr(fuse, '__version__'):
-    raise RuntimeError('your fuse module is too old for fuse.__version__')
+    print('error: fuse module is too old for fuse.__version__', file=sys.stderr)
+    sys.exit(2)
 fuse.fuse_python_api = (0, 2)
 
+if sys.version_info[0] > 2:
+    try:
+        fuse_ver = fuse.__version__.split('.')
+        fuse_ver_maj = int(fuse_ver[0])
+    except:
+        log('error: cannot determine the fuse major version; please report',
+            file=sys.stderr)
+        sys.exit(2)
+    if len(fuse_ver) < 3 or fuse_ver_maj < 1:
+        print("error: fuse module can't handle binary data; please upgrade to 1.0+\n",
+              file=sys.stderr)
+        sys.exit(2)
+
 from bup import options, git, vfs, xstat
+from bup.compat import argv_bytes, fsdecode, py_maj
 from bup.helpers import log
 from bup.repo import LocalRepo
 
+
 # FIXME: self.meta and want_meta?
 
+# The path handling is just wrong, but the current fuse module can't
+# handle bytes paths.
+
 class BupFs(fuse.Fuse):
     def __init__(self, repo, verbose=0, fake_metadata=False):
         fuse.Fuse.__init__(self)
@@ -31,6 +51,7 @@ class BupFs(fuse.Fuse):
         self.fake_metadata = fake_metadata
     
     def getattr(self, path):
+        path = argv_bytes(path)
         global opt
         if self.verbose > 0:
             log('--getattr(%r)\n' % path)
@@ -56,6 +77,7 @@ class BupFs(fuse.Fuse):
         return st
 
     def readdir(self, path, offset):
+        path = argv_bytes(path)
         assert not offset  # We don't return offsets, so offset should be unused
         res = vfs.resolve(self.repo, path, follow=False)
         dir_name, dir_item = res[-1]
@@ -64,18 +86,21 @@ class BupFs(fuse.Fuse):
         yield fuse.Direntry('..')
         # FIXME: make sure want_meta=False is being completely respected
         for ent_name, ent_item in vfs.contents(repo, dir_item, want_meta=False):
-            yield fuse.Direntry(ent_name.replace('/', '-'))
+            fusename = fsdecode(ent_name.replace(b'/', b'-'))
+            yield fuse.Direntry(fusename)
 
     def readlink(self, path):
+        path = argv_bytes(path)
         if self.verbose > 0:
             log('--readlink(%r)\n' % path)
         res = vfs.resolve(self.repo, path, follow=False)
         name, item = res[-1]
         if not item:
             return -errno.ENOENT
-        return vfs.readlink(repo, item)
+        return fsdecode(vfs.readlink(repo, item))
 
     def open(self, path, flags):
+        path = argv_bytes(path)
         if self.verbose > 0:
             log('--open(%r)\n' % path)
         res = vfs.resolve(self.repo, path, follow=False)
@@ -90,6 +115,7 @@ class BupFs(fuse.Fuse):
         #return vfs.fopen(repo, item)
 
     def read(self, path, size, offset):
+        path = argv_bytes(path)
         if self.verbose > 0:
             log('--read(%r)\n' % path)
         res = vfs.resolve(self.repo, path, follow=False)
@@ -100,6 +126,7 @@ class BupFs(fuse.Fuse):
             f.seek(offset)
             return f.read(size)
 
+
 optspec = """
 bup fuse [-d] [-f] <mountpoint>
 --
@@ -111,6 +138,14 @@ v,verbose     increase log output (can be used more than once)
 """
 o = options.Options(optspec)
 opt, flags, extra = o.parse(sys.argv[1:])
+if not opt.verbose:
+    opt.verbose = 0
+
+# Set stderr to be line buffered, even if it's not connected to the console
+# so that we'll be able to see diagnostics in a timely fashion.
+errfd = sys.stderr.fileno()
+sys.stderr.flush()
+sys.stderr = os.fdopen(errfd, 'w', 1)
 
 if len(extra) != 1:
     o.fatal('only one mount point argument expected')
@@ -118,7 +153,10 @@ if len(extra) != 1:
 git.check_repo_or_die()
 repo = LocalRepo()
 f = BupFs(repo=repo, verbose=opt.verbose, fake_metadata=(not opt.meta))
+
+# This is likely wrong, but the fuse module doesn't currently accept bytes
 f.fuse_args.mountpoint = extra[0]
+
 if opt.debug:
     f.fuse_args.add('debug')
 if opt.foreground:
index 03041f35de9d08224edb18172137a87a2d69dd38..e59f4d3880642db6f05d183b30b1ec81707dbf19 100644 (file)
@@ -25,7 +25,7 @@ if py3:
               file=sys.stderr)
         sys.exit(2)
 
-    from os import fsencode
+    from os import fsdecode, fsencode
     from shlex import quote
     input = input
     range = range
@@ -76,6 +76,9 @@ if py3:
 
 else:  # Python 2
 
+    def fsdecode(x):
+        return x
+
     def fsencode(x):
         return x
 
index 1732d66f2b3c4b71de209e8dd335adf3ef787df8..1ed35542473f09db017633c4b04317d7bfd68c0e 100755 (executable)
@@ -41,7 +41,7 @@ savename()
 {
     readonly secs="$1"
     WVPASS bup-python -c "from time import strftime, localtime; \
-       print strftime('%Y-%m-%d-%H%M%S', localtime($secs))"
+       print(strftime('%Y-%m-%d-%H%M%S', localtime($secs)))"
 }
 
 export TZ=UTC
@@ -49,7 +49,7 @@ export TZ=UTC
 WVPASS bup init
 WVPASS cd "$tmpdir"
 
-savestamp1=$(WVPASS bup-python -c 'import time; print int(time.time())') || exit $?
+savestamp1=$(WVPASS bup-python -c 'import time; print(int(time.time()))') || exit $?
 savestamp2=$(($savestamp1 + 1))
 
 savename1="$(savename "$savestamp1")" || exit $?