Changeset 51403 in webkit
- Timestamp:
- Nov 25, 2009 6:22:27 PM (14 years ago)
- Location:
- trunk/WebKitTools
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebKitTools/ChangeLog
r51399 r51403 1 2009-11-25 Eric Seidel <eric@webkit.org> 2 3 Reviewed by Adam Barth. 4 5 'bugzilla-tool help' should only show common commands like how 'git help' does 6 https://bugs.webkit.org/show_bug.cgi?id=31772 7 8 I also took this opportunity to make 'help' a real Command. 9 Making 'help' a real command required adding Command.tool (which we've wanted to do for a while). 10 11 * Scripts/bugzilla-tool: 12 - change should_show_command_help to should_show_in_main_help 13 * Scripts/modules/commands/download.py: 14 - Mark commands as being shown in main help or not. 15 - show_in_main_help = False is not required (default is false), 16 but it seemed to make the commands more self-documenting. 17 * Scripts/modules/commands/queries.py: ditto 18 * Scripts/modules/commands/queues.py: ditto 19 * Scripts/modules/commands/upload.py: ditto 20 * Scripts/modules/multicommandtool.py: 21 - Make Command hold a pointer to tool in self.tool. Most Command 22 subclasses do not take advantage of this yet, but it was required 23 for HelpCommand to be able to reach the tool from _help_epilog(). 24 - Move MultiCommandTool._standalone_help_for_command to Command.standalone_help 25 - Move MultiCommandTool._help_epilog to Command._help_epilog 26 - Move "help" logic into HelpCommand.execute() 27 - Change should_show_command_help to should_show_in_main_help and add a default implementation. 28 * Scripts/modules/multicommandtool_unittest.py: 29 - Test hiding of Commands in --help, and that all commands are shown in 'help --all-commands' 30 1 31 2009-11-25 Brian Weinstein <bweinstein@apple.com> 2 32 -
trunk/WebKitTools/Scripts/bugzilla-tool
r51287 r51403 72 72 return __file__ 73 73 74 def should_show_command_help(self, command): 74 def should_show_in_main_help(self, command): 75 if not command.show_in_main_help: 76 return False 75 77 if command.requires_local_commits: 76 78 return self.scm().supports_local_commits() -
trunk/WebKitTools/Scripts/modules/commands/download.py
r51383 r51403 68 68 class Build(Command): 69 69 name = "build" 70 show_in_main_help = False 70 71 def __init__(self): 71 72 options = WebKitLandingScripts.cleaning_options() … … 81 82 class ApplyAttachment(Command): 82 83 name = "apply-attachment" 84 show_in_main_help = True 83 85 def __init__(self): 84 86 options = WebKitApplyingScripts.apply_options() + WebKitLandingScripts.cleaning_options() … … 94 96 class ApplyPatches(Command): 95 97 name = "apply-patches" 98 show_in_main_help = True 96 99 def __init__(self): 97 100 options = WebKitApplyingScripts.apply_options() + WebKitLandingScripts.cleaning_options() … … 160 163 class LandDiff(Command): 161 164 name = "land-diff" 165 show_in_main_help = True 162 166 def __init__(self): 163 167 options = [ … … 256 260 class CheckStyle(AbstractPatchProcessingCommand): 257 261 name = "check-style" 262 show_in_main_help = False 258 263 def __init__(self): 259 264 options = WebKitLandingScripts.cleaning_options() … … 285 290 class BuildAttachment(AbstractPatchProcessingCommand): 286 291 name = "build-attachment" 292 show_in_main_help = False 287 293 def __init__(self): 288 294 options = WebKitLandingScripts.cleaning_options() … … 320 326 class LandAttachment(AbstractPatchLandingCommand): 321 327 name = "land-attachment" 328 show_in_main_help = True 322 329 def __init__(self): 323 330 AbstractPatchLandingCommand.__init__(self, "Land patches from bugzilla, optionally building and testing them first", "ATTACHMENT_ID [ATTACHMENT_IDS]") … … 329 336 class LandPatches(AbstractPatchLandingCommand): 330 337 name = "land-patches" 338 show_in_main_help = True 331 339 def __init__(self): 332 340 AbstractPatchLandingCommand.__init__(self, "Land all patches on the given bugs, optionally building and testing them first", "BUGID [BUGIDS]") … … 343 351 class Rollout(Command): 344 352 name = "rollout" 353 show_in_main_help = True 345 354 def __init__(self): 346 355 options = WebKitLandingScripts.cleaning_options() -
trunk/WebKitTools/Scripts/modules/commands/queries.py
r51287 r51403 57 57 class BugsToCommit(Command): 58 58 name = "bugs-to-commit" 59 show_in_main_help = False 59 60 def __init__(self): 60 61 Command.__init__(self, "List bugs in the commit-queue") … … 68 69 class PatchesToCommit(Command): 69 70 name = "patches-to-commit" 71 show_in_main_help = False 70 72 def __init__(self): 71 73 Command.__init__(self, "List patches in the commit-queue") … … 80 82 class ReviewedPatches(Command): 81 83 name = "reviewed-patches" 84 show_in_main_help = False 82 85 def __init__(self): 83 86 Command.__init__(self, "List r+'d patches on a bug", "BUGID") … … 92 95 class TreeStatus(Command): 93 96 name = "tree-status" 97 show_in_main_help = True 94 98 def __init__(self): 95 99 Command.__init__(self, "Print the status of the %s buildbots" % BuildBot.default_host) -
trunk/WebKitTools/Scripts/modules/commands/queues.py
r51287 r51403 111 111 class CommitQueue(AbstractQueue): 112 112 name = "commit-queue" 113 show_in_main_help = False 113 114 def __init__(self): 114 115 AbstractQueue.__init__(self) … … 167 168 class StyleQueue(AbstractTryQueue): 168 169 name = "style-queue" 170 show_in_main_help = False 169 171 def __init__(self): 170 172 AbstractTryQueue.__init__(self) … … 179 181 class BuildQueue(AbstractTryQueue): 180 182 name = "build-queue" 183 show_in_main_help = False 181 184 def __init__(self): 182 185 options = WebKitPort.port_options() -
trunk/WebKitTools/Scripts/modules/commands/upload.py
r51383 r51403 57 57 class CommitMessageForCurrentDiff(Command): 58 58 name = "commit-message" 59 show_in_main_help = False 59 60 def __init__(self): 60 61 Command.__init__(self, "Print a commit message suitable for the uncommitted changes") … … 67 68 class ObsoleteAttachments(Command): 68 69 name = "obsolete-attachments" 70 show_in_main_help = False 69 71 def __init__(self): 70 72 Command.__init__(self, "Mark all attachments on a bug as obsolete", "BUGID") … … 80 82 class PostDiff(Command): 81 83 name = "post-diff" 84 show_in_main_help = True 82 85 def __init__(self): 83 86 options = [ … … 121 124 class PostCommits(Command): 122 125 name = "post-commits" 126 show_in_main_help = True 123 127 def __init__(self): 124 128 options = [ … … 169 173 class CreateBug(Command): 170 174 name = "create-bug" 175 show_in_main_help = True 171 176 def __init__(self): 172 177 options = [ -
trunk/WebKitTools/Scripts/modules/multicommandtool.py
r51383 r51403 41 41 class Command(object): 42 42 name = None 43 # show_in_main_help = False # Subclasses must define show_in_main_help, we leave it out here to enforce that. 43 44 def __init__(self, help_text, argument_names=None, options=None, requires_local_commits=False): 44 45 self.help_text = help_text … … 48 49 self.option_parser = HelpPrintingOptionParser(usage=SUPPRESS_USAGE, add_help_option=False, option_list=self.options) 49 50 self.requires_local_commits = requires_local_commits 51 self.tool = None 52 53 # The tool calls bind_to_tool on each Command after adding it to its list. 54 def bind_to_tool(self, tool): 55 # Command instances can only be bound to one tool at a time. 56 if self.tool and tool != self.tool: 57 raise Exception("Command already bound to tool!") 58 self.tool = tool 50 59 51 60 @staticmethod … … 90 99 return self.execute(command_options, command_args, tool) or 0 91 100 101 def standalone_help(self): 102 help_text = self.name_with_arguments().ljust(len(self.name_with_arguments()) + 3) + self.help_text + "\n" 103 help_text += self.option_parser.format_option_help(IndentedHelpFormatter()) 104 return help_text 105 92 106 def execute(self, options, args, tool): 93 107 raise NotImplementedError, "subclasses must implement" … … 102 116 self.print_usage(sys.stderr) 103 117 error_message = "%s: error: %s\n" % (self.get_prog_name(), msg) 104 error_message += "\nType \" " + self.get_prog_name() + " --help\" to see usage.\n"118 error_message += "\nType \"%s --help\" to see usage.\n" % self.get_prog_name() 105 119 self.exit(1, error_message) 106 120 … … 113 127 114 128 129 class HelpCommand(Command): 130 name = "help" 131 show_in_main_help = False 132 133 def __init__(self): 134 options = [ 135 make_option("-a", "--all-commands", action="store_true", dest="show_all_commands", help="Print all available commands"), 136 ] 137 Command.__init__(self, "Display information about this program or its subcommands", "[COMMAND]", options=options) 138 self.show_all_commands = False # A hack used to pass --all-commands to _help_epilog even though it's called by the OptionParser. 139 140 def _help_epilog(self): 141 # Only show commands which are relevant to this checkout's SCM system. Might this be confusing to some users? 142 if self.show_all_commands: 143 epilog = "All %prog commands:\n" 144 relevant_commands = self.tool.commands[:] 145 else: 146 epilog = "Common %prog commands:\n" 147 relevant_commands = filter(self.tool.should_show_in_main_help, self.tool.commands) 148 longest_name_length = max(map(lambda command: len(command.name), relevant_commands)) 149 relevant_commands.sort(lambda a, b: cmp(a.name, b.name)) 150 command_help_texts = map(lambda command: " %s %s\n" % (command.name.ljust(longest_name_length), command.help_text), relevant_commands) 151 epilog += "%s\n" % "".join(command_help_texts) 152 epilog += "See '%prog help --all-commands' to list all commands.\n" 153 epilog += "See '%prog help COMMAND' for more information on a specific command.\n" 154 return self.tool.global_option_parser.expand_prog_name(epilog) 155 156 def execute(self, options, args, tool): 157 if args: 158 command = self.tool.command_by_name(args[0]) 159 if command: 160 print command.standalone_help() 161 return 0 162 163 self.show_all_commands = options.show_all_commands 164 tool.global_option_parser.print_help() 165 return 0 166 167 115 168 class MultiCommandTool(object): 116 169 def __init__(self, name=None, commands=None): 117 170 # Allow the unit tests to disable command auto-discovery. 118 171 self.commands = commands or [cls() for cls in self._find_all_commands() if cls.name] 119 self.global_option_parser = HelpPrintingOptionParser(epilog_method=self._help_epilog, prog=name, usage=self._usage_line()) 172 self.help_command = self.command_by_name(HelpCommand.name) 173 # Require a help command, even if the manual test list doesn't include one. 174 if not self.help_command: 175 self.help_command = HelpCommand() 176 self.commands.append(self.help_command) 177 for command in self.commands: 178 command.bind_to_tool(self) 179 self.global_option_parser = HelpPrintingOptionParser(epilog_method=self.help_command._help_epilog, prog=name, usage=self._usage_line()) 120 180 121 181 @classmethod … … 136 196 return "Usage: %prog [options] COMMAND [ARGS]" 137 197 138 @classmethod139 def _standalone_help_for_command(cls, command):140 help_text = command.name_with_arguments().ljust(len(command.name_with_arguments()) + 3) + command.help_text + "\n"141 help_text += command.option_parser.format_option_help(IndentedHelpFormatter())142 return help_text143 144 198 def name(self): 145 199 return self.global_option_parser.get_prog_name() 146 147 def _help_epilog(self):148 # Only show commands which are relevant to this checkout's SCM system. Might this be confusing to some users?149 relevant_commands = filter(self.should_show_command_help, self.commands)150 longest_name_length = max(map(lambda command: len(command.name), relevant_commands))151 relevant_commands.sort(lambda a, b: cmp(a.name, b.name))152 command_help_texts = map(lambda command: " %s %s\n" % (command.name.ljust(longest_name_length), command.help_text), relevant_commands)153 epilog = "%prog supports the following commands:\n"154 epilog += "%s\n" % "".join(command_help_texts)155 epilog += "See '%prog help COMMAND' for more information on a specific command.\n"156 return self.global_option_parser.expand_prog_name(epilog)157 200 158 201 def handle_global_args(self, args): … … 187 230 raise NotImplementedError, "subclasses must implement" 188 231 189 def should_show_ command_help(self, command):190 r aise NotImplementedError, "subclasses must implement"232 def should_show_in_main_help(self, command): 233 return command.show_in_main_help 191 234 192 235 def should_execute_command(self, command): … … 199 242 self.handle_global_args(global_args) 200 243 201 if not command_name: 202 self.global_option_parser.error("No command specified") 203 204 if command_name == "help": 205 if args_after_command_name: 206 command = self.command_by_name(args_after_command_name[0]) 207 log(self._standalone_help_for_command(command)) 208 else: 209 self.global_option_parser.print_help() 210 return 0 211 212 command = self.command_by_name(command_name) 244 command = self.command_by_name(command_name) or self.help_command 213 245 if not command: 214 246 self.global_option_parser.error("%s is not a recognized command" % command_name) -
trunk/WebKitTools/Scripts/modules/multicommandtool_unittest.py
r51383 r51403 36 36 class TrivialCommand(Command): 37 37 name = "trivial" 38 show_in_main_help = True 38 39 def __init__(self, **kwargs): 39 40 Command.__init__(self, "help text", **kwargs) … … 42 43 pass 43 44 45 class UncommonCommand(TrivialCommand): 46 name = "uncommon" 47 show_in_main_help = False 44 48 45 49 class CommandTest(unittest.TestCase): … … 77 81 return __file__ 78 82 79 def should_show_command_help(self, command):80 return True81 82 83 def should_execute_command(self, command): 83 return True84 return (True, None) 84 85 85 86 … … 108 109 self.assertEqual(tool.command_by_name("bar"), None) 109 110 111 def _assert_tool_main_outputs(self, tool, main_args, expected_stdout, expected_stderr = "", exit_code=0): 112 capture = OutputCapture() 113 capture.capture_output() 114 exit_code = tool.main(main_args) 115 (stdout_string, stderr_string) = capture.restore_output() 116 self.assertEqual(stdout_string, expected_stdout) 117 self.assertEqual(expected_stderr, expected_stderr) 118 119 def test_global_help(self): 120 tool = TrivialTool(commands=[TrivialCommand(), UncommonCommand()]) 121 expected_common_commands_help = """Usage: trivial-tool [options] COMMAND [ARGS] 122 123 Options: 124 -h, --help show this help message and exit 125 126 Common trivial-tool commands: 127 trivial help text 128 129 See 'trivial-tool help --all-commands' to list all commands. 130 See 'trivial-tool help COMMAND' for more information on a specific command. 131 132 """ 133 self._assert_tool_main_outputs(tool, ["tool", "help"], expected_common_commands_help) 134 expected_all_commands_help = """Usage: trivial-tool [options] COMMAND [ARGS] 135 136 Options: 137 -h, --help show this help message and exit 138 139 All trivial-tool commands: 140 help Display information about this program or its subcommands 141 trivial help text 142 uncommon help text 143 144 See 'trivial-tool help --all-commands' to list all commands. 145 See 'trivial-tool help COMMAND' for more information on a specific command. 146 147 """ 148 self._assert_tool_main_outputs(tool, ["tool", "help", "--all-commands"], expected_all_commands_help) 149 110 150 def test_command_help(self): 111 151 command_with_options = TrivialCommand(options=[make_option("--my_option")]) 112 152 tool = TrivialTool(commands=[command_with_options]) 113 114 capture = OutputCapture()115 capture.capture_output()116 exit_code = tool.main(["tool", "help", "trivial"])117 (stdout_string, stderr_string) = capture.restore_output()118 153 expected_subcommand_help = "trivial [options] help text\nOptions:\n --my_option=MY_OPTION\n\n" 119 self.assertEqual(exit_code, 0) 120 self.assertEqual(stdout_string, "") 121 self.assertEqual(stderr_string, expected_subcommand_help) 154 self._assert_tool_main_outputs(tool, ["tool", "help", "trivial"], expected_subcommand_help) 122 155 123 156
Note: See TracChangeset
for help on using the changeset viewer.