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>
t/test-compression.sh \
t/test-drecurse.sh \
t/test-fsck.sh \
t/test-compression.sh \
t/test-drecurse.sh \
t/test-fsck.sh \
t/test-ftp \
t/test-gc.sh \
t/test-import-duplicity.sh \
t/test-ftp \
t/test-gc.sh \
t/test-import-duplicity.sh \
ifeq "2" "$(bup_python_majver)"
cmdline_tests += \
t/test-web.sh \
ifeq "2" "$(bup_python_majver)"
cmdline_tests += \
t/test-web.sh \
t/test-index-check-device.sh \
t/test-restore-map-owner.sh \
t/test-xdev.sh
t/test-index-check-device.sh \
t/test-restore-map-owner.sh \
t/test-xdev.sh
"""
# end of bup preamble
"""
# 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:
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__'):
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)
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 import options, git, vfs, xstat
+from bup.compat import argv_bytes, fsdecode, py_maj
from bup.helpers import log
from bup.repo import LocalRepo
from bup.helpers import log
from bup.repo import LocalRepo
# FIXME: self.meta and want_meta?
# 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)
class BupFs(fuse.Fuse):
def __init__(self, repo, verbose=0, fake_metadata=False):
fuse.Fuse.__init__(self)
self.fake_metadata = fake_metadata
def getattr(self, path):
self.fake_metadata = fake_metadata
def getattr(self, path):
+ path = argv_bytes(path)
global opt
if self.verbose > 0:
log('--getattr(%r)\n' % path)
global opt
if self.verbose > 0:
log('--getattr(%r)\n' % path)
return st
def readdir(self, path, offset):
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]
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]
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('..')
# 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):
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
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):
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)
if self.verbose > 0:
log('--open(%r)\n' % path)
res = vfs.resolve(self.repo, path, follow=False)
#return vfs.fopen(repo, item)
def read(self, path, size, offset):
#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)
if self.verbose > 0:
log('--read(%r)\n' % path)
res = vfs.resolve(self.repo, path, follow=False)
f.seek(offset)
return f.read(size)
f.seek(offset)
return f.read(size)
optspec = """
bup fuse [-d] [-f] <mountpoint>
--
optspec = """
bup fuse [-d] [-f] <mountpoint>
--
"""
o = options.Options(optspec)
opt, flags, extra = o.parse(sys.argv[1:])
"""
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')
if len(extra) != 1:
o.fatal('only one mount point argument expected')
git.check_repo_or_die()
repo = LocalRepo()
f = BupFs(repo=repo, verbose=opt.verbose, fake_metadata=(not opt.meta))
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]
f.fuse_args.mountpoint = extra[0]
if opt.debug:
f.fuse_args.add('debug')
if opt.foreground:
if opt.debug:
f.fuse_args.add('debug')
if opt.foreground:
file=sys.stderr)
sys.exit(2)
file=sys.stderr)
sys.exit(2)
- from os import fsencode
+ from os import fsdecode, fsencode
from shlex import quote
input = input
range = range
from shlex import quote
input = input
range = range
+ def fsdecode(x):
+ return x
+
def fsencode(x):
return x
def fsencode(x):
return x
{
readonly secs="$1"
WVPASS bup-python -c "from time import strftime, localtime; \
{
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)))"
WVPASS bup init
WVPASS cd "$tmpdir"
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 $?
savestamp2=$(($savestamp1 + 1))
savename1="$(savename "$savestamp1")" || exit $?