mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-01-04 04:04:10 +00:00
Parameterize the Options class so we can synthesize an unhandled exception
This commit is contained in:
parent
2746eb9ae1
commit
a04a915628
@ -106,8 +106,7 @@ def parse_options(argv, config=None):
|
|||||||
config.parseOptions(argv) # may raise usage.error
|
config.parseOptions(argv) # may raise usage.error
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def parse_or_exit_with_explanation(argv, stdout=sys.stdout):
|
def parse_or_exit_with_explanation_with_config(config, argv, stdout, stderr):
|
||||||
config = Options()
|
|
||||||
try:
|
try:
|
||||||
parse_options(argv[1:], config=config)
|
parse_options(argv[1:], config=config)
|
||||||
except usage.error as e:
|
except usage.error as e:
|
||||||
@ -171,7 +170,7 @@ def _maybe_enable_eliot_logging(options, reactor):
|
|||||||
# Pass on the options so we can dispatch the subcommand.
|
# Pass on the options so we can dispatch the subcommand.
|
||||||
return options
|
return options
|
||||||
|
|
||||||
def run(argv=sys.argv, stderr=sys.stderr):
|
def run(configFactory=Options, argv=sys.argv, stdout=sys.stdout, stderr=sys.stderr):
|
||||||
# TODO(3035): Remove tox-check when error becomes a warning
|
# TODO(3035): Remove tox-check when error becomes a warning
|
||||||
if 'TOX_ENV_NAME' not in os.environ:
|
if 'TOX_ENV_NAME' not in os.environ:
|
||||||
assert sys.version_info < (3,), u"Tahoe-LAFS does not run under Python 3. Please use Python 2.7.x."
|
assert sys.version_info < (3,), u"Tahoe-LAFS does not run under Python 3. Please use Python 2.7.x."
|
||||||
@ -180,7 +179,15 @@ def run(argv=sys.argv, stderr=sys.stderr):
|
|||||||
from allmydata.windows.fixups import initialize
|
from allmydata.windows.fixups import initialize
|
||||||
initialize()
|
initialize()
|
||||||
# doesn't return: calls sys.exit(rc)
|
# doesn't return: calls sys.exit(rc)
|
||||||
task.react(lambda reactor: _run_with_reactor(reactor, argv, stderr))
|
task.react(
|
||||||
|
lambda reactor: _run_with_reactor(
|
||||||
|
reactor,
|
||||||
|
configFactory(),
|
||||||
|
argv,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _setup_coverage(reactor, argv):
|
def _setup_coverage(reactor, argv):
|
||||||
@ -223,13 +230,19 @@ def _setup_coverage(reactor, argv):
|
|||||||
reactor.addSystemEventTrigger('after', 'shutdown', write_coverage_data)
|
reactor.addSystemEventTrigger('after', 'shutdown', write_coverage_data)
|
||||||
|
|
||||||
|
|
||||||
def _run_with_reactor(reactor, argv, stderr):
|
def _run_with_reactor(reactor, config, argv, stdout, stderr):
|
||||||
|
|
||||||
_setup_coverage(reactor, argv)
|
_setup_coverage(reactor, argv)
|
||||||
|
|
||||||
d = defer.maybeDeferred(parse_or_exit_with_explanation, argv)
|
d = defer.maybeDeferred(
|
||||||
|
parse_or_exit_with_explanation_with_config,
|
||||||
|
config,
|
||||||
|
argv,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
)
|
||||||
d.addCallback(_maybe_enable_eliot_logging, reactor)
|
d.addCallback(_maybe_enable_eliot_logging, reactor)
|
||||||
d.addCallback(dispatch)
|
d.addCallback(dispatch, stdout=stdout, stderr=stderr)
|
||||||
def _show_exception(f):
|
def _show_exception(f):
|
||||||
# when task.react() notices a non-SystemExit exception, it does
|
# when task.react() notices a non-SystemExit exception, it does
|
||||||
# log.err() with the failure and then exits with rc=1. We want this
|
# log.err() with the failure and then exits with rc=1. We want this
|
||||||
|
@ -510,14 +510,13 @@ class CLI(CLITestMixin, unittest.TestCase):
|
|||||||
def test_exception_catcher(self):
|
def test_exception_catcher(self):
|
||||||
self.basedir = "cli/exception_catcher"
|
self.basedir = "cli/exception_catcher"
|
||||||
|
|
||||||
stderr = StringIO()
|
|
||||||
exc = Exception("canary")
|
exc = Exception("canary")
|
||||||
ns = Namespace()
|
class BrokenOptions(object):
|
||||||
|
def parseOptions(self, argv):
|
||||||
|
raise exc
|
||||||
|
|
||||||
ns.parse_called = False
|
stderr = StringIO()
|
||||||
def call_parse_or_exit(args):
|
ns = Namespace()
|
||||||
ns.parse_called = True
|
|
||||||
raise exc
|
|
||||||
|
|
||||||
ns.sys_exit_called = False
|
ns.sys_exit_called = False
|
||||||
def call_sys_exit(exitcode):
|
def call_sys_exit(exitcode):
|
||||||
@ -531,19 +530,17 @@ class CLI(CLITestMixin, unittest.TestCase):
|
|||||||
# it's safe to drop it on the floor.
|
# it's safe to drop it on the floor.
|
||||||
f(reactor)
|
f(reactor)
|
||||||
|
|
||||||
patcher = MonkeyPatcher((runner, 'parse_or_exit_with_explanation',
|
patcher = MonkeyPatcher((sys, 'exit', call_sys_exit),
|
||||||
call_parse_or_exit),
|
|
||||||
(sys, 'exit', call_sys_exit),
|
|
||||||
(task, 'react', fake_react),
|
(task, 'react', fake_react),
|
||||||
)
|
)
|
||||||
patcher.runWithPatches(
|
patcher.runWithPatches(
|
||||||
lambda: runner.run(
|
lambda: runner.run(
|
||||||
|
configFactory=BrokenOptions,
|
||||||
argv=["tahoe"],
|
argv=["tahoe"],
|
||||||
stderr=stderr,
|
stderr=stderr,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
self.failUnless(ns.parse_called)
|
|
||||||
self.failUnless(ns.sys_exit_called)
|
self.failUnless(ns.sys_exit_called)
|
||||||
self.failUnlessIn(str(exc), stderr.getvalue())
|
self.failUnlessIn(str(exc), stderr.getvalue())
|
||||||
|
|
||||||
|
@ -3,6 +3,9 @@ from __future__ import print_function
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import signal
|
import signal
|
||||||
|
from functools import (
|
||||||
|
partial,
|
||||||
|
)
|
||||||
from random import randrange
|
from random import randrange
|
||||||
from six.moves import StringIO
|
from six.moves import StringIO
|
||||||
from io import (
|
from io import (
|
||||||
@ -100,10 +103,20 @@ def run_cli_bytes(verb, *args, **kwargs):
|
|||||||
stdout = TextIOWrapper(BytesIO(), encoding)
|
stdout = TextIOWrapper(BytesIO(), encoding)
|
||||||
stderr = TextIOWrapper(BytesIO(), encoding)
|
stderr = TextIOWrapper(BytesIO(), encoding)
|
||||||
d = defer.succeed(argv)
|
d = defer.succeed(argv)
|
||||||
d.addCallback(runner.parse_or_exit_with_explanation, stdout=stdout)
|
d.addCallback(
|
||||||
d.addCallback(runner.dispatch,
|
partial(
|
||||||
stdin=StringIO(stdin),
|
runner.parse_or_exit_with_explanation_with_config,
|
||||||
stdout=stdout, stderr=stderr)
|
runner.Options(),
|
||||||
|
),
|
||||||
|
stdout=stdout,
|
||||||
|
stderr=stderr,
|
||||||
|
)
|
||||||
|
d.addCallback(
|
||||||
|
runner.dispatch,
|
||||||
|
stdin=StringIO(stdin),
|
||||||
|
stdout=stdout,
|
||||||
|
stderr=stderr,
|
||||||
|
)
|
||||||
def _done(rc):
|
def _done(rc):
|
||||||
return 0, _getvalue(stdout), _getvalue(stderr)
|
return 0, _getvalue(stdout), _getvalue(stderr)
|
||||||
def _err(f):
|
def _err(f):
|
||||||
|
Loading…
Reference in New Issue
Block a user