scripts: improve rendering of synopsis/usage

Subcommands "--help" is now rendered as:

```
 tahoe [global-options] COMMAND [options] ARGS
 (use 'tahoe --help' to view global options)
 USAGE (flags/options)
 DESCRIPTION
 DESCRIPTION_UNWRAPPED
```

The new .description and .description_unwrapped fields allow
commands (subclasses of twisted.python.usage.Usage) better control over
how their explanations are rendered: the old .longdesc field was wrapped
unpleasantly.
This commit is contained in:
Brian Warner 2015-05-26 11:29:49 -07:00
parent 5d5fa05a42
commit 01619844de
2 changed files with 33 additions and 3 deletions
src/allmydata/scripts

@ -1,5 +1,5 @@
import os, sys, urllib
import os, sys, urllib, textwrap
import codecs
from twisted.python import usage
from allmydata.util.assertutil import precondition
@ -10,6 +10,14 @@ from allmydata.scripts.default_nodedir import _default_nodedir
def get_default_nodedir():
return _default_nodedir
def wrap_paragraphs(text, width):
# like textwrap.wrap(), but preserve paragraphs (delimited by double
# newlines) and leading whitespace, and remove internal whitespace.
text = textwrap.dedent(text)
if text.startswith("\n"):
text = text[1:]
return "\n\n".join([textwrap.fill(paragraph, width=width)
for paragraph in text.split("\n\n")])
class BaseOptions(usage.Options):
def __init__(self):
@ -22,6 +30,24 @@ class BaseOptions(usage.Options):
def opt_version(self):
raise usage.UsageError("--version not allowed on subcommands")
description = None
description_unwrapped = None
def __str__(self):
width = int(os.environ.get('COLUMNS', '80'))
s = (self.getSynopsis() + '\n' +
"(use 'tahoe --help' to view global options)\n" +
'\n' +
self.getUsage())
if self.description:
s += '\n' + wrap_paragraphs(self.description, width) + '\n'
if self.description_unwrapped:
du = textwrap.dedent(self.description_unwrapped)
if du.startswith("\n"):
du = du[1:]
s += '\n' + du + '\n'
return s
class BasedirOptions(BaseOptions):
default_nodedir = _default_nodedir

@ -66,11 +66,15 @@ class Options(usage.Options):
print >>self.stdout, allmydata.get_package_versions_string(show_paths=True, debug=True)
self.no_command_needed = True
def getSynopsis(self):
return "\nUsage: tahoe [global-opts] <command> [command-options]"
def __str__(self):
return ("\nUsage: tahoe [global-options] <command> [command-options]\n"
+ self.getUsage())
synopsis = "\nUsage: tahoe [global-opts]" # used only for subcommands
def getUsage(self, **kwargs):
t = usage.Options.getUsage(self, **kwargs)
t = t.replace("Options:", "\nGlobal options:", 1)
return t + "\nPlease run 'tahoe <command> --help' for more details on each command.\n"
def postOptions(self):