2 # Copyright (c) 2009, Google Inc. All rights reserved.
3 # Copyright (c) 2009 Apple Inc. All rights reserved.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following disclaimer
13 # in the documentation and/or other materials provided with the
15 # * Neither the name of Google Inc. nor the names of its
16 # contributors may be used to endorse or promote products derived from
17 # this software without specific prior written permission.
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 from optparse import make_option
38 from modules.changelogs import ChangeLog
39 from modules.logging import log, tee
40 from modules.scm import CommitMessage, detect_scm_system, ScriptError, CheckoutNeedsUpdate
41 from modules.webkitport import WebKitPort
43 def commit_message_for_this_commit(scm):
44 changelog_paths = scm.modified_changelogs()
45 if not len(changelog_paths):
46 raise ScriptError(message="Found no modified ChangeLogs, cannot create a commit message.\n"
47 "All changes require a ChangeLog. See:\n"
48 "http://webkit.org/coding/contributing.html")
50 changelog_messages = []
51 for changelog_path in changelog_paths:
52 log("Parsing ChangeLog: %s" % changelog_path)
53 changelog_entry = ChangeLog(changelog_path).latest_entry()
54 if not changelog_entry:
55 raise ScriptError(message="Failed to parse ChangeLog: " + os.path.abspath(changelog_path))
56 changelog_messages.append(changelog_entry)
58 # FIXME: We should sort and label the ChangeLog messages like commit-log-editor does.
59 return CommitMessage("".join(changelog_messages).splitlines())
62 class WebKitLandingScripts:
64 def cleaning_options():
66 make_option("--force-clean", action="store_true", dest="force_clean", default=False, help="Clean working directory before applying patches (removes local changes and commits)"),
67 make_option("--no-clean", action="store_false", dest="clean", default=True, help="Don't check if the working directory is clean before applying patches"),
73 make_option("--ignore-builders", action="store_false", dest="check_builders", default=True, help="Don't check to see if the build.webkit.org builders are green before landing."),
74 make_option("--quiet", action="store_true", dest="quiet", default=False, help="Produce less console output."),
75 make_option("--non-interactive", action="store_true", dest="non_interactive", default=False, help="Never prompt the user, fail as fast as possible."),
76 ] + WebKitPort.port_options()
81 make_option("--no-close", action="store_false", dest="close_bug", default=True, help="Leave bug open after landing."),
82 make_option("--no-build", action="store_false", dest="build", default=True, help="Commit without building first, implies --no-test."),
83 make_option("--no-test", action="store_false", dest="test", default=True, help="Commit without running run-webkit-tests."),
87 def run_command_with_teed_output(args, teed_output):
88 child_process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
90 # Use our own custom wait loop because Popen ignores a tee'd stderr/stdout.
91 # FIXME: This could be improved not to flatten output to stdout.
93 output_line = child_process.stdout.readline()
94 if output_line == "" and child_process.poll() != None:
95 return child_process.poll()
96 teed_output.write(output_line)
99 def run_and_throw_if_fail(args, quiet=False):
100 # Cache the child's output locally so it can be used for error reports.
101 child_out_file = StringIO.StringIO()
103 dev_null = open(os.devnull, "w")
104 child_stdout = tee(child_out_file, dev_null if quiet else sys.stdout)
105 exit_code = WebKitLandingScripts.run_command_with_teed_output(args, child_stdout)
109 child_output = child_out_file.getvalue()
110 child_out_file.close()
113 raise ScriptError(script_args=args, exit_code=exit_code, output=child_output)
116 def run_webkit_script(cls, script_name, quiet=False, port=WebKitPort):
117 log("Running %s" % script_name)
118 cls.run_and_throw_if_fail(port.script_path(script_name), quiet)
121 def build_webkit(cls, quiet=False, port=WebKitPort):
122 log("Building WebKit")
123 cls.run_and_throw_if_fail(port.build_webkit_command(), quiet)
126 def ensure_builders_are_green(buildbot, options):
127 if not options.check_builders or buildbot.core_builders_are_green():
129 error("Builders at %s are red, please do not commit. Pass --ignore-builders to bypass this check." % (buildbot.buildbot_host))
132 def run_webkit_tests(cls, launch_safari, fail_fast=False, quiet=False, port=WebKitPort):
133 args = port.run_webkit_tests_command()
134 if not launch_safari:
135 args.append("--no-launch-safari")
137 args.append("--quiet")
139 args.append("--exit-after-n-failures=1")
140 cls.run_and_throw_if_fail(args)
143 def prepare_clean_working_directory(scm, options, allow_local_commits=False):
144 os.chdir(scm.checkout_root)
145 if not allow_local_commits:
146 scm.ensure_no_local_commits(options.force_clean)
148 scm.ensure_clean_working_directory(force_clean=options.force_clean)