Fix the help synopses of CLI commands to include [options] in the right place. fixes #1359, fixes #636

This commit is contained in:
david-sarah 2011-07-24 15:54:40 -07:00
parent f9d218c673
commit b978378392
5 changed files with 108 additions and 46 deletions

View File

@ -52,6 +52,10 @@ class VDriveOptions(BaseOptions):
class MakeDirectoryOptions(VDriveOptions): class MakeDirectoryOptions(VDriveOptions):
def parseArgs(self, where=""): def parseArgs(self, where=""):
self.where = argv_to_unicode(where) self.where = argv_to_unicode(where)
def getSynopsis(self):
return "Usage: %s mkdir [options] [REMOTE_DIR]" % (self.command_name,)
longdesc = """Create a new directory, either unlinked or as a subdirectory.""" longdesc = """Create a new directory, either unlinked or as a subdirectory."""
class AddAliasOptions(VDriveOptions): class AddAliasOptions(VDriveOptions):
@ -62,7 +66,7 @@ class AddAliasOptions(VDriveOptions):
self.cap = cap self.cap = cap
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s add-alias ALIAS[:] DIRCAP" % (os.path.basename(sys.argv[0]),) return "Usage: %s add-alias [options] ALIAS[:] DIRCAP" % (self.command_name,)
longdesc = """Add a new alias for an existing directory.""" longdesc = """Add a new alias for an existing directory."""
@ -73,11 +77,14 @@ class CreateAliasOptions(VDriveOptions):
self.alias = self.alias[:-1] self.alias = self.alias[:-1]
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s create-alias ALIAS[:]" % (os.path.basename(sys.argv[0]),) return "Usage: %s create-alias [options] ALIAS[:]" % (self.command_name,)
longdesc = """Create a new directory and add an alias for it.""" longdesc = """Create a new directory and add an alias for it."""
class ListAliasOptions(VDriveOptions): class ListAliasesOptions(VDriveOptions):
def getSynopsis(self):
return "Usage: %s list-aliases [options]" % (self.command_name,)
longdesc = """Display a table of all configured aliases.""" longdesc = """Display a table of all configured aliases."""
class ListOptions(VDriveOptions): class ListOptions(VDriveOptions):
@ -135,7 +142,7 @@ class GetOptions(VDriveOptions):
self.to_file = None self.to_file = None
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s get REMOTE_FILE LOCAL_FILE" % (os.path.basename(sys.argv[0]),) return "Usage: %s get [options] REMOTE_FILE LOCAL_FILE" % (self.command_name,)
longdesc = """ longdesc = """
Retrieve a file from the grid and write it to the local filesystem. If Retrieve a file from the grid and write it to the local filesystem. If
@ -174,7 +181,7 @@ class PutOptions(VDriveOptions):
self.from_file = None self.from_file = None
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s put LOCAL_FILE REMOTE_FILE" % (os.path.basename(sys.argv[0]),) return "Usage: %s put [options] LOCAL_FILE REMOTE_FILE" % (self.command_name,)
longdesc = """ longdesc = """
Put a file into the grid, copying its contents from the local filesystem. Put a file into the grid, copying its contents from the local filesystem.
@ -205,13 +212,16 @@ class CpOptions(VDriveOptions):
"When copying to local files, write out filecaps instead of actual " "When copying to local files, write out filecaps instead of actual "
"data (only useful for debugging and tree-comparison purposes)."), "data (only useful for debugging and tree-comparison purposes)."),
] ]
def parseArgs(self, *args): def parseArgs(self, *args):
if len(args) < 2: if len(args) < 2:
raise usage.UsageError("cp requires at least two arguments") raise usage.UsageError("cp requires at least two arguments")
self.sources = map(argv_to_unicode, args[:-1]) self.sources = map(argv_to_unicode, args[:-1])
self.destination = argv_to_unicode(args[-1]) self.destination = argv_to_unicode(args[-1])
def getSynopsis(self): def getSynopsis(self):
return "Usage: tahoe [options] cp FROM.. TO" return "Usage: tahoe cp [options] FROM.. TO"
longdesc = """ longdesc = """
Use 'tahoe cp' to copy files between a local filesystem and a Tahoe grid. Use 'tahoe cp' to copy files between a local filesystem and a Tahoe grid.
Any FROM/TO arguments that begin with an alias indicate Tahoe-side Any FROM/TO arguments that begin with an alias indicate Tahoe-side
@ -242,11 +252,11 @@ class RmOptions(VDriveOptions):
self.where = argv_to_unicode(where) self.where = argv_to_unicode(where)
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s rm REMOTE_FILE" % (os.path.basename(sys.argv[0]),) return "Usage: %s rm [options] REMOTE_FILE" % (self.command_name,)
class UnlinkOptions(RmOptions): class UnlinkOptions(RmOptions):
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s unlink REMOTE_FILE" % (os.path.basename(sys.argv[0]),) return "Usage: %s unlink [options] REMOTE_FILE" % (self.command_name,)
class MvOptions(VDriveOptions): class MvOptions(VDriveOptions):
def parseArgs(self, frompath, topath): def parseArgs(self, frompath, topath):
@ -254,7 +264,8 @@ class MvOptions(VDriveOptions):
self.to_file = argv_to_unicode(topath) self.to_file = argv_to_unicode(topath)
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s mv FROM TO" % (os.path.basename(sys.argv[0]),) return "Usage: %s mv [options] FROM TO" % (self.command_name,)
longdesc = """ longdesc = """
Use 'tahoe mv' to move files that are already on the grid elsewhere on Use 'tahoe mv' to move files that are already on the grid elsewhere on
the grid, e.g., 'tahoe mv alias:some_file alias:new_file'. the grid, e.g., 'tahoe mv alias:some_file alias:new_file'.
@ -273,7 +284,7 @@ class LnOptions(VDriveOptions):
self.to_file = argv_to_unicode(topath) self.to_file = argv_to_unicode(topath)
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s ln FROM_LINK TO_LINK" % (os.path.basename(sys.argv[0]),) return "Usage: %s ln [options] FROM_LINK TO_LINK" % (self.command_name,)
longdesc = """ longdesc = """
Use 'tahoe ln' to duplicate a link (directory entry) already on the grid Use 'tahoe ln' to duplicate a link (directory entry) already on the grid
@ -319,8 +330,8 @@ class BackupOptions(VDriveOptions):
self.from_dir = argv_to_unicode(localdir) self.from_dir = argv_to_unicode(localdir)
self.to_dir = argv_to_unicode(topath) self.to_dir = argv_to_unicode(topath)
def getSynopsis(Self): def getSynopsis(self):
return "Usage: %s backup FROM ALIAS:TO" % os.path.basename(sys.argv[0]) return "Usage: %s backup [options] FROM ALIAS:TO" % (self.command_name,)
def opt_exclude(self, pattern): def opt_exclude(self, pattern):
"""Ignore files matching a glob pattern. You may give multiple """Ignore files matching a glob pattern. You may give multiple
@ -378,7 +389,7 @@ class WebopenOptions(VDriveOptions):
self.where = argv_to_unicode(where) self.where = argv_to_unicode(where)
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s webopen [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),) return "Usage: %s webopen [options] [ALIAS:PATH]" % (self.command_name,)
longdesc = """Open a web browser to the contents of some file or longdesc = """Open a web browser to the contents of some file or
directory on the grid. When run without arguments, open the Welcome directory on the grid. When run without arguments, open the Welcome
@ -395,7 +406,7 @@ class ManifestOptions(VDriveOptions):
self.where = argv_to_unicode(where) self.where = argv_to_unicode(where)
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s manifest [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),) return "Usage: %s manifest [options] [ALIAS:PATH]" % (self.command_name,)
longdesc = """Print a list of all files and directories reachable from longdesc = """Print a list of all files and directories reachable from
the given starting point.""" the given starting point."""
@ -408,7 +419,7 @@ class StatsOptions(VDriveOptions):
self.where = argv_to_unicode(where) self.where = argv_to_unicode(where)
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s stats [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),) return "Usage: %s stats [options] [ALIAS:PATH]" % (self.command_name,)
longdesc = """Print statistics about of all files and directories longdesc = """Print statistics about of all files and directories
reachable from the given starting point.""" reachable from the given starting point."""
@ -424,7 +435,7 @@ class CheckOptions(VDriveOptions):
self.where = argv_to_unicode(where) self.where = argv_to_unicode(where)
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s check [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),) return "Usage: %s check [options] [ALIAS:PATH]" % (self.command_name,)
longdesc = """ longdesc = """
Check a single file or directory: count how many shares are available and Check a single file or directory: count how many shares are available and
@ -443,7 +454,7 @@ class DeepCheckOptions(VDriveOptions):
self.where = argv_to_unicode(where) self.where = argv_to_unicode(where)
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s deep-check [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),) return "Usage: %s deep-check [options] [ALIAS:PATH]" % (self.command_name,)
longdesc = """ longdesc = """
Check all files and directories reachable from the given starting point Check all files and directories reachable from the given starting point
@ -454,7 +465,7 @@ subCommands = [
["mkdir", None, MakeDirectoryOptions, "Create a new directory."], ["mkdir", None, MakeDirectoryOptions, "Create a new directory."],
["add-alias", None, AddAliasOptions, "Add a new alias cap."], ["add-alias", None, AddAliasOptions, "Add a new alias cap."],
["create-alias", None, CreateAliasOptions, "Create a new alias cap."], ["create-alias", None, CreateAliasOptions, "Create a new alias cap."],
["list-aliases", None, ListAliasOptions, "List all alias caps."], ["list-aliases", None, ListAliasesOptions, "List all alias caps."],
["ls", None, ListOptions, "List a directory."], ["ls", None, ListOptions, "List a directory."],
["get", None, GetOptions, "Retrieve a file from the grid."], ["get", None, GetOptions, "Retrieve a file from the grid."],
["put", None, PutOptions, "Upload a file into the grid."], ["put", None, PutOptions, "Upload a file into the grid."],

View File

@ -40,6 +40,12 @@ class BaseOptions(usage.Options):
_default_nodedir and (" [default for most commands: " + quote_output(_default_nodedir) + "]") or "")], _default_nodedir and (" [default for most commands: " + quote_output(_default_nodedir) + "]") or "")],
] ]
def __init__(self):
super(BaseOptions, self).__init__()
self.command_name = os.path.basename(sys.argv[0])
if self.command_name == 'trial':
self.command_name = 'tahoe'
def opt_version(self): def opt_version(self):
import allmydata import allmydata
print >>self.stdout, allmydata.get_package_versions_string(debug=True) print >>self.stdout, allmydata.get_package_versions_string(debug=True)

View File

@ -17,7 +17,7 @@ class CreateClientOptions(BasedirMixin, BaseOptions):
] ]
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s create-client [options] [NODEDIR]" % (os.path.basename(sys.argv[0]),) return "Usage: %s create-client [options] [NODEDIR]" % (self.command_name,)
class CreateNodeOptions(CreateClientOptions): class CreateNodeOptions(CreateClientOptions):
@ -26,7 +26,7 @@ class CreateNodeOptions(CreateClientOptions):
] ]
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s create-node [options] [NODEDIR]" % (os.path.basename(sys.argv[0]),) return "Usage: %s create-node [options] [NODEDIR]" % (self.command_name,)
class CreateIntroducerOptions(BasedirMixin, BaseOptions): class CreateIntroducerOptions(BasedirMixin, BaseOptions):
@ -37,7 +37,7 @@ class CreateIntroducerOptions(BasedirMixin, BaseOptions):
] ]
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s create-introducer [options] NODEDIR" % (os.path.basename(sys.argv[0]),) return "Usage: %s create-introducer [options] NODEDIR" % (self.command_name,)
client_tac = """ client_tac = """

View File

@ -13,12 +13,12 @@ class StartOptions(BasedirMixin, BaseOptions):
] ]
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s start [options] [NODEDIR]" % (os.path.basename(sys.argv[0]),) return "Usage: %s start [options] [NODEDIR]" % (self.command_name,)
class StopOptions(BasedirMixin, BaseOptions): class StopOptions(BasedirMixin, BaseOptions):
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s stop [options] [NODEDIR]" % (os.path.basename(sys.argv[0]),) return "Usage: %s stop [options] [NODEDIR]" % (self.command_name,)
class RestartOptions(BasedirMixin, BaseOptions): class RestartOptions(BasedirMixin, BaseOptions):
@ -28,7 +28,7 @@ class RestartOptions(BasedirMixin, BaseOptions):
] ]
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s restart [options] [NODEDIR]" % (os.path.basename(sys.argv[0]),) return "Usage: %s restart [options] [NODEDIR]" % (self.command_name,)
class RunOptions(BasedirMixin, BaseOptions): class RunOptions(BasedirMixin, BaseOptions):
@ -39,7 +39,7 @@ class RunOptions(BasedirMixin, BaseOptions):
] ]
def getSynopsis(self): def getSynopsis(self):
return "Usage: %s run [options] [NODEDIR]" % (os.path.basename(sys.argv[0]),) return "Usage: %s run [options] [NODEDIR]" % (self.command_name,)
def start(opts, out=sys.stdout, err=sys.stderr): def start(opts, out=sys.stdout, err=sys.stderr):

View File

@ -447,67 +447,112 @@ class CLI(CLITestMixin, unittest.TestCase):
class Help(unittest.TestCase): class Help(unittest.TestCase):
def test_get(self): def test_get(self):
help = str(cli.GetOptions()) help = str(cli.GetOptions())
self.failUnless("get REMOTE_FILE LOCAL_FILE" in help, help) self.failUnlessIn(" get [options] REMOTE_FILE LOCAL_FILE", help)
self.failUnless("% tahoe get FOO |less" in help, help) self.failUnlessIn("% tahoe get FOO |less", help)
def test_put(self): def test_put(self):
help = str(cli.PutOptions()) help = str(cli.PutOptions())
self.failUnless("put LOCAL_FILE REMOTE_FILE" in help, help) self.failUnlessIn(" put [options] LOCAL_FILE REMOTE_FILE", help)
self.failUnless("% cat FILE | tahoe put" in help, help) self.failUnlessIn("% cat FILE | tahoe put", help)
def test_unlink(self):
help = str(cli.UnlinkOptions())
self.failUnlessIn(" unlink [options] REMOTE_FILE", help)
def test_rm(self): def test_rm(self):
help = str(cli.RmOptions()) help = str(cli.RmOptions())
self.failUnless("rm REMOTE_FILE" in help, help) self.failUnlessIn(" rm [options] REMOTE_FILE", help)
def test_mv(self): def test_mv(self):
help = str(cli.MvOptions()) help = str(cli.MvOptions())
self.failUnless("mv FROM TO" in help, help) self.failUnlessIn(" mv [options] FROM TO", help)
self.failUnless("Use 'tahoe mv' to move files" in help) self.failUnlessIn("Use 'tahoe mv' to move files", help)
def test_cp(self):
help = str(cli.CpOptions())
self.failUnlessIn(" cp [options] FROM.. TO", help)
self.failUnlessIn("Use 'tahoe cp' to copy files", help)
def test_ln(self): def test_ln(self):
help = str(cli.LnOptions()) help = str(cli.LnOptions())
self.failUnless("ln FROM_LINK TO_LINK" in help, help) self.failUnlessIn(" ln [options] FROM_LINK TO_LINK", help)
self.failUnless("Use 'tahoe ln' to duplicate a link" in help) self.failUnlessIn("Use 'tahoe ln' to duplicate a link", help)
def test_mkdir(self):
help = str(cli.MakeDirectoryOptions())
self.failUnlessIn(" mkdir [options] [REMOTE_DIR]", help)
self.failUnlessIn("Create a new directory", help)
def test_backup(self): def test_backup(self):
help = str(cli.BackupOptions()) help = str(cli.BackupOptions())
self.failUnless("backup FROM ALIAS:TO" in help, help) self.failUnlessIn(" backup [options] FROM ALIAS:TO", help)
def test_webopen(self): def test_webopen(self):
help = str(cli.WebopenOptions()) help = str(cli.WebopenOptions())
self.failUnless("webopen [ALIAS:PATH]" in help, help) self.failUnlessIn(" webopen [options] [ALIAS:PATH]", help)
def test_manifest(self): def test_manifest(self):
help = str(cli.ManifestOptions()) help = str(cli.ManifestOptions())
self.failUnless("manifest [ALIAS:PATH]" in help, help) self.failUnlessIn(" manifest [options] [ALIAS:PATH]", help)
def test_stats(self): def test_stats(self):
help = str(cli.StatsOptions()) help = str(cli.StatsOptions())
self.failUnless("stats [ALIAS:PATH]" in help, help) self.failUnlessIn(" stats [options] [ALIAS:PATH]", help)
def test_check(self): def test_check(self):
help = str(cli.CheckOptions()) help = str(cli.CheckOptions())
self.failUnless("check [ALIAS:PATH]" in help, help) self.failUnlessIn(" check [options] [ALIAS:PATH]", help)
def test_deep_check(self): def test_deep_check(self):
help = str(cli.DeepCheckOptions()) help = str(cli.DeepCheckOptions())
self.failUnless("deep-check [ALIAS:PATH]" in help, help) self.failUnlessIn(" deep-check [options] [ALIAS:PATH]", help)
def test_create_alias(self): def test_create_alias(self):
help = str(cli.CreateAliasOptions()) help = str(cli.CreateAliasOptions())
self.failUnless("create-alias ALIAS[:]" in help, help) self.failUnlessIn(" create-alias [options] ALIAS[:]", help)
def test_add_aliases(self): def test_add_alias(self):
help = str(cli.AddAliasOptions()) help = str(cli.AddAliasOptions())
self.failUnless("add-alias ALIAS[:] DIRCAP" in help, help) self.failUnlessIn(" add-alias [options] ALIAS[:] DIRCAP", help)
def test_list_aliases(self):
help = str(cli.ListAliasesOptions())
self.failUnlessIn(" list-aliases [options]", help)
def test_start(self):
help = str(startstop_node.StartOptions())
self.failUnlessIn(" start [options] [NODEDIR]", help)
def test_stop(self):
help = str(startstop_node.StopOptions())
self.failUnlessIn(" stop [options] [NODEDIR]", help)
def test_restart(self):
help = str(startstop_node.RestartOptions())
self.failUnlessIn(" restart [options] [NODEDIR]", help)
def test_run(self):
help = str(startstop_node.RunOptions())
self.failUnlessIn(" run [options] [NODEDIR]", help)
def test_create_client(self):
help = str(create_node.CreateClientOptions())
self.failUnlessIn(" create-client [options] [NODEDIR]", help)
def test_create_node(self):
help = str(create_node.CreateNodeOptions())
self.failUnlessIn(" create-node [options] [NODEDIR]", help)
def test_create_introducer(self):
help = str(create_node.CreateIntroducerOptions())
self.failUnlessIn(" create-introducer [options] NODEDIR", help)
def test_debug_trial(self): def test_debug_trial(self):
help = str(debug.TrialOptions()) help = str(debug.TrialOptions())
self.failUnless("debug trial [options] [[file|package|module|TestCase|testmethod]...]" in help, help) self.failUnlessIn(" debug trial [options] [[file|package|module|TestCase|testmethod]...]", help)
self.failUnless("The 'tahoe debug trial' command uses the correct imports" in help, help) self.failUnlessIn("The 'tahoe debug trial' command uses the correct imports", help)
class CreateAlias(GridTestMixin, CLITestMixin, unittest.TestCase): class CreateAlias(GridTestMixin, CLITestMixin, unittest.TestCase):