diff options
| author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-03 09:55:33 +0100 |
|---|---|---|
| committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-03 09:55:33 +0100 |
| commit | cd44dc59cdfc39534aef4d417e9f3c412e3be139 (patch) | |
| tree | 8d89889ba95ed6ec9322e733846cc9cce9d7dff1 /Tools/Scripts/webkitpy/common | |
| parent | d11f84f5b5cdc0d92a08af01b13472fdd5f9acb9 (diff) | |
| download | qtwebkit-cd44dc59cdfc39534aef4d417e9f3c412e3be139.tar.gz | |
Imported WebKit commit fce473cb4d55aa9fe9d0b0322a2fffecb731b961 (http://svn.webkit.org/repository/webkit/trunk@106560)
Diffstat (limited to 'Tools/Scripts/webkitpy/common')
26 files changed, 389 insertions, 274 deletions
diff --git a/Tools/Scripts/webkitpy/common/checkout/checkout.py b/Tools/Scripts/webkitpy/common/checkout/checkout.py index 08abe6cd8..8f450249c 100644 --- a/Tools/Scripts/webkitpy/common/checkout/checkout.py +++ b/Tools/Scripts/webkitpy/common/checkout/checkout.py @@ -1,9 +1,9 @@ # Copyright (c) 2010 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 @@ -13,7 +13,7 @@ # * 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 @@ -121,13 +121,13 @@ class Checkout(object): def modified_non_changelogs(self, git_commit, changed_files=None): return self._modified_files_matching_predicate(git_commit, lambda path: not self.is_path_to_changelog(path), changed_files=changed_files) - def commit_message_for_this_commit(self, git_commit, changed_files=None): + def commit_message_for_this_commit(self, git_commit, changed_files=None, return_stderr=False): changelog_paths = self.modified_changelogs(git_commit, changed_files) if not len(changelog_paths): raise ScriptError(message="Found no modified ChangeLogs, cannot create a commit message.\n" "All changes require a ChangeLog. See:\n %s" % urls.contribution_guidelines) - message_text = self._scm.run([self._scm.script_path('commit-log-editor'), '--print-log'] + changelog_paths, return_stderr=False) + message_text = self._scm.run([self._scm.script_path('commit-log-editor'), '--print-log'] + changelog_paths, return_stderr=return_stderr) return CommitMessage(message_text.splitlines()) def recent_commit_infos_for_files(self, paths): @@ -150,16 +150,15 @@ class Checkout(object): def chromium_deps(self): return DEPS(self._scm.absolute_path(self._filesystem.join("Source", "WebKit", "chromium", "DEPS"))) - def apply_patch(self, patch, force=False): + def apply_patch(self, patch): # It's possible that the patch was not made from the root directory. # We should detect and handle that case. # FIXME: Move _scm.script_path here once we get rid of all the dependencies. - args = [self._scm.script_path('svn-apply')] + # --force (continue after errors) is the common case, so we always use it. + args = [self._scm.script_path('svn-apply'), "--force"] if patch.reviewer(): args += ['--reviewer', patch.reviewer().full_name] - if force: - args.append('--force') - self._executive.run_command(args, input=patch.contents()) + self._executive.run_command(args, input=patch.contents(), cwd=self._scm.checkout_root) def apply_reverse_diff(self, revision): self._scm.apply_reverse_diff(revision) diff --git a/Tools/Scripts/webkitpy/common/checkout/checkout_mock.py b/Tools/Scripts/webkitpy/common/checkout/checkout_mock.py index 039db1f6a..25b05c33a 100644 --- a/Tools/Scripts/webkitpy/common/checkout/checkout_mock.py +++ b/Tools/Scripts/webkitpy/common/checkout/checkout_mock.py @@ -84,7 +84,7 @@ class MockCheckout(object): def chromium_deps(self): return MockDEPS() - def apply_patch(self, patch, force=False): + def apply_patch(self, patch): pass def apply_reverse_diffs(self, revision): diff --git a/Tools/Scripts/webkitpy/common/checkout/checkout_unittest.py b/Tools/Scripts/webkitpy/common/checkout/checkout_unittest.py index 962364b6c..3b0943247 100644 --- a/Tools/Scripts/webkitpy/common/checkout/checkout_unittest.py +++ b/Tools/Scripts/webkitpy/common/checkout/checkout_unittest.py @@ -42,6 +42,7 @@ from webkitpy.common.system.executive import Executive, ScriptError from webkitpy.common.system.filesystem import FileSystem # FIXME: This should not be needed. from webkitpy.common.system.filesystem_mock import MockFileSystem from webkitpy.common.system.executive_mock import MockExecutive +from webkitpy.common.system.outputcapture import OutputCapture from webkitpy.thirdparty.mock import Mock @@ -139,7 +140,9 @@ Second part of this complicated change by me, Tor Arne Vestb\u00f8! checkout = Checkout(mock_scm) checkout.modified_changelogs = lambda git_commit, changed_files=None: self.changelogs - commit_message = checkout.commit_message_for_this_commit(git_commit=None) + commit_message = checkout.commit_message_for_this_commit(git_commit=None, return_stderr=True) + # Throw away the first line - a warning about unknown VCS root. + commit_message.message_lines = commit_message.message_lines[1:] self.assertEqual(commit_message.message(), self.expected_commit_message) @@ -250,3 +253,13 @@ class CheckoutTest(unittest.TestCase): checkout = self._make_checkout() checkout._scm.checkout_root = "/foo/bar" self.assertEqual(checkout.chromium_deps()._path, '/foo/bar/Source/WebKit/chromium/DEPS') + + def test_apply_patch(self): + checkout = self._make_checkout() + checkout._executive = MockExecutive(should_log=True) + checkout._scm.script_path = lambda script: script + mock_patch = Mock() + mock_patch.contents = lambda: "foo" + mock_patch.reviewer = lambda: None + expected_stderr = "MOCK run_command: ['svn-apply', '--force'], cwd=/mock-checkout\n" + OutputCapture().assert_outputs(self, checkout.apply_patch, [mock_patch], expected_stderr=expected_stderr) diff --git a/Tools/Scripts/webkitpy/common/checkout/scm/git.py b/Tools/Scripts/webkitpy/common/checkout/scm/git.py index 7c23be056..866b24cc4 100644 --- a/Tools/Scripts/webkitpy/common/checkout/scm/git.py +++ b/Tools/Scripts/webkitpy/common/checkout/scm/git.py @@ -434,16 +434,11 @@ class Git(SCM, SVNRepository): def push_local_commits_to_server(self, username=None, password=None): dcommit_command = ['git', 'svn', 'dcommit'] - if self.dryrun: - dcommit_command.append('--dry-run') if (not username or not password) and not self.has_authorization_for_realm(SVN.svn_server_realm): raise AuthenticationError(SVN.svn_server_host, prompt_for_password=True) if username: dcommit_command.extend(["--username", username]) output = self.run(dcommit_command, error_handler=commit_error_handler, input=password, cwd=self.checkout_root) - # Return a string which looks like a commit so that things which parse this output will succeed. - if self.dryrun: - output += "\nCommitted r0" return output # This function supports the following argument formats: diff --git a/Tools/Scripts/webkitpy/common/checkout/scm/scm.py b/Tools/Scripts/webkitpy/common/checkout/scm/scm.py index b00470bbb..4b581b17f 100644 --- a/Tools/Scripts/webkitpy/common/checkout/scm/scm.py +++ b/Tools/Scripts/webkitpy/common/checkout/scm/scm.py @@ -61,7 +61,6 @@ class SCM: def __init__(self, cwd, executive=None, filesystem=None): self.cwd = cwd self.checkout_root = self.find_checkout_root(self.cwd) - self.dryrun = False self._executive = executive or Executive() self._filesystem = filesystem or FileSystem() diff --git a/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py b/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py index ae5ac845c..209bd3510 100644 --- a/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py +++ b/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py @@ -757,11 +757,6 @@ Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== commit_text = self.scm.commit_with_message("another test commit", username) self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '6') - self.scm.dryrun = True - write_into_file_at_path('test_file', 'still more test content') - commit_text = self.scm.commit_with_message("yet another test commit", username) - self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '0') - def test_commit_in_subdir(self, username=None): write_into_file_at_path('test_dir/test_file3', 'more test content') os.chdir("test_dir") @@ -1216,11 +1211,6 @@ class GitSVNTest(SCMTest): commit_text = self.scm.commit_with_message("another test commit") self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '6') - self.scm.dryrun = True - write_into_file_at_path('test_file', 'still more test content') - commit_text = self.scm.commit_with_message("yet another test commit") - self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '0') - def test_commit_with_message_working_copy_only(self): write_into_file_at_path('test_file_commit1', 'more test content') run_command(['git', 'add', 'test_file_commit1']) diff --git a/Tools/Scripts/webkitpy/common/checkout/scm/svn.py b/Tools/Scripts/webkitpy/common/checkout/scm/svn.py index cd4e1ea60..3f583a7d3 100644 --- a/Tools/Scripts/webkitpy/common/checkout/scm/svn.py +++ b/Tools/Scripts/webkitpy/common/checkout/scm/svn.py @@ -333,12 +333,6 @@ class SVN(SCM, SVNRepository): if changed_files: svn_commit_args.extend(changed_files) - if self.dryrun: - _log.debug('Would run SVN command: "' + " ".join(svn_commit_args) + '"') - - # Return a string which looks like a commit so that things which parse this output will succeed. - return "Dry run, no commit.\nCommitted revision 0." - return self._run_svn(svn_commit_args, cwd=self.checkout_root, error_handler=commit_error_handler) def svn_commit_log(self, svn_revision): diff --git a/Tools/Scripts/webkitpy/common/config/build.py b/Tools/Scripts/webkitpy/common/config/build.py index ac9a1360d..fcb5e62c3 100644 --- a/Tools/Scripts/webkitpy/common/config/build.py +++ b/Tools/Scripts/webkitpy/common/config/build.py @@ -55,7 +55,6 @@ def _should_file_trigger_build(target_platform, file): ("wx", []), # Directories that should trigger builds on only some bots. - ("Source/JavaScriptGlue", ["mac"]), ("Source/WebCore/image-decoders", ["chromium"]), ("LayoutTests/platform/mac", ["mac", "win"]), ("cairo", ["gtk", "wincairo"]), diff --git a/Tools/Scripts/webkitpy/common/config/build_unittest.py b/Tools/Scripts/webkitpy/common/config/build_unittest.py index 7e76befe6..bdc340489 100644 --- a/Tools/Scripts/webkitpy/common/config/build_unittest.py +++ b/Tools/Scripts/webkitpy/common/config/build_unittest.py @@ -33,8 +33,7 @@ class ShouldBuildTest(unittest.TestCase): (["Websites/bugs.webkit.org/foo"], []), (["Source/JavaScriptCore/JavaScriptCore.xcodeproj/foo"], ["mac-leopard", "mac-lion", "mac-snowleopard"]), (["Source/JavaScriptCore/JavaScriptCore.vcproj/foo", "Source/WebKit2/win/WebKit2.vcproj", "Source/WebKit/win/WebKit.sln", "Tools/WebKitTestRunner/Configurations/WebKitTestRunnerCommon.vsprops"], ["win"]), - (["Source/JavaScriptGlue/foo", "Source/WebCore/bar"], ["*"]), - (["Source/JavaScriptGlue/foo"], ["mac-leopard", "mac-lion", "mac-snowleopard"]), + (["LayoutTests/platform/mac/foo", "Source/WebCore/bar"], ["*"]), (["LayoutTests/foo"], ["*"]), (["LayoutTests/canvas/philip/tests/size.attributes.parse.exp-expected.txt", "LayoutTests/canvas/philip/tests/size.attributes.parse.exp.html"], ["*"]), (["LayoutTests/platform/chromium-linux/foo"], ["chromium-linux"]), diff --git a/Tools/Scripts/webkitpy/common/config/committers.py b/Tools/Scripts/webkitpy/common/config/committers.py index eb9afc332..6e7399ecb 100644 --- a/Tools/Scripts/webkitpy/common/config/committers.py +++ b/Tools/Scripts/webkitpy/common/config/committers.py @@ -1,5 +1,5 @@ # Copyright (c) 2011, Apple Inc. All rights reserved. -# Copyright (c) 2009, 2011 Google Inc. All rights reserved. +# Copyright (c) 2009, 2011, 2012 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 @@ -105,6 +105,7 @@ watchers_who_are_not_contributors = [ contributors_who_are_not_committers = [ + Contributor("Adam Kallai", "kallai.adam@stud.u-szeged.hu", 'kadam'), Contributor("Aharon Lanin", "aharon@google.com"), Contributor("Alan Stearns", "stearns@adobe.com", 'astearns'), Contributor("Alexandre Elias", "aelias@chromium.org"), @@ -113,8 +114,8 @@ contributors_who_are_not_committers = [ Contributor("Andras Piroska", "pandras@inf.u-szeged.hu", "andris88"), Contributor("Anne van Kesteren", "annevankesteren+webkit@gmail.com", "annevk"), Contributor("Annie Sullivan", "sullivan@chromium.org", "annie"), - Contributor("Antoine Labour", "piman@chromium.org", "piman"), Contributor("Aryeh Gregor", "ayg@aryeh.name", "AryehGregor"), + Contributor("Balazs Ankes", "ankes.balazs@stud.u-szeged.hu", 'abalazs'), Contributor("Commit Queue", "commit-queue@webkit.org"), Contributor("Dana Jansens", "danakj@chromium.org", "danakj"), Contributor("Daniel Sievers", "sievers@chromium.org"), @@ -130,16 +131,18 @@ contributors_who_are_not_committers = [ Contributor("Greg Simon", "gregsimon@chromium.org", "gregsimon"), Contributor("Gregg Tavares", ["gman@google.com", "gman@chromium.org"], "gman"), Contributor("Ian Hickson", "ian@hixie.ch", "hixie"), + Contributor("Janos Badics", "dicska@gmail.hu", 'dicska'), Contributor("John Bates", ["jbates@google.com", "jbates@chromium.org"], "jbates"), Contributor("John Bauman", ["jbauman@chromium.org", "jbauman@google.com"], "jbauman"), Contributor("Kaustubh Atrawalkar", ["kaustubh@motorola.com"], "silverroots"), - Contributor("Kristof Kosztyo", "kkristof@inf.u-szeged.hu", "kkristof"), Contributor("Kulanthaivel Palanichamy", "kulanthaivel@codeaurora.org", "kvel"), + Contributor("Nandor Huszka", "huszka.nandor@stud.u-szeged.hu", "hnandor"), Contributor("Oliver Varga", ["voliver@inf.u-szeged.hu", "Varga.Oliver@stud.u-szeged.hu"], "TwistO"), Contributor("Peter Gal", "galpeter@inf.u-szeged.hu", "elecro"), Contributor("Peter Linss", "peter.linss@hp.com", "plinss"), Contributor("Radar WebKit Bug Importer", "webkit-bug-importer@group.apple.com"), - Contributor("Shawn Singh", "shawnsingh@chromium.org", "shawnsingh"), + Contributor("Roland Takacs", "takacs.roland@stud.u-szeged.hu", "rtakacs"), + Contributor("Szilard Ledan-Muntean", "muntean-ledan.szilard@stud.u-szeged.hu", "szledan"), Contributor("Tab Atkins", ["tabatkins@google.com", "jackalmage@gmail.com"], "tabatkins"), Contributor("Tamas Czene", ["tczene@inf.u-szeged.hu", "Czene.Tamas@stud.u-szeged.hu"], "tczene"), Contributor("WebKit Review Bot", "webkit.review.bot@gmail.com", "sheriff-bot"), @@ -178,6 +181,7 @@ committers_unable_to_review = [ Committer("Andras Becsi", ["abecsi@webkit.org", "andras.becsi@nokia.com"], "bbandix"), Committer("Anna Cavender", "annacc@chromium.org", "annacc"), Committer("Anthony Ricaud", "rik@webkit.org", "rik"), + Committer("Antoine Labour", "piman@chromium.org", "piman"), Committer("Anton D'Auria", "adauria@apple.com", "antonlefou"), Committer("Anton Muhin", "antonm@chromium.org", "antonm"), Committer("Balazs Kelemen", "kbalazs@webkit.org", "kbalazs"), @@ -199,6 +203,7 @@ committers_unable_to_review = [ Committer("Christian Dywan", ["christian@twotoasts.de", "christian@webkit.org", "christian@lanedo.com"]), Committer("Collin Jackson", "collinj@webkit.org", "collinjackson"), Committer("Cris Neckar", "cdn@chromium.org", "cneckar"), + Committer("Dan Winship", "danw@gnome.org", "danw"), Committer("Daniel Cheng", "dcheng@chromium.org", "dcheng"), Committer("David Grogan", ["dgrogan@chromium.org", "dgrogan@google.com"], "dgrogan"), Committer("David Smith", ["catfish.man@gmail.com", "dsmith@webkit.org"], "catfishman"), @@ -257,6 +262,7 @@ committers_unable_to_review = [ Committer("Jon Lee", "jonlee@apple.com", "jonlee"), Committer("Joone Hur", ["joone.hur@collabora.co.uk", "joone@kldp.org", "joone@webkit.org"], "joone"), Committer("Joost de Valk", ["joost@webkit.org", "webkit-dev@joostdevalk.nl"], "Altha"), + Committer("Joshua Bell", ["jsbell@chromium.org", "jsbell@google.com"], "jsbell"), Committer("Julie Parent", ["jparent@google.com", "jparent@chromium.org"], "jparent"), Committer("Jungshik Shin", "jshin@chromium.org"), Committer("Justin Schuh", "jschuh@chromium.org", "jschuh"), @@ -265,10 +271,10 @@ committers_unable_to_review = [ Committer("Kenichi Ishibashi", "bashi@chromium.org", "bashi"), Committer("Kenji Imasaki", "imasaki@chromium.org", "imasaki"), Committer("Kent Hansen", "kent.hansen@nokia.com", "khansen"), - Committer("Kentaro Hara", ["haraken@chromium.org"], "haraken"), Committer(u"Kim Gr\u00f6nholm", "kim.1.gronholm@nokia.com"), Committer("Kimmo Kinnunen", ["kimmo.t.kinnunen@nokia.com", "kimmok@iki.fi", "ktkinnun@webkit.org"], "kimmok"), Committer("Kinuko Yasuda", "kinuko@chromium.org", "kinuko"), + Committer("Kristof Kosztyo", "kkristof@inf.u-szeged.hu", "kkristof"), Committer("Krzysztof Kowalczyk", "kkowalczyk@gmail.com"), Committer("Kwang Yul Seo", ["kwangyul.seo@gmail.com", "skyul@company100.net", "kseo@webkit.org"], "kwangseo"), Committer("Leandro Gracia Gil", "leandrogracia@chromium.org", "leandrogracia"), @@ -298,6 +304,7 @@ committers_unable_to_review = [ Committer("Mike Reed", "reed@google.com", "reed"), Committer("Mike Thole", ["mthole@mikethole.com", "mthole@apple.com"]), Committer("Mikhail Naganov", "mnaganov@chromium.org"), + Committer("Naoki Takano", ["honten@chromium.org", "takano.naoki@gmail.com"], "honten"), Committer("Nat Duca", ["nduca@chromium.org", "nduca@google.com"], "nduca"), Committer("Nayan Kumar K", ["nayankk@motorola.com", "nayankk@gmail.com"], "xc0ffee"), Committer("Nico Weber", ["thakis@chromium.org", "thakis@google.com"], "thakis"), @@ -323,8 +330,10 @@ committers_unable_to_review = [ Committer("Satish Sampath", "satish@chromium.org"), Committer("Scott Violet", "sky@chromium.org", "sky"), Committer("Sergio Villar Senin", ["svillar@igalia.com", "sergio@webkit.org"], "svillar"), + Committer("Shawn Singh", "shawnsingh@chromium.org", "shawnsingh"), Committer("Siddharth Mathur", "siddharth.mathur@nokia.com", "simathur"), Committer("Steve Lacey", "sjl@chromium.org", "stevela"), + Committer("Takashi Toyoshima", "toyoshim@chromium.org", "toyoshim"), Committer("Tim Horton", "timothy_horton@apple.com", "thorton"), Committer("Tom Zakrajsek", "tomz@codeaurora.org", "tomz"), Committer("Tommy Widenflycht", "tommyw@google.com", "tommyw"), @@ -336,7 +345,6 @@ committers_unable_to_review = [ Committer("Victoria Kirst", ["vrk@chromium.org", "vrk@google.com"], "vrk"), Committer("Vincent Scheib", "scheib@chromium.org", "scheib"), Committer("Vitaly Repeshko", "vitalyr@chromium.org"), - Committer("Vsevolod Vlasov", "vsevik@chromium.org"), Committer("William Siegrist", "wsiegrist@apple.com", "wms"), Committer("W. James MacLean", "wjmaclean@chromium.org", "wjmaclean"), Committer("Xianzhu Wang", ["wangxianzhu@chromium.org", "phnixwxz@gmail.com", "wangxianzhu@google.com"], "wangxianzhu"), @@ -352,7 +360,6 @@ committers_unable_to_review = [ Committer("Zeno Albisser", ["zeno@webkit.org", "zeno.albisser@nokia.com"], "zalbisser"), Committer("Zhenyao Mo", "zmo@google.com", "zhenyao"), Committer("Zoltan Horvath", ["zoltan@webkit.org", "hzoltan@inf.u-szeged.hu", "horvath.zoltan.6@stud.u-szeged.hu"], "zoltan"), - Committer("Naoki Takano", ["honten@chromium.org", "takano.naoki@gmail.com"], "honten"), ] @@ -427,6 +434,7 @@ reviewers_list = [ Reviewer("Kenneth Rohde Christiansen", ["kenneth@webkit.org", "kenneth.christiansen@openbossa.org", "kenneth.christiansen@gmail.com"], ["kenne", "kenneth"]), Reviewer("Kenneth Russell", "kbr@google.com", "kbr_google"), Reviewer("Kent Tamura", ["tkent@chromium.org", "tkent@google.com"], "tkent"), + Reviewer("Kentaro Hara", ["haraken@chromium.org"], "haraken"), Reviewer("Kevin Decker", "kdecker@apple.com", "superkevin"), Reviewer("Kevin McCullough", "kmccullough@apple.com", "maculloch"), Reviewer("Kevin Ollivier", ["kevino@theolliviers.com", "kevino@webkit.org"], "kollivier"), @@ -461,6 +469,7 @@ reviewers_list = [ Reviewer("Tony Gentilcore", "tonyg@chromium.org", "tonyg-cr"), Reviewer(u"Tor Arne Vestb\u00f8", ["vestbo@webkit.org", "tor.arne.vestbo@nokia.com"], "torarne"), Reviewer("Vicki Murley", "vicki@apple.com"), + Reviewer("Vsevolod Vlasov", "vsevik@chromium.org", "vsevik"), Reviewer("Xan Lopez", ["xan.lopez@gmail.com", "xan@gnome.org", "xan@webkit.org", "xlopez@igalia.com"], "xan"), Reviewer("Yury Semikhatsky", "yurys@chromium.org", "yurys"), Reviewer("Zack Rusin", "zack@kde.org", "zackr"), diff --git a/Tools/Scripts/webkitpy/common/config/committers_unittest.py b/Tools/Scripts/webkitpy/common/config/committers_unittest.py index d3b10b82a..53d9c4d14 100644 --- a/Tools/Scripts/webkitpy/common/config/committers_unittest.py +++ b/Tools/Scripts/webkitpy/common/config/committers_unittest.py @@ -104,7 +104,10 @@ class CommittersTest(unittest.TestCase): def _assert_fuzz_match(self, text, name_of_expected_contributor, expected_distance): committers = CommitterList() contributors, distance = committers.contributors_by_fuzzy_match(text) - expected_names = [name_of_expected_contributor] if name_of_expected_contributor else [] + if type(name_of_expected_contributor) is list: + expected_names = name_of_expected_contributor + else: + expected_names = [name_of_expected_contributor] if name_of_expected_contributor else [] self.assertEqual(([contributor.full_name for contributor in contributors], distance), (expected_names, expected_distance)) def test_contributors_by_fuzzy_match(self): @@ -167,7 +170,7 @@ class CommittersTest(unittest.TestCase): # self._assert_fuzz_match('Chris', 'Chris Blumenberg', 0) self._assert_fuzz_match('cblu', 'Chris Blumenberg', 0) - self._assert_fuzz_match('Dan', 'Dan Bernstein', 0) + self._assert_fuzz_match('Dan', ['Dan Winship', 'Dan Bernstein'], 0) self._assert_fuzz_match('Dan B', 'Dan Bernstein', 0) # self._assert_fuzz_match('mitz', 'Dan Bernstein', 0) self._assert_fuzz_match('Mitz Pettel', 'Dan Bernstein', 1) diff --git a/Tools/Scripts/webkitpy/common/config/ports.py b/Tools/Scripts/webkitpy/common/config/ports.py index 3e100b059..02c1f5b55 100644 --- a/Tools/Scripts/webkitpy/common/config/ports.py +++ b/Tools/Scripts/webkitpy/common/config/ports.py @@ -36,6 +36,8 @@ from webkitpy.common.system.executive import Executive class WebKitPort(object): + results_directory = "/tmp/layout-test-results" + # We might need to pass scm into this function for scm.checkout_root @classmethod def script_path(cls, script_name): @@ -122,7 +124,7 @@ class WebKitPort(object): @classmethod def layout_tests_results_path(cls): - return "/tmp/layout-test-results/results.html" + return os.path.join(cls.results_directory, "full_results.json") class MacPort(WebKitPort): @@ -172,6 +174,7 @@ class GtkPort(WebKitPort): def build_webkit_command(cls, build_style=None): command = WebKitPort.build_webkit_command(build_style=build_style) command.append("--gtk") + command.append("--update-gtk") command.append(WebKitPort.makeArgs()) return command @@ -244,10 +247,6 @@ class ChromiumPort(WebKitPort): return command @classmethod - def run_webkit_unit_tests_command(cls): - return cls.script_shell_command("run-chromium-webkit-unit-tests") - - @classmethod def run_webkit_tests_command(cls): command = cls.script_shell_command("new-run-webkit-tests") command.append("--chromium") @@ -259,34 +258,12 @@ class ChromiumPort(WebKitPort): return None -# FIXME: This port is a bit of a hack to get our infrastructure running on EC2. class ChromiumXVFBPort(ChromiumPort): - results_directory = "/tmp/layout-test-results" - @classmethod def flag(cls): return "--port=chromium-xvfb" @classmethod def run_webkit_tests_command(cls): - # FIXME: We should find a better way to do this. Some of these options - # are specific to new-run-webkit-tests and some of them are due to - # running in non-interactive mode. - return ["xvfb-run"] + ChromiumPort.run_webkit_tests_command() + [ - "--results-directory=%s" % cls.results_directory, - "--skip-failing-tests", - "--print=actual,config,expected,misc,slowest,unexpected,unexpected-results", - ] - - @classmethod - def run_python_unittests_command(cls): - return None - - @classmethod - def run_perl_unittests_command(cls): - return None - - @classmethod - def layout_tests_results_path(cls): - return os.path.join(cls.results_directory, "full_results.json") + return ["xvfb-run"] + ChromiumPort.run_webkit_tests_command() diff --git a/Tools/Scripts/webkitpy/common/config/ports_mock.py b/Tools/Scripts/webkitpy/common/config/ports_mock.py index 77f51532e..d63efd2c6 100644 --- a/Tools/Scripts/webkitpy/common/config/ports_mock.py +++ b/Tools/Scripts/webkitpy/common/config/ports_mock.py @@ -28,11 +28,13 @@ class MockPort(object): + results_directory = "/mock-results" + def name(self): return "MockPort" def layout_tests_results_path(self): - return "/mock-results/results.html" + return "/mock-results/full_results.json" def check_webkit_style_command(self): return ["mock-check-webkit-style"] diff --git a/Tools/Scripts/webkitpy/common/config/ports_unittest.py b/Tools/Scripts/webkitpy/common/config/ports_unittest.py index e413c26ec..0532512aa 100644 --- a/Tools/Scripts/webkitpy/common/config/ports_unittest.py +++ b/Tools/Scripts/webkitpy/common/config/ports_unittest.py @@ -51,8 +51,8 @@ class WebKitPortTest(unittest.TestCase): self.assertEquals(GtkPort.name(), "Gtk") self.assertEquals(GtkPort.flag(), "--port=gtk") self.assertEquals(GtkPort.run_webkit_tests_command(), WebKitPort.script_shell_command("run-webkit-tests") + ["--gtk"]) - self.assertEquals(GtkPort.build_webkit_command(), WebKitPort.script_shell_command("build-webkit") + ["--gtk", WebKitPort.makeArgs()]) - self.assertEquals(GtkPort.build_webkit_command(build_style="debug"), WebKitPort.script_shell_command("build-webkit") + ["--debug", "--gtk", WebKitPort.makeArgs()]) + self.assertEquals(GtkPort.build_webkit_command(), WebKitPort.script_shell_command("build-webkit") + ["--gtk", "--update-gtk", WebKitPort.makeArgs()]) + self.assertEquals(GtkPort.build_webkit_command(build_style="debug"), WebKitPort.script_shell_command("build-webkit") + ["--debug", "--gtk", "--update-gtk", WebKitPort.makeArgs()]) def test_qt_port(self): self.assertEquals(QtPort.name(), "Qt") @@ -70,7 +70,7 @@ class WebKitPortTest(unittest.TestCase): self.assertEquals(ChromiumPort.update_webkit_command(), WebKitPort.script_shell_command("update-webkit") + ["--chromium"]) def test_chromium_xvfb_port(self): - self.assertEquals(ChromiumXVFBPort.run_webkit_tests_command(), ['xvfb-run'] + WebKitPort.script_shell_command('new-run-webkit-tests') + ['--chromium', '--skip-failing-tests', '--results-directory=/tmp/layout-test-results', '--skip-failing-tests', '--print=actual,config,expected,misc,slowest,unexpected,unexpected-results']) + self.assertEquals(ChromiumXVFBPort.run_webkit_tests_command(), ['xvfb-run'] + WebKitPort.script_shell_command('new-run-webkit-tests') + ['--chromium', '--skip-failing-tests']) if __name__ == '__main__': unittest.main() diff --git a/Tools/Scripts/webkitpy/common/config/watchlist b/Tools/Scripts/webkitpy/common/config/watchlist index 0354fda01..bf92f05da 100755 --- a/Tools/Scripts/webkitpy/common/config/watchlist +++ b/Tools/Scripts/webkitpy/common/config/watchlist @@ -21,6 +21,9 @@ "ChromiumPublicApi": { "filename": r"Source/WebKit/chromium/public/" }, + "AppleMacPublicApi": { + "filename": r"Source/WebCore/bindings/objc/PublicDOMInterfaces.h" + }, "Forms": { "filename": r"Source/WebCore/html/HTML(FieldSet|Form|FormControl|Input|Label" r"|OptGroup|Option|Select|TextArea|TextFormControl)Element\." @@ -81,6 +84,13 @@ "GtkWebKit2PublicAPI": { "filename": r"Source/WebKit2/UIProcess/API/gtk/", }, + "QtBuildSystem": { + # Project files for each target are intentionally left out, as those + # mostly list source and header files, which would just add noise. + "filename": r"Tools/qmake/" + r"|WebKit.pro" + r"|.*DerivedSources\.pri", + }, "QtWebKit2PublicAPI": { "filename": r"Source/WebKit2/UIProcess/API/qt/" r"|Source/WebKit2/UIProcess/API/cpp/qt/" @@ -131,8 +141,9 @@ "ChromiumDumpRenderTree": [ "tkent@chromium.org", ], "ChromiumGraphics": [ "jamesr@chromium.org", "cc-bugs@google.com" ], "ChromiumPublicApi": [ "fishd@chromium.org", ], + "AppleMacPublicApi": [ "timothy@apple.com" ], "Forms": [ "tkent@chromium.org", ], - "GStreamerGraphics": [ "pnormand@igalia.com", "gns@gnome.org" ], + "GStreamerGraphics": [ "alexis.menard@openbossa.org", "pnormand@igalia.com", "gns@gnome.org" ], "WebIDL": [ "abarth@webkit.org", "ojan@chromium.org" ], "StyleChecker": [ "levin@chromium.org", ], "ThreadingFiles|ThreadingUsage": [ "levin+threading@chromium.org", ], @@ -144,9 +155,10 @@ "webkitpy": [ "abarth@webkit.org", "ojan@chromium.org" ], "TestFailures": [ "abarth@webkit.org", "dglazkov@chromium.org" ], "GtkWebKit2PublicAPI": [ "cgarcia@igalia.com", "gns@gnome.org" ], - "QtWebKit2PublicAPI": [ "zoltan@webkit.org", ], - "QtWebKit2PlatformSpecific": [ "zoltan@webkit.org", ], - "CSS": [ "macpherson@chromium.org", ], + "QtBuildSystem" : [ "vestbo@webkit.org", ], + "QtWebKit2PublicAPI": [ "alexis.menard@openbossa.org", "zoltan@webkit.org", ], + "QtWebKit2PlatformSpecific": [ "alexis.menard@openbossa.org", "zoltan@webkit.org", ], + "CSS": [ "alexis.menard@openbossa.org", "macpherson@chromium.org", ], "EFL": [ "kubo@profusion.mobi", ], "CMake": [ "kubo@profusion.mobi", ], "SoupNetwork": [ "kubo@profusion.mobi", ], @@ -154,6 +166,10 @@ "MESSAGE_RULES": { "ChromiumPublicApi": [ "Please wait for approval from fishd@chromium.org before submitting " "because this patch contains changes to the Chromium public API.", ], + "AppleMacPublicApi": [ "Please wait for approval from timothy@apple.com (or another member " + "of the Apple Safari Team) before submitting " + "because this patch contains changes to the Apple Mac " + "WebKit.framework public API.", ], "GtkWebKit2PublicAPI": [ "Thanks for the patch. If this patch contains new public API " "please make sure it follows the guidelines for new WebKit2 GTK+ API. " "See http://trac.webkit.org/wiki/WebKitGTK/AddingNewWebKit2API", ], diff --git a/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py b/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py index 511f1bbdb..a32e86e13 100644 --- a/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py +++ b/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py @@ -259,20 +259,26 @@ class BugzillaQueries(object): class Bugzilla(object): - def __init__(self, dryrun=False, committers=committers.CommitterList()): - self.dryrun = dryrun + def __init__(self, committers=committers.CommitterList()): self.authenticated = False self.queries = BugzillaQueries(self) self.committers = committers self.cached_quips = [] self.edit_user_parser = EditUsersParser() + self._browser = None - # FIXME: We should use some sort of Browser mock object when in dryrun - # mode (to prevent any mistakes). - from webkitpy.thirdparty.autoinstalled.mechanize import Browser - self.browser = Browser() - # Ignore bugs.webkit.org/robots.txt until we fix it to allow this script. - self.browser.set_handle_robots(False) + def _get_browser(self): + if not self._browser: + from webkitpy.thirdparty.autoinstalled.mechanize import Browser + self._browser = Browser() + # Ignore bugs.webkit.org/robots.txt until we fix it to allow this script. + self._browser.set_handle_robots(False) + return self._browser + + def _set_browser(self, value): + self._browser = value + + browser = property(_get_browser, _set_browser) def fetch_user(self, user_id): self.authenticate() @@ -291,7 +297,7 @@ class Bugzilla(object): def quips(self): # We only fetch and parse the list of quips once per instantiation # so that we do not burden bugs.webkit.org. - if not self.cached_quips and not self.dryrun: + if not self.cached_quips: self.cached_quips = self.queries.fetch_quips() return self.cached_quips @@ -475,11 +481,6 @@ class Bugzilla(object): if self.authenticated: return - if self.dryrun: - log("Skipping log in for dry run...") - self.authenticated = True - return - credentials = Credentials(config_urls.bug_server_host, git_prefix="bugzilla") attempts = 0 @@ -563,10 +564,6 @@ class Bugzilla(object): comment_text=None): self.authenticate() log('Adding attachment "%s" to %s' % (description, self.bug_url_for_bug_id(bug_id))) - if self.dryrun: - log(comment_text) - return - self.browser.open(self.add_attachment_url(bug_id)) self.browser.select_form(name="entryform") file_object = self._file_object_for_upload(file_or_string) @@ -590,10 +587,6 @@ class Bugzilla(object): self.authenticate() log('Adding patch "%s" to %s' % (description, self.bug_url_for_bug_id(bug_id))) - if self.dryrun: - log(comment_text) - return - self.browser.open(self.add_attachment_url(bug_id)) self.browser.select_form(name="entryform") file_object = self._file_object_for_upload(file_or_string) @@ -644,11 +637,6 @@ class Bugzilla(object): self.authenticate() log('Creating bug with title "%s"' % bug_title) - if self.dryrun: - log(bug_description) - # FIXME: This will make some paths fail, as they assume this returns an id. - return - self.browser.open(config_urls.bug_server_url + "enter_bug.cgi?product=WebKit") self.browser.select_form(name="Create") component_items = self.browser.find_control('component').items @@ -706,9 +694,6 @@ class Bugzilla(object): comment_text += "\n\n%s" % additional_comment_text log(comment_text) - if self.dryrun: - return - self.browser.open(self.attachment_url_for_id(attachment_id, 'edit')) self.browser.select_form(nr=1) self.browser.set_value(comment_text, name='comment', nr=0) @@ -732,9 +717,6 @@ class Bugzilla(object): comment_text += "\n\n%s" % additional_comment_text log(comment_text) - if self.dryrun: - return - self.browser.open(self.attachment_url_for_id(attachment_id, 'edit')) self.browser.select_form(nr=1) @@ -751,10 +733,6 @@ class Bugzilla(object): self.authenticate() log("Obsoleting attachment: %s" % attachment_id) - if self.dryrun: - log(comment_text) - return - self.browser.open(self.attachment_url_for_id(attachment_id, 'edit')) self.browser.select_form(nr=1) self.browser.find_control('isobsolete').items[0].selected = True @@ -772,9 +750,6 @@ class Bugzilla(object): self.authenticate() log("Adding %s to the CC list for bug %s" % (email_address_list, bug_id)) - if self.dryrun: - return - self.browser.open(self.bug_url_for_bug_id(bug_id)) self.browser.select_form(name="changeform") self.browser["newcc"] = ", ".join(email_address_list) @@ -784,10 +759,6 @@ class Bugzilla(object): self.authenticate() log("Adding comment to bug %s" % bug_id) - if self.dryrun: - log(comment_text) - return - self.browser.open(self.bug_url_for_bug_id(bug_id)) self.browser.select_form(name="changeform") self.browser["comment"] = comment_text @@ -799,10 +770,6 @@ class Bugzilla(object): self.authenticate() log("Closing bug %s as fixed" % bug_id) - if self.dryrun: - log(comment_text) - return - self.browser.open(self.bug_url_for_bug_id(bug_id)) self.browser.select_form(name="changeform") if comment_text: @@ -821,10 +788,6 @@ class Bugzilla(object): assignee = self.username log("Assigning bug %s to %s" % (bug_id, assignee)) - if self.dryrun: - log(comment_text) - return - self.browser.open(self.bug_url_for_bug_id(bug_id)) self.browser.select_form(name="changeform") @@ -850,9 +813,6 @@ for someone to add EditBugs to your bugs.webkit.org account.""") # Bugzilla requires a comment when re-opening a bug, so we know it will # never be None. log(comment_text) - if self.dryrun: - return - self.browser.open(self.bug_url_for_bug_id(bug_id)) self.browser.select_form(name="changeform") bug_status = self.browser.find_control("bug_status", type="select") diff --git a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py index 644a8219a..e84fcbffd 100644 --- a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py +++ b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py @@ -432,23 +432,78 @@ class BuildBot(object): return build build = build.previous_build() - def last_green_revision(self): - builds = self._latest_builds_from_builders() - target_revision = builds[0].revision() - # An alternate way to do this would be to start at one revision and walk backwards - # checking builder.build_for_revision, however build_for_revision is very slow on first load. - while True: - # Make builds agree on revision - builds = [self._build_at_or_before_revision(build, target_revision) for build in builds] - if None in builds: # One of the builds failed to load from the server. - return None - min_revision = min(map(lambda build: build.revision(), builds)) - if min_revision != target_revision: - target_revision = min_revision - continue # Builds don't all agree on revision, keep searching - # Check to make sure they're all green - all_are_green = reduce(operator.and_, map(lambda build: build.is_green(), builds)) - if not all_are_green: - target_revision -= 1 + def _fetch_builder_page(self, builder): + builder_page_url = "%s/builders/%s?numbuilds=100" % (self.buildbot_url, urllib2.quote(builder.name())) + return urllib2.urlopen(builder_page_url) + + def _revisions_for_builder(self, builder): + soup = BeautifulSoup(self._fetch_builder_page(builder)) + revisions = [] + for status_row in soup.find('table').findAll('tr'): + revision_anchor = status_row.find('a') + table_cells = status_row.findAll('td') + if not table_cells or len(table_cells) < 3 or not table_cells[2].string: continue - return min_revision + if revision_anchor and revision_anchor.string and re.match(r'^\d+$', revision_anchor.string): + revisions.append((int(revision_anchor.string), 'success' in table_cells[2].string)) + return revisions + + def _find_green_revision(self, builder_revisions): + revision_statuses = {} + for builder in builder_revisions: + for revision, succeeded in builder_revisions[builder]: + revision_statuses.setdefault(revision, set()) + if succeeded and revision_statuses[revision] != None: + revision_statuses[revision].add(builder) + else: + revision_statuses[revision] = None + + # In descending order, look for a revision X with successful builds + # Once we found X, check if remaining builders succeeded in the neighborhood of X. + revisions_in_order = sorted(revision_statuses.keys(), reverse=True) + for i, revision in enumerate(revisions_in_order): + if not revision_statuses[revision]: + continue + + builders_succeeded_in_future = set() + for future_revision in sorted(revisions_in_order[:i + 1]): + if not revision_statuses[future_revision]: + break + builders_succeeded_in_future = builders_succeeded_in_future.union(revision_statuses[future_revision]) + + builders_succeeded_in_past = set() + for past_revision in revisions_in_order[i:]: + if not revision_statuses[past_revision]: + break + builders_succeeded_in_past = builders_succeeded_in_past.union(revision_statuses[past_revision]) + + if len(builders_succeeded_in_future) == len(builder_revisions) and len(builders_succeeded_in_past) == len(builder_revisions): + return revision + return None + + def last_green_revision(self, builder_name_regex): + compiled_builder_name_regex = re.compile(builder_name_regex, flags=re.IGNORECASE) + builders = [builder for builder in self.builders() if compiled_builder_name_regex.search(builder.name())] + if len(builders) > 10: + return '"%s" matches too many bots' % builder_name_regex + elif not len(builders): + return '"%s" doesn\'t match any bot' % builder_name_regex + + builder_revisions = {} + for builder in builders: + builder_revisions[builder] = self._revisions_for_builder(builder) + + result = '' + revision_with_all_builders = self._find_green_revision(builder_revisions) + if revision_with_all_builders: + result += 'The last known green revision is %d\n' % revision_with_all_builders + + for builder in builders: + succeeded_revisions = [revision for revision, succeeded in builder_revisions[builder] if succeeded] + if not succeeded_revisions: + result += '%s has had no green revision in the last %d runs' % (builder.name(), len(builder_revisions[builder])) + else: + result += '%s: %d' % (builder.name(), max(succeeded_revisions)) + result += "\n" + + return result diff --git a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_mock.py b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_mock.py index f9e27b80b..34f714985 100644 --- a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_mock.py +++ b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_mock.py @@ -90,8 +90,8 @@ class MockBuildBot(object): self._mock_builder2_status, ] - def last_green_revision(self): - return 9479 + def last_green_revision(self, builder_name): + return builder_name + ' 1: ' + str(9479) + '\n' + builder_name + ' 2: ' + str(9400) def light_tree_on_fire(self): self._mock_builder2_status["is_green"] = False diff --git a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py index 5b1e57140..7e22cf5ff 100644 --- a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py +++ b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py @@ -299,37 +299,140 @@ class BuildBotTest(unittest.TestCase): files = buildbot._parse_twisted_directory_listing(self._example_directory_listing) self.assertEqual(self._expected_files, files) - # Revision, is_green - # Ordered from newest (highest number) to oldest. - fake_builder1 = [ - [2, False], - [1, True], - ] - fake_builder2 = [ - [2, False], - [1, True], - ] - fake_builders = [ - fake_builder1, - fake_builder2, - ] - def _build_from_fake(self, fake_builder, index): - if index >= len(fake_builder): - return None - fake_build = fake_builder[index] - build = Build( - builder=fake_builder, - build_number=index, - revision=fake_build[0], - is_green=fake_build[1], - ) - def mock_previous_build(): - return self._build_from_fake(fake_builder, index + 1) - build.previous_build = mock_previous_build - return build - - def _fake_builds_at_index(self, index): - return [self._build_from_fake(builder, index) for builder in self.fake_builders] + _fake_builder_page = ''' + <body> + <div class="content"> + <h1>Some Builder</h1> + <p>(<a href="../waterfall?show=Some Builder">view in waterfall</a>)</p> + <div class="column"> + <h2>Recent Builds:</h2> + <table class="info"> + <tr> + <th>Time</th> + <th>Revision</th> + <th>Result</th> <th>Build #</th> + <th>Info</th> + </tr> + <tr class="alt"> + <td>Jan 10 15:49</td> + <td><span class="revision" title="Revision 104643"><a href="http://trac.webkit.org/changeset/104643">104643</a></span></td> + <td class="success">failure</td> <td><a href=".../37604">#37604</a></td> + <td class="left">Build successful</td> + </tr> + <tr class=""> + <td>Jan 10 15:32</td> + <td><span class="revision" title="Revision 104636"><a href="http://trac.webkit.org/changeset/104636">104636</a></span></td> + <td class="success">failure</td> <td><a href=".../37603">#37603</a></td> + <td class="left">Build successful</td> + </tr> + <tr class="alt"> + <td>Jan 10 15:18</td> + <td><span class="revision" title="Revision 104635"><a href="http://trac.webkit.org/changeset/104635">104635</a></span></td> + <td class="success">success</td> <td><a href=".../37602">#37602</a></td> + <td class="left">Build successful</td> + </tr> + <tr class=""> + <td>Jan 10 14:51</td> + <td><span class="revision" title="Revision 104633"><a href="http://trac.webkit.org/changeset/104633">104633</a></span></td> + <td class="failure">failure</td> <td><a href=".../37601">#37601</a></td> + <td class="left">Failed compile-webkit</td> + </tr> + </table> + </body>''' + _fake_builder_page_without_success = ''' + <body> + <table> + <tr class="alt"> + <td>Jan 10 15:49</td> + <td><span class="revision" title="Revision 104643"><a href="http://trac.webkit.org/changeset/104643">104643</a></span></td> + <td class="success">failure</td> + </tr> + <tr class=""> + <td>Jan 10 15:32</td> + <td><span class="revision" title="Revision 104636"><a href="http://trac.webkit.org/changeset/104636">104636</a></span></td> + <td class="success">failure</td> + </tr> + <tr class="alt"> + <td>Jan 10 15:18</td> + <td><span class="revision" title="Revision 104635"><a href="http://trac.webkit.org/changeset/104635">104635</a></span></td> + <td class="success">failure</td> + </tr> + <tr class=""> + <td>Jan 10 11:58</td> + <td><span class="revision" title="Revision ??"><a href="http://trac.webkit.org/changeset/%3F%3F">??</a></span></td> + <td class="retry">retry</td> + </tr> + <tr class=""> + <td>Jan 10 14:51</td> + <td><span class="revision" title="Revision 104633"><a href="http://trac.webkit.org/changeset/104633">104633</a></span></td> + <td class="failure">failure</td> + </tr> + </table> + </body>''' + + def test_revisions_for_builder(self): + buildbot = BuildBot() + buildbot._fetch_builder_page = lambda builder: builder.page + builder_with_success = Builder('Some builder', None) + builder_with_success.page = self._fake_builder_page + self.assertEqual(buildbot._revisions_for_builder(builder_with_success), [(104643, False), (104636, False), (104635, True), (104633, False)]) + + builder_without_success = Builder('Some builder', None) + builder_without_success.page = self._fake_builder_page_without_success + self.assertEqual(buildbot._revisions_for_builder(builder_without_success), [(104643, False), (104636, False), (104635, False), (104633, False)]) + + def test_find_green_revision(self): + buildbot = BuildBot() + self.assertEqual(buildbot._find_green_revision({ + 'Builder 1': [(1, True), (3, True)], + 'Builder 2': [(1, True), (3, False)], + 'Builder 3': [(1, True), (3, True)], + }), 1) + self.assertEqual(buildbot._find_green_revision({ + 'Builder 1': [(1, False), (3, True)], + 'Builder 2': [(1, True), (3, True)], + 'Builder 3': [(1, True), (3, True)], + }), 3) + self.assertEqual(buildbot._find_green_revision({ + 'Builder 1': [(1, True), (2, True)], + 'Builder 2': [(1, False), (2, True), (3, True)], + 'Builder 3': [(1, True), (3, True)], + }), None) + self.assertEqual(buildbot._find_green_revision({ + 'Builder 1': [(1, True), (2, True)], + 'Builder 2': [(1, True), (2, True), (3, True)], + 'Builder 3': [(1, True), (3, True)], + }), 2) + self.assertEqual(buildbot._find_green_revision({ + 'Builder 1': [(1, False), (2, True)], + 'Builder 2': [(1, True), (3, True)], + 'Builder 3': [(1, True), (3, True)], + }), None) + self.assertEqual(buildbot._find_green_revision({ + 'Builder 1': [(1, True), (3, True)], + 'Builder 2': [(1, False), (2, True), (3, True), (4, True)], + 'Builder 3': [(2, True), (4, True)], + }), 3) + self.assertEqual(buildbot._find_green_revision({ + 'Builder 1': [(1, True), (3, True)], + 'Builder 2': [(1, False), (2, True), (3, True), (4, False)], + 'Builder 3': [(2, True), (4, True)], + }), None) + self.assertEqual(buildbot._find_green_revision({ + 'Builder 1': [(1, True), (3, True)], + 'Builder 2': [(1, False), (2, True), (3, True), (4, False)], + 'Builder 3': [(2, True), (3, True), (4, True)], + }), 3) + self.assertEqual(buildbot._find_green_revision({ + 'Builder 1': [(1, True), (2, True)], + 'Builder 2': [], + 'Builder 3': [(1, True), (2, True)], + }), None) + self.assertEqual(buildbot._find_green_revision({ + 'Builder 1': [(1, True), (3, False), (5, True), (10, True), (12, False)], + 'Builder 2': [(1, True), (3, False), (7, True), (9, True), (12, False)], + 'Builder 3': [(1, True), (3, True), (7, True), (11, False), (12, True)], + }), 7) def test_last_green_revision(self): buildbot = BuildBot() @@ -337,8 +440,24 @@ class BuildBotTest(unittest.TestCase): def mock_builds_from_builders(): return self._fake_builds_at_index(0) + # Revision, is_green + # Ordered from newest (highest number) to oldest. + fake_builder1 = Builder("Fake Builder 1", None) + fake_builder1.revisions = [(1, True), (3, False), (5, True), (10, True), (12, False)] + fake_builder2 = Builder("Fake Builder 2", None) + fake_builder2.revisions = [(1, True), (3, False), (7, True), (9, True), (12, False)] + some_builder = Builder("Some Builder", None) + some_builder.revisions = [(1, True), (3, True), (7, True), (11, False), (12, True)] + + buildbot.builders = lambda: [fake_builder1, fake_builder2, some_builder] + buildbot._revisions_for_builder = lambda builder: builder.revisions buildbot._latest_builds_from_builders = mock_builds_from_builders - self.assertEqual(buildbot.last_green_revision(), 1) + self.assertEqual(buildbot.last_green_revision(''), + "The last known green revision is 7\nFake Builder 1: 10\nFake Builder 2: 9\nSome Builder: 12\n") + + some_builder.revisions = [(1, False), (3, False)] + self.assertEqual(buildbot.last_green_revision(''), + "Fake Builder 1: 10\nFake Builder 2: 9\nSome Builder has had no green revision in the last 2 runs\n") def _fetch_build(self, build_number): if build_number == 5: diff --git a/Tools/Scripts/webkitpy/common/net/file_uploader.py b/Tools/Scripts/webkitpy/common/net/file_uploader.py index 66e49e866..aa3488bbf 100644 --- a/Tools/Scripts/webkitpy/common/net/file_uploader.py +++ b/Tools/Scripts/webkitpy/common/net/file_uploader.py @@ -84,31 +84,35 @@ def _encode_multipart_form_data(fields, files): class FileUploader(object): - def __init__(self, url): + def __init__(self, url, timeout_seconds): self._url = url + self._timeout_seconds = timeout_seconds - def _upload_files(self, attrs, file_objs): - # FIXME: We should use the same variable names for the formal and actual parameters. - content_type, data = _encode_multipart_form_data(attrs, file_objs) - headers = { - "Content-Type": content_type, - } - # FIXME: We should talk to the network via a Host object. - request = urllib2.Request(self._url, data, headers) - urllib2.urlopen(request) - - def upload(self, params, files, timeout_seconds): + def upload_single_text_file(self, filesystem, content_type, filename): + return self._upload_data(content_type, filesystem.read_text_file(filename)) + + def upload_as_multipart_form_data(self, filesystem, files, attrs): file_objs = [] for filename, path in files: # FIXME: We should talk to the filesytem via a Host object. with codecs.open(path, "rb") as file: file_objs.append(('file', filename, file.read())) + # FIXME: We should use the same variable names for the formal and actual parameters. + content_type, data = _encode_multipart_form_data(attrs, file_objs) + return self._upload_data(content_type, data) + + def _upload_data(self, content_type, data): + def callback(): + request = urllib2.Request(self._url, data, {"Content-Type": content_type}) + return urllib2.urlopen(request) + orig_timeout = socket.getdefaulttimeout() + response = None try: # FIXME: We shouldn't mutate global static state. - socket.setdefaulttimeout(timeout_seconds) - NetworkTransaction(timeout_seconds=timeout_seconds).run( - lambda: self._upload_files(params, file_objs)) + socket.setdefaulttimeout(self._timeout_seconds) + response = NetworkTransaction(timeout_seconds=self._timeout_seconds).run(callback) finally: socket.setdefaulttimeout(orig_timeout) + return response diff --git a/Tools/Scripts/webkitpy/common/system/executive.py b/Tools/Scripts/webkitpy/common/system/executive.py index 0481f0472..06f870c72 100644 --- a/Tools/Scripts/webkitpy/common/system/executive.py +++ b/Tools/Scripts/webkitpy/common/system/executive.py @@ -27,12 +27,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -try: - # This API exists only in Python 2.6 and higher. :( - import multiprocessing -except ImportError: - multiprocessing = None - +import multiprocessing import ctypes import errno import logging @@ -160,21 +155,7 @@ class Executive(object): return child_output def cpu_count(self): - if multiprocessing: - return multiprocessing.cpu_count() - # Darn. We don't have the multiprocessing package. - system_name = platform.system() - if system_name == "Darwin": - return int(self.run_command(["sysctl", "-n", "hw.ncpu"])) - elif system_name == "Windows": - return int(os.environ.get('NUMBER_OF_PROCESSORS', 1)) - elif system_name == "Linux": - num_cores = os.sysconf("SC_NPROCESSORS_ONLN") - if isinstance(num_cores, int) and num_cores > 0: - return num_cores - # This quantity is a lie but probably a reasonable guess for modern - # machines. - return 2 + return multiprocessing.cpu_count() @staticmethod def interpreter_for_script(script_path, fs=None): diff --git a/Tools/Scripts/webkitpy/common/system/executive_mock.py b/Tools/Scripts/webkitpy/common/system/executive_mock.py index c3a4c4d5f..f698235e9 100644 --- a/Tools/Scripts/webkitpy/common/system/executive_mock.py +++ b/Tools/Scripts/webkitpy/common/system/executive_mock.py @@ -34,6 +34,10 @@ from webkitpy.common.system.executive import ScriptError # FIXME: This should be unified with MockExecutive2 class MockExecutive(object): + @staticmethod + def ignore_error(error): + pass + def __init__(self, should_log=False, should_throw=False, should_throw_when_run=None): self._should_log = should_log self._should_throw = should_throw @@ -79,6 +83,10 @@ class MockExecutive(object): class MockExecutive2(object): + @staticmethod + def ignore_error(error): + pass + def __init__(self, output='', exit_code=0, exception=None, run_command_fn=None, stderr=''): self._output = output diff --git a/Tools/Scripts/webkitpy/common/system/executive_unittest.py b/Tools/Scripts/webkitpy/common/system/executive_unittest.py index a0878f9ce..c63ff3555 100644 --- a/Tools/Scripts/webkitpy/common/system/executive_unittest.py +++ b/Tools/Scripts/webkitpy/common/system/executive_unittest.py @@ -33,9 +33,14 @@ import subprocess import sys import unittest +# Since we execute this script directly as part of the unit tests, we need to ensure +# that Tools/Scripts is in sys.path for the next imports to work correctly. +script_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) +if script_dir not in sys.path: + sys.path.append(script_dir) + from webkitpy.common.system.executive import Executive, ScriptError from webkitpy.common.system.filesystem_mock import MockFileSystem -from webkitpy.test import cat, echo class ScriptErrorTest(unittest.TestCase): @@ -64,8 +69,11 @@ def never_ending_command(): return ['yes'] -class ExecutiveTest(unittest.TestCase): +def command_line(cmd, *args): + return [sys.executable, __file__, '--' + cmd] + list(args) + +class ExecutiveTest(unittest.TestCase): def assert_interpreter_for_content(self, intepreter, content): fs = MockFileSystem() file_path = None @@ -102,8 +110,8 @@ class ExecutiveTest(unittest.TestCase): executive = Executive() self.assertRaises(AssertionError, executive.run_command, "echo") self.assertRaises(AssertionError, executive.run_command, u"echo") - executive.run_command(echo.command_arguments('foo')) - executive.run_command(tuple(echo.command_arguments('foo'))) + executive.run_command(command_line('echo', 'foo')) + executive.run_command(tuple(command_line('echo', 'foo'))) def test_run_command_with_unicode(self): """Validate that it is safe to pass unicode() objects @@ -124,24 +132,24 @@ class ExecutiveTest(unittest.TestCase): executive = Executive() - output = executive.run_command(cat.command_arguments(), input=unicode_tor_input) + output = executive.run_command(command_line('cat'), input=unicode_tor_input) self.assertEquals(output, unicode_tor_output) - output = executive.run_command(echo.command_arguments("-n", unicode_tor_input)) + output = executive.run_command(command_line('echo', unicode_tor_input)) self.assertEquals(output, unicode_tor_output) - output = executive.run_command(echo.command_arguments("-n", unicode_tor_input), decode_output=False) + output = executive.run_command(command_line('echo', unicode_tor_input), decode_output=False) self.assertEquals(output, encoded_tor) # Make sure that str() input also works. - output = executive.run_command(cat.command_arguments(), input=encoded_tor, decode_output=False) + output = executive.run_command(command_line('cat'), input=encoded_tor, decode_output=False) self.assertEquals(output, encoded_tor) # FIXME: We should only have one run* method to test - output = executive.run_and_throw_if_fail(echo.command_arguments("-n", unicode_tor_input), quiet=True) + output = executive.run_and_throw_if_fail(command_line('echo', unicode_tor_input), quiet=True) self.assertEquals(output, unicode_tor_output) - output = executive.run_and_throw_if_fail(echo.command_arguments("-n", unicode_tor_input), quiet=True, decode_output=False) + output = executive.run_and_throw_if_fail(command_line('echo', unicode_tor_input), quiet=True, decode_output=False) self.assertEquals(output, encoded_tor) def test_kill_process(self): @@ -207,3 +215,17 @@ class ExecutiveTest(unittest.TestCase): executive = Executive() pids = executive.running_pids() self.assertTrue(os.getpid() in pids) + + +def main(platform, stdin, stdout, cmd, args): + if platform == 'win32' and hasattr(stdout, 'fileno'): + import msvcrt + msvcrt.setmode(stdout.fileno(), os.O_BINARY) + if cmd == '--cat': + stdout.write(stdin.read()) + elif cmd == '--echo': + stdout.write(' '.join(args)) + return 0 + +if __name__ == '__main__' and len(sys.argv) > 1 and sys.argv[1] in ('--cat', '--echo'): + sys.exit(main(sys.platform, sys.stdin, sys.stdout, sys.argv[1], sys.argv[2:])) diff --git a/Tools/Scripts/webkitpy/common/system/fileutils.py b/Tools/Scripts/webkitpy/common/system/fileutils.py deleted file mode 100644 index 55821f835..000000000 --- a/Tools/Scripts/webkitpy/common/system/fileutils.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) 2010 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: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. 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. -# -# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 sys - - -def make_stdout_binary(): - """Puts sys.stdout into binary mode (on platforms that have a distinction - between text and binary mode).""" - if sys.platform != 'win32' or not hasattr(sys.stdout, 'fileno'): - return - import msvcrt - import os - msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) diff --git a/Tools/Scripts/webkitpy/common/system/platforminfo_mock.py b/Tools/Scripts/webkitpy/common/system/platforminfo_mock.py index 71c3e8ce7..7302761de 100644 --- a/Tools/Scripts/webkitpy/common/system/platforminfo_mock.py +++ b/Tools/Scripts/webkitpy/common/system/platforminfo_mock.py @@ -32,13 +32,13 @@ class MockPlatformInfo(object): os_version = 'snowleopard' def is_mac(self): - return True + return self.os_name == 'mac' def is_linux(self): - return False + return self.os_name == 'linux' - def is_windows(self): - return False + def is_win(self): + return self.os_name == 'win' def display_name(self): return "MockPlatform 1.0" diff --git a/Tools/Scripts/webkitpy/common/system/systemhost_mock.py b/Tools/Scripts/webkitpy/common/system/systemhost_mock.py index 61f8972bf..f3bc94139 100644 --- a/Tools/Scripts/webkitpy/common/system/systemhost_mock.py +++ b/Tools/Scripts/webkitpy/common/system/systemhost_mock.py @@ -35,11 +35,15 @@ from webkitpy.common.system.workspace_mock import MockWorkspace class MockSystemHost(object): - def __init__(self, log_executive=False, executive_throws_when_run=None): + def __init__(self, log_executive=False, executive_throws_when_run=None, os_name=None, os_version=None): self.executive = MockExecutive(should_log=log_executive, should_throw_when_run=executive_throws_when_run) self.filesystem = MockFileSystem() self.user = MockUser() self.platform = MockPlatformInfo() + if os_name: + self.platform.os_name = os_name + if os_version: + self.platform.os_version = os_version # FIXME: Should this take pointers to the filesystem and the executive? self.workspace = MockWorkspace() |
