Improve error reporting and help for start/stop/etc. commands.

Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
Daira Hopwood 2014-10-21 19:15:32 +01:00
parent 13ae872ace
commit fc886a7d02
6 changed files with 67 additions and 32 deletions

View File

@ -39,7 +39,7 @@ class BasedirOptions(BaseOptions):
default_nodedir = _default_nodedir default_nodedir = _default_nodedir
optParameters = [ optParameters = [
["basedir", "C", None, "Same as --node-directory (default %s)." ["basedir", "C", None, "Specify which Tahoe base directory should be used. [default: %s]"
% get_default_nodedir()], % get_default_nodedir()],
] ]
@ -67,6 +67,21 @@ class BasedirOptions(BaseOptions):
if not self['basedir']: if not self['basedir']:
raise usage.UsageError("A base directory for the node must be provided.") raise usage.UsageError("A base directory for the node must be provided.")
class NoDefaultBasedirOptions(BasedirOptions):
default_nodedir = None
optParameters = [
["basedir", "C", None, "Specify which Tahoe base directory should be used."],
]
# This is overridden in order to ensure we get a "Wrong number of arguments."
# error when more than one argument is given.
def parseArgs(self, basedir=None):
BasedirOptions.parseArgs(self, basedir)
def getSynopsis(self):
return "Usage: %s [global-opts] %s [options] NODEDIR" % (self.command_name, self.subcommand_name)
DEFAULT_ALIAS = u"tahoe" DEFAULT_ALIAS = u"tahoe"

View File

@ -1,6 +1,6 @@
import os, sys import os, sys
from allmydata.scripts.common import BasedirOptions from allmydata.scripts.common import BasedirOptions, NoDefaultBasedirOptions
from allmydata.util.assertutil import precondition from allmydata.util.assertutil import precondition
from allmydata.util.encodingutil import listdir_unicode, argv_to_unicode, quote_output from allmydata.util.encodingutil import listdir_unicode, argv_to_unicode, quote_output
import allmydata import allmydata
@ -19,6 +19,11 @@ class CreateClientOptions(BasedirOptions):
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s [global-opts] create-client [options] [NODEDIR]" % (self.command_name,) return "Usage: %s [global-opts] create-client [options] [NODEDIR]" % (self.command_name,)
# This is overridden in order to ensure we get a "Wrong number of arguments."
# error when more than one argument is given.
def parseArgs(self, basedir=None):
BasedirOptions.parseArgs(self, basedir)
class CreateNodeOptions(CreateClientOptions): class CreateNodeOptions(CreateClientOptions):
optFlags = [ optFlags = [
@ -29,11 +34,8 @@ class CreateNodeOptions(CreateClientOptions):
return "Usage: %s [global-opts] create-node [options] [NODEDIR]" % (self.command_name,) return "Usage: %s [global-opts] create-node [options] [NODEDIR]" % (self.command_name,)
class CreateIntroducerOptions(BasedirOptions): class CreateIntroducerOptions(NoDefaultBasedirOptions):
default_nodedir = None subcommand_name = "create-introducer"
def getSynopsis(self):
return "Usage: %s [global-opts] create-introducer [options] NODEDIR" % (self.command_name,)
client_tac = """ client_tac = """

View File

@ -1,14 +1,12 @@
import os, sys import os, sys
from allmydata.scripts.common import BasedirOptions from allmydata.scripts.common import NoDefaultBasedirOptions
from allmydata.util.assertutil import precondition from allmydata.util.assertutil import precondition
from allmydata.util.encodingutil import listdir_unicode, quote_output from allmydata.util.encodingutil import listdir_unicode, quote_output
class CreateKeyGeneratorOptions(BasedirOptions):
default_nodedir = None
def getSynopsis(self): class CreateKeyGeneratorOptions(NoDefaultBasedirOptions):
return "Usage: %s [global-opts] create-key-generator [options] NODEDIR" % (self.command_name,) subcommand_name = "create-key-generator"
keygen_tac = """ keygen_tac = """

View File

@ -8,30 +8,45 @@ from allmydata.util.encodingutil import listdir_unicode, quote_output
class StartOptions(BasedirOptions): class StartOptions(BasedirOptions):
subcommand_name = "start"
def parseArgs(self, basedir=None, *twistd_args): def parseArgs(self, basedir=None, *twistd_args):
# this can't handle e.g. 'tahoe start --nodaemon', since then # This can't handle e.g. 'tahoe start --nodaemon', since '--nodaemon'
# --nodaemon looks like a basedir. So you can either use 'tahoe # looks like an option to the tahoe subcommand, not to twistd.
# start' or 'tahoe start BASEDIR --TWISTD-OPTIONS'. # So you can either use 'tahoe start' or 'tahoe start NODEDIR --TWISTD-OPTIONS'.
# Note that 'tahoe --node-directory=NODEDIR start --TWISTD-OPTIONS' also
# isn't allowed, unfortunately.
BasedirOptions.parseArgs(self, basedir) BasedirOptions.parseArgs(self, basedir)
self.twistd_args = twistd_args self.twistd_args = twistd_args
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s [global-opts] start [options] [NODEDIR]" % (self.command_name,) return "Usage: %s [global-opts] %s [options] [NODEDIR [twistd-options]]" % (self.command_name, self.subcommand_name)
def getUsage(self, width=None):
t = BasedirOptions.getUsage(self, width) + "\n"
twistd_options = str(MyTwistdConfig()).partition("\n")[2].partition("\n\n")[0]
t += twistd_options.replace("Options:", "twistd-options:", 1)
t += """
Note that if any twistd-options are used, NODEDIR must be specified explicitly
(not by default or using -C/--basedir or -d/--node-directory), and followed by
the twistd-options.
"""
return t
class StopOptions(BasedirOptions): class StopOptions(BasedirOptions):
def parseArgs(self, basedir=None):
BasedirOptions.parseArgs(self, basedir)
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s [global-opts] stop [options] [NODEDIR]" % (self.command_name,) return "Usage: %s [global-opts] stop [options] [NODEDIR]" % (self.command_name,)
class RestartOptions(StartOptions): class RestartOptions(StartOptions):
def getSynopsis(self): subcommand_name = "restart"
return "Usage: %s [global-opts] restart [options] [NODEDIR]" % (self.command_name,)
class RunOptions(StartOptions): class RunOptions(StartOptions):
def getSynopsis(self): subcommand_name = "run"
return "Usage: %s [global-opts] run [options] [NODEDIR]" % (self.command_name,)
class MyTwistdConfig(twistd.ServerOptions): class MyTwistdConfig(twistd.ServerOptions):
@ -103,8 +118,8 @@ def start(config, out=sys.stdout, err=sys.stderr):
twistd_config.parseOptions(twistd_args) twistd_config.parseOptions(twistd_args)
except usage.error, ue: except usage.error, ue:
# these arguments were unsuitable for 'twistd' # these arguments were unsuitable for 'twistd'
print >>err, twistd_config print >>err, config
print >>err, "tahoe start: %s" % (config.subCommand, ue) print >>err, "tahoe %s: usage error from twistd: %s\n" % (config.subcommand_name, ue)
return 1 return 1
twistd_config.loadedPlugins = {"StartTahoeNode": StartTahoeNodePlugin(nodetype, basedir)} twistd_config.loadedPlugins = {"StartTahoeNode": StartTahoeNodePlugin(nodetype, basedir)}

View File

@ -1,14 +1,12 @@
import os, sys import os, sys
from allmydata.scripts.common import BasedirOptions from allmydata.scripts.common import NoDefaultBasedirOptions
from allmydata.util.assertutil import precondition from allmydata.util.assertutil import precondition
from allmydata.util.encodingutil import listdir_unicode, quote_output from allmydata.util.encodingutil import listdir_unicode, quote_output
class CreateStatsGathererOptions(BasedirOptions):
default_nodedir = None
def getSynopsis(self): class CreateStatsGathererOptions(NoDefaultBasedirOptions):
return "Usage: %s [global-opts] create-stats-gatherer [options] NODEDIR" % (self.command_name,) subcommand_name = "create-stats-gatherer"
stats_gatherer_tac = """ stats_gatherer_tac = """

View File

@ -646,7 +646,7 @@ class Help(unittest.TestCase):
def test_start(self): def test_start(self):
help = str(startstop_node.StartOptions()) help = str(startstop_node.StartOptions())
self.failUnlessIn(" [global-opts] start [options] [NODEDIR]", help) self.failUnlessIn(" [global-opts] start [options] [NODEDIR [twistd-options]]", help)
def test_stop(self): def test_stop(self):
help = str(startstop_node.StopOptions()) help = str(startstop_node.StopOptions())
@ -654,11 +654,11 @@ class Help(unittest.TestCase):
def test_restart(self): def test_restart(self):
help = str(startstop_node.RestartOptions()) help = str(startstop_node.RestartOptions())
self.failUnlessIn(" [global-opts] restart [options] [NODEDIR]", help) self.failUnlessIn(" [global-opts] restart [options] [NODEDIR [twistd-options]]", help)
def test_run(self): def test_run(self):
help = str(startstop_node.RunOptions()) help = str(startstop_node.RunOptions())
self.failUnlessIn(" [global-opts] run [options] [NODEDIR]", help) self.failUnlessIn(" [global-opts] run [options] [NODEDIR [twistd-options]]", help)
def test_create_client(self): def test_create_client(self):
help = str(create_node.CreateClientOptions()) help = str(create_node.CreateClientOptions())
@ -3869,6 +3869,9 @@ class Options(unittest.TestCase):
o = self.parse(["--node-directory", "there", "start"]) o = self.parse(["--node-directory", "there", "start"])
self.failUnlessEqual(o["basedir"], os.path.abspath("there")) self.failUnlessEqual(o["basedir"], os.path.abspath("there"))
o = self.parse(["start", "here", "--nodaemon"])
self.failUnlessEqual(o["basedir"], os.path.abspath("here"))
self.failUnlessRaises(usage.UsageError, self.parse, self.failUnlessRaises(usage.UsageError, self.parse,
["--basedir", "there", "start"]) ["--basedir", "there", "start"])
self.failUnlessRaises(usage.UsageError, self.parse, self.failUnlessRaises(usage.UsageError, self.parse,
@ -3886,3 +3889,7 @@ class Options(unittest.TestCase):
["--node-directory=there", ["--node-directory=there",
"start", "--basedir=here", "anywhere"]) "start", "--basedir=here", "anywhere"])
self.failUnlessRaises(usage.UsageError, self.parse,
["--node-directory=there", "start", "--nodaemon"])
self.failUnlessRaises(usage.UsageError, self.parse,
["start", "--basedir=here", "--nodaemon"])