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("--no-close", action="store_false", dest="close_bug", default=True, help="Leave bug open after landing."),
75 make_option("--no-build", action="store_false", dest="build", default=True, help="Commit without building first, implies --no-test."),
76 make_option("--no-test", action="store_false", dest="test", default=True, help="Commit without running run-webkit-tests."),
77 make_option("--quiet", action="store_true", dest="quiet", default=False, help="Produce less console output."),
78 make_option("--non-interactive", action="store_true", dest="non_interactive", default=False, help="Never prompt the user, fail as fast as possible."),
79 ] + WebKitPort.port_options()
82 def run_command_with_teed_output(args, teed_output):
83 child_process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
85 # Use our own custom wait loop because Popen ignores a tee'd stderr/stdout.
86 # FIXME: This could be improved not to flatten output to stdout.
88 output_line = child_process.stdout.readline()
89 if output_line == "" and child_process.poll() != None:
90 return child_process.poll()
91 teed_output.write(output_line)
94 def run_and_throw_if_fail(args, quiet=False):
95 # Cache the child's output locally so it can be used for error reports.
96 child_out_file = StringIO.StringIO()
98 dev_null = open(os.devnull, "w")
99 child_stdout = tee(child_out_file, dev_null if quiet else sys.stdout)
100 exit_code = WebKitLandingScripts.run_command_with_teed_output(args, child_stdout)
104 child_output = child_out_file.getvalue()
105 child_out_file.close()
108 raise ScriptError(script_args=args, exit_code=exit_code, output=child_output)
111 def run_webkit_script(cls, script_name, quiet=False, port=WebKitPort):
112 log("Running %s" % script_name)
113 cls.run_and_throw_if_fail(port.script_path(script_name), quiet)
116 def build_webkit(cls, quiet=False, port=WebKitPort):
117 log("Building WebKit")
118 cls.run_and_throw_if_fail(port.build_webkit_command(), quiet)
121 def ensure_builders_are_green(buildbot, options):
122 if not options.check_builders or buildbot.core_builders_are_green():
124 error("Builders at %s are red, please do not commit. Pass --ignore-builders to bypass this check." % (buildbot.buildbot_host))
127 def run_webkit_tests(cls, launch_safari, fail_fast=False, quiet=False, port=WebKitPort):
128 args = port.run_webkit_tests_command()
129 if not launch_safari:
130 args.append("--no-launch-safari")
132 args.append("--quiet")
134 args.append("--exit-after-n-failures=1")
135 cls.run_and_throw_if_fail(args)
138 def prepare_clean_working_directory(scm, options, allow_local_commits=False):
139 os.chdir(scm.checkout_root)
140 if not allow_local_commits:
141 scm.ensure_no_local_commits(options.force_clean)
143 scm.ensure_clean_working_directory(force_clean=options.force_clean)