Merge PR161: add --ignore-unsendable-files flag for 'wormhole send'
closes #161 closes #112
This commit is contained in:
commit
10d2bea203
|
@ -10,7 +10,7 @@ from . import public_relay
|
|||
from .. import __version__
|
||||
from ..timing import DebugTiming
|
||||
from ..errors import (WrongPasswordError, WelcomeError, KeyFormatError,
|
||||
TransferError, NoTorError)
|
||||
TransferError, NoTorError, UnsendableFileError)
|
||||
from twisted.internet.defer import inlineCallbacks, maybeDeferred
|
||||
from twisted.python.failure import Failure
|
||||
from twisted.internet.task import react
|
||||
|
@ -109,7 +109,7 @@ def _dispatch_command(reactor, cfg, command):
|
|||
msg = fill("ERROR: " + dedent(e.__doc__))
|
||||
print(msg, file=cfg.stderr)
|
||||
raise SystemExit(1)
|
||||
except WelcomeError as e:
|
||||
except (WelcomeError, UnsendableFileError) as e:
|
||||
msg = fill("ERROR: " + dedent(e.__doc__))
|
||||
print(msg, file=cfg.stderr)
|
||||
print(six.u(""), file=cfg.stderr)
|
||||
|
@ -173,6 +173,10 @@ TorArgs = _compose(
|
|||
"--text", default=None, metavar="MESSAGE",
|
||||
help="text message to send, instead of a file. Use '-' to read from stdin.",
|
||||
)
|
||||
@click.option(
|
||||
"--ignore-unsendable-files", default=False, is_flag=True,
|
||||
help="Don't raise an error if a file can't be read."
|
||||
)
|
||||
@click.argument("what", required=False)
|
||||
@click.pass_obj
|
||||
def send(cfg, **kwargs):
|
||||
|
|
|
@ -6,7 +6,8 @@ from twisted.python import log
|
|||
from twisted.protocols import basic
|
||||
from twisted.internet import reactor
|
||||
from twisted.internet.defer import inlineCallbacks, returnValue
|
||||
from ..errors import TransferError, WormholeClosedError, NoTorError
|
||||
from ..errors import (TransferError, WormholeClosedError, NoTorError,
|
||||
UnsendableFileError)
|
||||
from wormhole import create, __version__
|
||||
from ..transit import TransitSender
|
||||
from ..util import dict_to_bytes, bytes_to_dict, bytes_to_hexstr
|
||||
|
@ -274,9 +275,17 @@ class Sender:
|
|||
for fn in files:
|
||||
archivename = os.path.join(*tuple(localpath+[fn]))
|
||||
localfilename = os.path.join(path, fn)
|
||||
zf.write(localfilename, archivename)
|
||||
num_bytes += os.stat(localfilename).st_size
|
||||
num_files += 1
|
||||
try:
|
||||
zf.write(localfilename, archivename)
|
||||
num_bytes += os.stat(localfilename).st_size
|
||||
num_files += 1
|
||||
except OSError as e:
|
||||
errmsg = u"{}: {}".format(fn, e.strerror)
|
||||
if self._args.ignore_unsendable_files:
|
||||
print(u"{} (ignoring error)".format(errmsg),
|
||||
file=args.stderr)
|
||||
else:
|
||||
raise UnsendableFileError(errmsg)
|
||||
fd_to_send.seek(0,2)
|
||||
filesize = fd_to_send.tell()
|
||||
fd_to_send.seek(0,0)
|
||||
|
|
|
@ -3,6 +3,16 @@ from __future__ import unicode_literals
|
|||
class WormholeError(Exception):
|
||||
"""Parent class for all wormhole-related errors"""
|
||||
|
||||
class UnsendableFileError(Exception):
|
||||
"""
|
||||
A file you wanted to send couldn't be read, maybe because it's not
|
||||
a file, or because it's a symlink that points to something
|
||||
that doesn't exist.
|
||||
|
||||
To ignore this kind of error, you can run wormhole with the
|
||||
--ignore-unsendable-files flag.
|
||||
"""
|
||||
|
||||
class ServerError(WormholeError):
|
||||
"""The relay server complained about something we did."""
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@ from twisted.internet.defer import gatherResults, inlineCallbacks, returnValue
|
|||
from .. import __version__
|
||||
from .common import ServerBase, config
|
||||
from ..cli import cmd_send, cmd_receive, welcome, cli
|
||||
from ..errors import TransferError, WrongPasswordError, WelcomeError
|
||||
from ..errors import (TransferError, WrongPasswordError, WelcomeError,
|
||||
UnsendableFileError)
|
||||
from wormhole.server.cmd_server import MyPlugin
|
||||
from wormhole.server.cli import server
|
||||
|
||||
|
@ -65,6 +66,40 @@ class OfferData(unittest.TestCase):
|
|||
self.assertEqual(fd_to_send.tell(), 0)
|
||||
self.assertEqual(fd_to_send.read(), message)
|
||||
|
||||
def _create_broken_symlink(self):
|
||||
if not hasattr(os, 'symlink'):
|
||||
raise unittest.SkipTest("host OS does not support symlinks")
|
||||
|
||||
parent_dir = self.mktemp()
|
||||
os.mkdir(parent_dir)
|
||||
send_dir = "dirname"
|
||||
os.mkdir(os.path.join(parent_dir, send_dir))
|
||||
os.symlink('/non/existent/file',
|
||||
os.path.join(parent_dir, send_dir, 'linky'))
|
||||
|
||||
send_dir_arg = send_dir
|
||||
self.cfg.what = send_dir_arg
|
||||
self.cfg.cwd = parent_dir
|
||||
|
||||
def test_broken_symlink_raises_err(self):
|
||||
self._create_broken_symlink()
|
||||
self.cfg.ignore_unsendable_files = False
|
||||
e = self.assertRaises(UnsendableFileError, build_offer, self.cfg)
|
||||
|
||||
# On english distributions of Linux, this will be
|
||||
# "linky: No such file or directory", but the error may be
|
||||
# different on Windows and other locales and/or Unix variants, so
|
||||
# we'll just assert the part we know about.
|
||||
self.assertIn("linky: ", str(e))
|
||||
|
||||
def test_broken_symlink_is_ignored(self):
|
||||
self._create_broken_symlink()
|
||||
self.cfg.ignore_unsendable_files = True
|
||||
d, fd_to_send = build_offer(self.cfg)
|
||||
self.assertIn('(ignoring error)', self.cfg.stderr.getvalue())
|
||||
self.assertEqual(d['directory']['numfiles'], 0)
|
||||
self.assertEqual(d['directory']['numbytes'], 0)
|
||||
|
||||
def test_missing_file(self):
|
||||
self.cfg.what = filename = "missing"
|
||||
send_dir = self.mktemp()
|
||||
|
|
Loading…
Reference in New Issue
Block a user