| # Copyright (c) 2010 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. |
| |
| """Webkit-patch is a tool with multiple sub-commands with different purposes. |
| |
| Historically, it had commands related to dealing with bugzilla, and posting |
| and comitting patches to WebKit. More recently, it has commands for printing |
| expectations, fetching new test baselines, starting a commit-announcer IRC bot, |
| etc. These commands don't necessarily have anything to do with each other. |
| """ |
| |
| import logging |
| import optparse |
| import sys |
| |
| from webkitpy.common.host import Host |
| from webkitpy.tool.commands.analyze_baselines import AnalyzeBaselines |
| from webkitpy.tool.commands.auto_rebaseline import AutoRebaseline |
| from webkitpy.tool.commands.command import HelpPrintingOptionParser |
| from webkitpy.tool.commands.commit_announcer import CommitAnnouncerCommand |
| from webkitpy.tool.commands.flaky_tests import FlakyTests |
| from webkitpy.tool.commands.help_command import HelpCommand |
| from webkitpy.tool.commands.layout_tests_server import LayoutTestsServer |
| from webkitpy.tool.commands.optimize_baselines import OptimizeBaselines |
| from webkitpy.tool.commands.pretty_diff import PrettyDiff |
| from webkitpy.tool.commands.queries import CrashLog |
| from webkitpy.tool.commands.queries import PrintBaselines |
| from webkitpy.tool.commands.queries import PrintExpectations |
| from webkitpy.tool.commands.rebaseline import CopyExistingBaselinesInternal |
| from webkitpy.tool.commands.rebaseline import Rebaseline |
| from webkitpy.tool.commands.rebaseline import RebaselineExpectations |
| from webkitpy.tool.commands.rebaseline import RebaselineJson |
| from webkitpy.tool.commands.rebaseline import RebaselineTest |
| from webkitpy.tool.commands.rebaseline_cl import RebaselineCL |
| from webkitpy.tool.commands.rebaseline_server import RebaselineServer |
| |
| |
| _log = logging.getLogger(__name__) |
| |
| |
| class WebKitPatch(Host): |
| # FIXME: It might make more sense if this class had a Host attribute |
| # instead of being a Host subclass. |
| |
| global_options = [ |
| optparse.make_option( |
| '-v', '--verbose', action='store_true', dest='verbose', default=False, |
| help='enable all logging'), |
| optparse.make_option( |
| '-d', '--directory', action='append', default=[], |
| help='Directory to look at for changed files'), |
| ] |
| |
| def __init__(self, path): |
| super(WebKitPatch, self).__init__() |
| self._path = path |
| self.commands = [ |
| AnalyzeBaselines(), |
| AutoRebaseline(), |
| CommitAnnouncerCommand(), |
| CopyExistingBaselinesInternal(), |
| CrashLog(), |
| FlakyTests(), |
| LayoutTestsServer(), |
| OptimizeBaselines(), |
| PrettyDiff(), |
| PrintBaselines(), |
| PrintExpectations(), |
| Rebaseline(), |
| RebaselineCL(), |
| RebaselineExpectations(), |
| RebaselineJson(), |
| RebaselineServer(), |
| RebaselineTest(), |
| ] |
| self.help_command = HelpCommand(tool=self) |
| self.commands.append(self.help_command) |
| |
| def main(self, argv=None): |
| argv = argv or sys.argv |
| (command_name, args) = self._split_command_name_from_args(argv[1:]) |
| |
| option_parser = self._create_option_parser() |
| self._add_global_options(option_parser) |
| |
| command = self.command_by_name(command_name) or self.help_command |
| if not command: |
| option_parser.error('%s is not a recognized command', command_name) |
| |
| command.set_option_parser(option_parser) |
| (options, args) = command.parse_args(args) |
| |
| (should_execute, failure_reason) = self._should_execute_command(command) |
| if not should_execute: |
| _log.error(failure_reason) |
| return 0 # FIXME: Should this really be 0? |
| |
| result = command.check_arguments_and_execute(options, args, self) |
| return result |
| |
| def path(self): |
| return self._path |
| |
| @staticmethod |
| def _split_command_name_from_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 (None, args[:]) |
| |
| command = args[command_index] |
| return (command, args[:command_index] + args[command_index + 1:]) |
| |
| def _create_option_parser(self): |
| usage = 'Usage: %prog [options] COMMAND [ARGS]' |
| name = optparse.OptionParser().get_prog_name() |
| return HelpPrintingOptionParser(epilog_method=self.help_command.help_epilog, prog=name, usage=usage) |
| |
| def _add_global_options(self, option_parser): |
| global_options = self.global_options or [] |
| for option in global_options: |
| option_parser.add_option(option) |
| |
| def _should_execute_command(self, command): |
| if command.requires_local_commits and not self.git().supports_local_commits(): |
| failure_reason = '%s requires local commits using %s in %s.' % ( |
| command.name, self.git().display_name(), self.git().checkout_root) |
| return (False, failure_reason) |
| return (True, None) |
| |
| def name(self): |
| return optparse.OptionParser().get_prog_name() |
| |
| def should_show_in_main_help(self, command): |
| if not command.show_in_main_help: |
| return False |
| if command.requires_local_commits: |
| return self.git().supports_local_commits() |
| return True |
| |
| def command_by_name(self, command_name): |
| for command in self.commands: |
| if command_name == command.name: |
| return command |
| return None |