From 01619844de3d51df3528f0b691962e4b7b865dc5 Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Tue, 26 May 2015 11:29:49 -0700 Subject: [PATCH] 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. --- src/allmydata/scripts/common.py | 28 +++++++++++++++++++++++++++- src/allmydata/scripts/runner.py | 8 ++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/allmydata/scripts/common.py b/src/allmydata/scripts/common.py index 2894d3dd..3ebb3e8c 100644 --- a/src/allmydata/scripts/common.py +++ b/src/allmydata/scripts/common.py @@ -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 diff --git a/src/allmydata/scripts/runner.py b/src/allmydata/scripts/runner.py index f295a980..4767e59e 100644 --- a/src/allmydata/scripts/runner.py +++ b/src/allmydata/scripts/runner.py @@ -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-options]" + def __str__(self): + return ("\nUsage: tahoe [global-options] [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 --help' for more details on each command.\n" def postOptions(self): -- 2.37.2