[SCM] WebKit Debian packaging branch, webkit-1.2, updated. upstream/1.1.90-6072-g9a69373

eric at webkit.org eric at webkit.org
Wed Apr 7 23:50:56 UTC 2010


The following commit has been merged in the webkit-1.2 branch:
commit 911f5a2dcd9c10e24a35ad0d78f7029b4b5ca0e7
Author: eric at webkit.org <eric at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Fri Nov 20 00:55:19 2009 +0000

    2009-11-19  Eric Seidel  <eric at webkit.org>
    
            Reviewed by Adam Barth.
    
            Move MultiCommandTool and Command into a separate file and add some basic unit tests
            https://bugs.webkit.org/show_bug.cgi?id=31695
    
            * Scripts/bugzilla-tool:
            * Scripts/modules/multicommandtool.py: Added.
            * Scripts/modules/multicommandtool_unittest.py: Added.
            * Scripts/run-webkit-unittests:
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@51223 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog
index 77eb3c1..e53e7ac 100644
--- a/WebKitTools/ChangeLog
+++ b/WebKitTools/ChangeLog
@@ -1,5 +1,17 @@
 2009-11-19  Eric Seidel  <eric at webkit.org>
 
+        Reviewed by Adam Barth.
+
+        Move MultiCommandTool and Command into a separate file and add some basic unit tests
+        https://bugs.webkit.org/show_bug.cgi?id=31695
+
+        * Scripts/bugzilla-tool:
+        * Scripts/modules/multicommandtool.py: Added.
+        * Scripts/modules/multicommandtool_unittest.py: Added.
+        * Scripts/run-webkit-unittests:
+
+2009-11-19  Eric Seidel  <eric at webkit.org>
+
         No review, just adding a FIXME.
 
         Split out command parsing and help printing from BugzillaTool
diff --git a/WebKitTools/Scripts/bugzilla-tool b/WebKitTools/Scripts/bugzilla-tool
index 3bbbc95..ce2a78d 100755
--- a/WebKitTools/Scripts/bugzilla-tool
+++ b/WebKitTools/Scripts/bugzilla-tool
@@ -38,19 +38,21 @@ import sys
 import time
 
 from datetime import datetime, timedelta
-from optparse import OptionParser, IndentedHelpFormatter, SUPPRESS_USAGE, make_option
+from optparse import make_option
 
 # Import WebKit-specific modules.
 from modules.bugzilla import Bugzilla, parse_bug_id
+from modules.buildbot import BuildBot
 from modules.changelogs import ChangeLog
 from modules.comments import bug_comment_from_commit_text
 from modules.logging import error, log, tee
+from modules.multicommandtool import MultiCommandTool, Command
 from modules.patchcollection import PatchCollection
 from modules.scm import CommitMessage, detect_scm_system, ScriptError, CheckoutNeedsUpdate
-from modules.buildbot import BuildBot
 from modules.statusbot import StatusBot
 from modules.workqueue import WorkQueue, WorkQueueDelegate
 
+
 def plural(noun):
     # This is a dumb plural() implementation which was just enough for our uses.
     if re.search("h$", noun):
@@ -82,29 +84,6 @@ def commit_message_for_this_commit(scm):
     return CommitMessage("".join(changelog_messages).splitlines())
 
 
-class Command:
-    def __init__(self, help_text, argument_names="", options=[], requires_local_commits=False):
-        self.help_text = help_text
-        self.argument_names = argument_names
-        self.options = options
-        self.option_parser = HelpPrintingOptionParser(usage=SUPPRESS_USAGE, add_help_option=False, option_list=self.options)
-        self.requires_local_commits = requires_local_commits
-
-    def name_with_arguments(self, command_name):
-        usage_string = command_name
-        if len(self.options) > 0:
-            usage_string += " [options]"
-        if self.argument_names:
-            usage_string += " " + self.argument_names
-        return usage_string
-
-    def parse_args(self, args):
-        return self.option_parser.parse_args(args)
-
-    def execute(self, options, args, tool):
-        raise NotImplementedError, "subclasses must implement"
-
-
 class BugsToCommit(Command):
     def __init__(self):
         Command.__init__(self, "Bugs in the commit queue")
@@ -834,119 +813,6 @@ class StyleQueue(AbstractQueue):
         log(message)
 
 
-class NonWrappingEpilogIndentedHelpFormatter(IndentedHelpFormatter):
-    def __init__(self):
-        IndentedHelpFormatter.__init__(self)
-
-    # The standard IndentedHelpFormatter paragraph-wraps the epilog, killing our custom formatting.
-    def format_epilog(self, epilog):
-        if epilog:
-            return "\n" + epilog + "\n"
-        return ""
-
-
-class HelpPrintingOptionParser(OptionParser):
-    def error(self, msg):
-        self.print_usage(sys.stderr)
-        error_message = "%s: error: %s\n" % (self.get_prog_name(), msg)
-        error_message += "\nType \"" + self.get_prog_name() + " --help\" to see usage.\n"
-        self.exit(2, error_message)
-
-
-class MultiCommandTool:
-    def __init__(self, commands):
-        self.commands = commands
-        # FIXME: Calling self._commands_usage() in the constructor is bad because
-        # it calls self.should_show_command_help which is subclass-defined.
-        # The subclass will not be fully initialized at this point.
-        self.global_option_parser = HelpPrintingOptionParser(usage=self._usage_line(), formatter=NonWrappingEpilogIndentedHelpFormatter(), epilog=self._commands_usage())
-
-    @staticmethod
-    def _usage_line():
-        return "Usage: %prog [options] command [command-options] [command-arguments]"
-
-    # FIXME: This can all be simplified once Command objects know their own names.
-    @staticmethod
-    def _name_and_arguments(command):
-        return command['object'].name_with_arguments(command["name"])
-
-    def _command_help_formatter(self):
-        # Use our own help formatter so as to indent enough.
-        formatter = IndentedHelpFormatter()
-        formatter.indent()
-        formatter.indent()
-        return formatter
-
-    @classmethod
-    def _help_for_command(cls, command, formatter, longest_name_length):
-        help_text = "  " + cls._name_and_arguments(command).ljust(longest_name_length + 3) + command['object'].help_text + "\n"
-        help_text += command['object'].option_parser.format_option_help(formatter)
-        return help_text
-
-    def _commands_usage(self):
-        # Only show commands which are relevant to this checkout.  This might be confusing to some users?
-        relevant_commands = filter(self.should_show_command_help, self.commands)
-        longest_name_length = max(map(lambda command: len(self._name_and_arguments(command)), relevant_commands))
-        command_help_texts = map(lambda command: self._help_for_command(command, self._command_help_formatter(), longest_name_length), relevant_commands)
-        return "Commands:\n" + "".join(command_help_texts)
-
-    def handle_global_args(self, args):
-        (options, args) = self.global_option_parser.parse_args(args)
-        if len(args):
-            # We'll never hit this because _split_args splits at the first arg without a leading "-"
-            self.global_option_parser.error("Extra arguments before command: " + args)
-
-    @staticmethod
-    def _split_args(args):
-        # Assume the first argument which doesn't start with "-" is the command name.
-        command_index = 0
-        for arg in args:
-            if arg[0] != "-":
-                break
-            command_index += 1
-        else:
-            return (args[:], None, [])
-
-        global_args = args[:command_index]
-        command = args[command_index]
-        command_args = args[command_index + 1:]
-        return (global_args, command, command_args)
-
-    def command_by_name(self, command_name):
-        for command in self.commands:
-            if command_name == command["name"]:
-                return command
-        return None
-
-    def should_show_command_help(self, command):
-        raise NotImplementedError, "subclasses must implement"
-
-    def should_execute_command(self, command):
-        raise NotImplementedError, "subclasses must implement"
-
-    def main(self):
-        (global_args, command_name, args_after_command_name) = self._split_args(sys.argv[1:])
-
-        # Handle --help, etc:
-        self.handle_global_args(global_args)
-
-        if not command_name:
-            self.global_option_parser.error("No command specified")
-
-        command = self.command_by_name(command_name)
-        if not command:
-            self.global_option_parser.error(command_name + " is not a recognized command")
-
-        command_object = command["object"]
-
-        (should_execute, failure_reason) = self.should_execute_command(command)
-        if not should_execute:
-            error(failure_reason)
-
-        (command_options, command_args) = command_object.parse_args(args_after_command_name)
-        return command_object.execute(command_options, command_args, self)
-
-
 class BugzillaTool(MultiCommandTool):
     def __init__(self):
         # HACK: Set self.cached_scm before calling MultiCommandTool.__init__ because
diff --git a/WebKitTools/Scripts/modules/multicommandtool.py b/WebKitTools/Scripts/modules/multicommandtool.py
new file mode 100644
index 0000000..6e1d661
--- /dev/null
+++ b/WebKitTools/Scripts/modules/multicommandtool.py
@@ -0,0 +1,167 @@
+# Copyright (c) 2009, Google Inc. All rights reserved.
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# 
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# MultiCommandTool provides a framework for writing svn-like/git-like tools
+# which are called with the following format:
+# tool-name [global options] command-name [command options]
+
+import sys
+
+from optparse import OptionParser, IndentedHelpFormatter, SUPPRESS_USAGE, make_option
+
+class Command:
+    def __init__(self, help_text, argument_names=None, options=None, requires_local_commits=False):
+        self.help_text = help_text
+        self.argument_names = argument_names
+        self.options = options
+        self.option_parser = HelpPrintingOptionParser(usage=SUPPRESS_USAGE, add_help_option=False, option_list=self.options)
+        self.requires_local_commits = requires_local_commits
+
+    def name_with_arguments(self, command_name):
+        usage_string = command_name
+        if self.options:
+            usage_string += " [options]"
+        if self.argument_names:
+            usage_string += " " + self.argument_names
+        return usage_string
+
+    def parse_args(self, args):
+        return self.option_parser.parse_args(args)
+
+    def execute(self, options, args, tool):
+        raise NotImplementedError, "subclasses must implement"
+
+
+class NonWrappingEpilogIndentedHelpFormatter(IndentedHelpFormatter):
+    # The standard IndentedHelpFormatter paragraph-wraps the epilog, killing our custom formatting.
+    def format_epilog(self, epilog):
+        if epilog:
+            return "\n" + epilog + "\n"
+        return ""
+
+
+class HelpPrintingOptionParser(OptionParser):
+    def error(self, msg):
+        self.print_usage(sys.stderr)
+        error_message = "%s: error: %s\n" % (self.get_prog_name(), msg)
+        error_message += "\nType \"" + self.get_prog_name() + " --help\" to see usage.\n"
+        self.exit(1, error_message)
+
+
+class MultiCommandTool:
+    def __init__(self, commands):
+        self.commands = commands
+        # FIXME: Calling self._commands_usage() in the constructor is bad because
+        # it calls self.should_show_command_help which is subclass-defined.
+        # The subclass will not be fully initialized at this point.
+        self.global_option_parser = HelpPrintingOptionParser(usage=self._usage_line(), formatter=NonWrappingEpilogIndentedHelpFormatter(), epilog=self._commands_usage())
+
+    @staticmethod
+    def _usage_line():
+        return "Usage: %prog [options] command [command-options] [command-arguments]"
+
+    # FIXME: This can all be simplified once Command objects know their own names.
+    @staticmethod
+    def _name_and_arguments(command):
+        return command['object'].name_with_arguments(command["name"])
+
+    def _command_help_formatter(self):
+        # Use our own help formatter so as to indent enough.
+        formatter = IndentedHelpFormatter()
+        formatter.indent()
+        formatter.indent()
+        return formatter
+
+    @classmethod
+    def _help_for_command(cls, command, formatter, longest_name_length):
+        help_text = "  " + cls._name_and_arguments(command).ljust(longest_name_length + 3) + command['object'].help_text + "\n"
+        help_text += command['object'].option_parser.format_option_help(formatter)
+        return help_text
+
+    def _commands_usage(self):
+        # Only show commands which are relevant to this checkout.  This might be confusing to some users?
+        relevant_commands = filter(self.should_show_command_help, self.commands)
+        longest_name_length = max(map(lambda command: len(self._name_and_arguments(command)), relevant_commands))
+        command_help_texts = map(lambda command: self._help_for_command(command, self._command_help_formatter(), longest_name_length), relevant_commands)
+        return "Commands:\n" + "".join(command_help_texts)
+
+    def handle_global_args(self, args):
+        (options, args) = self.global_option_parser.parse_args(args)
+        # We should never hit this because _split_args splits at the first arg without a leading "-".
+        if args:
+            self.global_option_parser.error("Extra arguments before command: " + args)
+
+    @staticmethod
+    def _split_args(args):
+        # Assume the first argument which doesn't start with "-" is the command name.
+        command_index = 0
+        for arg in args:
+            if arg[0] != "-":
+                break
+            command_index += 1
+        else:
+            return (args[:], None, [])
+
+        global_args = args[:command_index]
+        command = args[command_index]
+        command_args = args[command_index + 1:]
+        return (global_args, command, command_args)
+
+    def command_by_name(self, command_name):
+        for command in self.commands:
+            if command_name == command["name"]:
+                return command
+        return None
+
+    def should_show_command_help(self, command):
+        raise NotImplementedError, "subclasses must implement"
+
+    def should_execute_command(self, command):
+        raise NotImplementedError, "subclasses must implement"
+
+    def main(self):
+        (global_args, command_name, args_after_command_name) = self._split_args(sys.argv[1:])
+
+        # Handle --help, etc:
+        self.handle_global_args(global_args)
+
+        if not command_name:
+            self.global_option_parser.error("No command specified")
+
+        command = self.command_by_name(command_name)
+        if not command:
+            self.global_option_parser.error(command_name + " is not a recognized command")
+
+        (should_execute, failure_reason) = self.should_execute_command(command)
+        if not should_execute:
+            error(failure_reason)
+
+        command_object = command["object"]
+        (command_options, command_args) = command_object.parse_args(args_after_command_name)
+        return command_object.execute(command_options, command_args, self)
diff --git a/WebKitTools/Scripts/modules/multicommandtool_unittest.py b/WebKitTools/Scripts/modules/multicommandtool_unittest.py
new file mode 100644
index 0000000..997e11a
--- /dev/null
+++ b/WebKitTools/Scripts/modules/multicommandtool_unittest.py
@@ -0,0 +1,89 @@
+# Copyright (c) 2009, Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# 
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import unittest
+from multicommandtool import MultiCommandTool, Command
+
+from optparse import make_option
+
+class TrivialCommand(Command):
+    def __init__(self, **kwargs):
+        Command.__init__(self, "help text", **kwargs)
+
+    def execute(self, options, args, tool):
+        pass
+
+
+class CommandTest(unittest.TestCase):
+    def test_name_with_arguments(self):
+        command_with_args = TrivialCommand(argument_names="ARG1 ARG2")
+        self.assertEqual(command_with_args.name_with_arguments("simple"), "simple ARG1 ARG2")
+
+        command_with_args = TrivialCommand(options=[make_option("--my_option")])
+        self.assertEqual(command_with_args.name_with_arguments("simple"), "simple [options]")
+
+
+class TrivialTool(MultiCommandTool):
+    def __init__(self, commands):
+        MultiCommandTool.__init__(self, commands)
+
+    def should_show_command_help(self, command):
+        return True
+
+    def should_execute_command(self, command):
+        return True
+
+
+class MultiCommandToolTest(unittest.TestCase):
+    def _assert_split(self, args, expected_split):
+        self.assertEqual(MultiCommandTool._split_args(args), expected_split)
+
+    def test_split_args(self):
+        # MultiCommandToolTest._split_args returns: (global_args, command, command_args)
+        full_args = ["--global-option", "command", "--option", "arg"]
+        full_args_expected = (["--global-option"], "command", ["--option", "arg"])
+        self._assert_split(full_args, full_args_expected)
+
+        full_args = []
+        full_args_expected = ([], None, [])
+        self._assert_split(full_args, full_args_expected)
+
+        full_args = ["command", "arg"]
+        full_args_expected = ([], "command", ["arg"])
+        self._assert_split(full_args, full_args_expected)
+
+    def test_command_by_name(self):
+        foo_command = { "name" : "foo_command", "object" :  TrivialCommand() }
+        tool = TrivialTool([foo_command])
+
+        self.assertEqual(tool.command_by_name("foo_command"), foo_command)
+        self.assertEqual(tool.command_by_name("bar"), None)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/WebKitTools/Scripts/run-webkit-unittests b/WebKitTools/Scripts/run-webkit-unittests
index 8e518e2..99e2d08 100755
--- a/WebKitTools/Scripts/run-webkit-unittests
+++ b/WebKitTools/Scripts/run-webkit-unittests
@@ -36,6 +36,7 @@ from modules.committers_unittest import *
 from modules.cpp_style_unittest import *
 from modules.diff_parser_unittest import *
 from modules.logging_unittest import *
+from modules.multicommandtool_unittest import *
 from modules.patchcollection_unittest import *
 from modules.scm_unittest import *
 from modules.workqueue_unittest import *

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list