| # 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 |