summaryrefslogtreecommitdiffstats
path: root/Tools/Scripts/webkitpy/common
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/Scripts/webkitpy/common')
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/scm.py57
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/scm_unittest.py13
-rw-r--r--Tools/Scripts/webkitpy/common/config/build.py2
-rw-r--r--Tools/Scripts/webkitpy/common/config/build_unittest.py1
-rw-r--r--Tools/Scripts/webkitpy/common/config/committers.py6
-rw-r--r--Tools/Scripts/webkitpy/common/config/ports.py17
-rw-r--r--Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py13
-rw-r--r--Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py25
-rw-r--r--Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py2
-rw-r--r--Tools/Scripts/webkitpy/common/net/credentials.py3
-rw-r--r--Tools/Scripts/webkitpy/common/net/layouttestresults.py13
-rw-r--r--Tools/Scripts/webkitpy/common/net/layouttestresults_unittest.py6
-rw-r--r--Tools/Scripts/webkitpy/common/net/statusserver.py3
-rw-r--r--Tools/Scripts/webkitpy/common/system/executive.py17
-rw-r--r--Tools/Scripts/webkitpy/common/system/executive_unittest.py28
-rw-r--r--Tools/Scripts/webkitpy/common/system/filesystem.py8
-rw-r--r--Tools/Scripts/webkitpy/common/system/filesystem_mock.py38
-rw-r--r--Tools/Scripts/webkitpy/common/system/filesystem_unittest.py21
-rw-r--r--Tools/Scripts/webkitpy/common/system/user.py5
19 files changed, 226 insertions, 52 deletions
diff --git a/Tools/Scripts/webkitpy/common/checkout/scm.py b/Tools/Scripts/webkitpy/common/checkout/scm.py
index e436402..3e8d5e5 100644
--- a/Tools/Scripts/webkitpy/common/checkout/scm.py
+++ b/Tools/Scripts/webkitpy/common/checkout/scm.py
@@ -134,8 +134,9 @@ def commit_error_handler(error):
class AuthenticationError(Exception):
- def __init__(self, server_host):
+ def __init__(self, server_host, prompt_for_password=False):
self.server_host = server_host
+ self.prompt_for_password = prompt_for_password
class AmbiguousCommitError(Exception):
@@ -291,7 +292,7 @@ class SCM:
def revert_files(self, file_paths):
self._subclass_must_implement()
- def commit_with_message(self, message, username=None, git_commit=None, force_squash=False, changed_files=None):
+ def commit_with_message(self, message, username=None, password=None, git_commit=None, force_squash=False, changed_files=None):
self._subclass_must_implement()
def svn_commit_log(self, svn_revision):
@@ -319,8 +320,19 @@ class SCM:
return []
-class SVN(SCM):
- # FIXME: We should move these values to a WebKit-specific config file.
+# A mixin class that represents common functionality for SVN and Git-SVN.
+class SVNRepository:
+ def has_authorization_for_realm(self, realm, home_directory=os.getenv("HOME")):
+ # Assumes find and grep are installed.
+ if not os.path.isdir(os.path.join(home_directory, ".subversion")):
+ return False
+ find_args = ["find", ".subversion", "-type", "f", "-exec", "grep", "-q", realm, "{}", ";", "-print"]
+ find_output = self.run(find_args, cwd=home_directory, error_handler=Executive.ignore_error).rstrip()
+ return find_output and os.path.isfile(os.path.join(home_directory, find_output))
+
+
+class SVN(SCM, SVNRepository):
+ # FIXME: These belong in common.config.urls
svn_server_host = "svn.webkit.org"
svn_server_realm = "<http://svn.webkit.org:80> Mac OS Forge"
@@ -374,14 +386,6 @@ class SVN(SCM):
def commit_success_regexp():
return "^Committed revision (?P<svn_revision>\d+)\.$"
- def has_authorization_for_realm(self, realm=svn_server_realm, home_directory=os.getenv("HOME")):
- # Assumes find and grep are installed.
- if not os.path.isdir(os.path.join(home_directory, ".subversion")):
- return False
- find_args = ["find", ".subversion", "-type", "f", "-exec", "grep", "-q", realm, "{}", ";", "-print"];
- find_output = self.run(find_args, cwd=home_directory, error_handler=Executive.ignore_error).rstrip()
- return find_output and os.path.isfile(os.path.join(home_directory, find_output))
-
@memoized
def svn_version(self):
return self.run(['svn', '--version', '--quiet'])
@@ -556,11 +560,11 @@ class SVN(SCM):
# FIXME: This should probably use cwd=self.checkout_root.
self.run(['svn', 'revert'] + file_paths)
- def commit_with_message(self, message, username=None, git_commit=None, force_squash=False, changed_files=None):
+ def commit_with_message(self, message, username=None, password=None, git_commit=None, force_squash=False, changed_files=None):
# git-commit and force are not used by SVN.
svn_commit_args = ["svn", "commit"]
- if not username and not self.has_authorization_for_realm():
+ if not username and not self.has_authorization_for_realm(self.svn_server_realm):
raise AuthenticationError(self.svn_server_host)
if username:
svn_commit_args.extend(["--username", username])
@@ -577,8 +581,7 @@ class SVN(SCM):
# 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."
- # FIXME: Should this use cwd=self.checkout_root?
- return self.run(svn_commit_args, error_handler=commit_error_handler)
+ return self.run(svn_commit_args, cwd=self.checkout_root, error_handler=commit_error_handler)
def svn_commit_log(self, svn_revision):
svn_revision = self.strip_r_from_svn_revision(svn_revision)
@@ -599,7 +602,7 @@ class SVN(SCM):
# All git-specific logic should go here.
-class Git(SCM):
+class Git(SCM, SVNRepository):
def __init__(self, cwd, executive=None):
SCM.__init__(self, cwd, executive)
self._check_git_architecture()
@@ -834,7 +837,7 @@ class Git(SCM):
if num_local_commits > 1 or (num_local_commits > 0 and not working_directory_is_clean):
raise AmbiguousCommitError(num_local_commits, working_directory_is_clean)
- def commit_with_message(self, message, username=None, git_commit=None, force_squash=False, changed_files=None):
+ def commit_with_message(self, message, username=None, password=None, git_commit=None, force_squash=False, changed_files=None):
# Username is ignored during Git commits.
working_directory_is_clean = self.working_directory_is_clean()
@@ -844,7 +847,7 @@ class Git(SCM):
if working_directory_is_clean:
raise ScriptError(message="The working copy is not modified. --git-commit=HEAD.. only commits working copy changes.")
self.commit_locally_with_message(message)
- return self._commit_on_branch(message, 'HEAD')
+ return self._commit_on_branch(message, 'HEAD', username=username, password=password)
# Need working directory changes to be committed so we can checkout the merge branch.
if not working_directory_is_clean:
@@ -852,15 +855,15 @@ class Git(SCM):
# That will modify the working-copy and cause us to hit this error.
# The ChangeLog modification could be made to modify the existing local commit.
raise ScriptError(message="Working copy is modified. Cannot commit individual git_commits.")
- return self._commit_on_branch(message, git_commit)
+ return self._commit_on_branch(message, git_commit, username=username, password=password)
if not force_squash:
self._assert_can_squash(working_directory_is_clean)
self.run(['git', 'reset', '--soft', self.remote_merge_base()])
self.commit_locally_with_message(message)
- return self.push_local_commits_to_server()
+ return self.push_local_commits_to_server(username=username, password=password)
- def _commit_on_branch(self, message, git_commit):
+ def _commit_on_branch(self, message, git_commit, username=None, password=None):
branch_ref = self.run(['git', 'symbolic-ref', 'HEAD']).strip()
branch_name = branch_ref.replace('refs/heads/', '')
commit_ids = self.commit_ids_from_commitish_arguments([git_commit])
@@ -889,7 +892,7 @@ class Git(SCM):
self.run(['git', 'cherry-pick', '--no-commit', commit])
self.run(['git', 'commit', '-m', message])
- output = self.push_local_commits_to_server()
+ output = self.push_local_commits_to_server(username=username, password=password)
except Exception, e:
log("COMMIT FAILED: " + str(e))
output = "Commit failed."
@@ -937,11 +940,15 @@ class Git(SCM):
def commit_locally_with_message(self, message):
self.run(['git', 'commit', '--all', '-F', '-'], input=message)
- def push_local_commits_to_server(self):
+ def push_local_commits_to_server(self, username=None, password=None):
dcommit_command = ['git', 'svn', 'dcommit']
if self.dryrun:
dcommit_command.append('--dry-run')
- output = self.run(dcommit_command, error_handler=commit_error_handler)
+ if 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)
# Return a string which looks like a commit so that things which parse this output will succeed.
if self.dryrun:
output += "\nCommitted r0"
diff --git a/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py b/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py
index 79b354d..ab3f45a 100644
--- a/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py
+++ b/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py
@@ -650,6 +650,13 @@ Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
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")
+ commit_text = self.scm.commit_with_message("another test commit", username)
+ os.chdir("..")
+ self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '6')
+
def test_commit_text_parsing(self):
self._shared_test_commit_with_message()
@@ -657,7 +664,7 @@ Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
self._shared_test_commit_with_message("dbates@webkit.org")
def test_commit_without_authorization(self):
- self.scm.has_authorization_for_realm = lambda: False
+ self.scm.has_authorization_for_realm = lambda realm: False
self.assertRaises(AuthenticationError, self._shared_test_commit_with_message)
def test_has_authorization_for_realm(self):
@@ -667,7 +674,7 @@ Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
os.mkdir(svn_config_dir_path)
fake_webkit_auth_file = os.path.join(svn_config_dir_path, "fake_webkit_auth_file")
write_into_file_at_path(fake_webkit_auth_file, SVN.svn_server_realm)
- self.assertTrue(scm.has_authorization_for_realm(home_directory=fake_home_dir))
+ self.assertTrue(scm.has_authorization_for_realm(SVN.svn_server_realm, home_directory=fake_home_dir))
os.remove(fake_webkit_auth_file)
os.rmdir(svn_config_dir_path)
os.rmdir(fake_home_dir)
@@ -677,7 +684,7 @@ Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
fake_home_dir = tempfile.mkdtemp(suffix="fake_home_dir")
svn_config_dir_path = os.path.join(fake_home_dir, ".subversion")
os.mkdir(svn_config_dir_path)
- self.assertFalse(scm.has_authorization_for_realm(home_directory=fake_home_dir))
+ self.assertFalse(scm.has_authorization_for_realm(SVN.svn_server_realm, home_directory=fake_home_dir))
os.rmdir(svn_config_dir_path)
os.rmdir(fake_home_dir)
diff --git a/Tools/Scripts/webkitpy/common/config/build.py b/Tools/Scripts/webkitpy/common/config/build.py
index 42d0721..d25d606 100644
--- a/Tools/Scripts/webkitpy/common/config/build.py
+++ b/Tools/Scripts/webkitpy/common/config/build.py
@@ -97,10 +97,12 @@ def _should_file_trigger_build(target_platform, file):
(r"(?:^|/)GNUmakefile\.am$", ["gtk"]),
(r"/\w+Chromium\w*\.(?:cpp|h|mm)$", ["chromium"]),
(r"Mac\.(?:cpp|h|mm)$", ["mac"]),
+ (r"\.(?:vcproj|vsprops|sln)$", ["win"]),
(r"\.exp(?:\.in)?$", ["mac"]),
(r"\.gypi?", ["chromium"]),
(r"\.order$", ["mac"]),
(r"\.pr[io]$", ["qt"]),
+ (r"\.vcproj/", ["win"]),
(r"\.xcconfig$", ["mac"]),
(r"\.xcodeproj/", ["mac"]),
]
diff --git a/Tools/Scripts/webkitpy/common/config/build_unittest.py b/Tools/Scripts/webkitpy/common/config/build_unittest.py
index 9144874..6bd71e8 100644
--- a/Tools/Scripts/webkitpy/common/config/build_unittest.py
+++ b/Tools/Scripts/webkitpy/common/config/build_unittest.py
@@ -32,6 +32,7 @@ class ShouldBuildTest(unittest.TestCase):
(["Websites/bugs.webkit.org/foo", "Source/WebCore/bar"], ["*"]),
(["Websites/bugs.webkit.org/foo"], []),
(["Source/JavaScriptCore/JavaScriptCore.xcodeproj/foo"], ["mac-leopard", "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-snowleopard"]),
(["LayoutTests/foo"], ["*"]),
diff --git a/Tools/Scripts/webkitpy/common/config/committers.py b/Tools/Scripts/webkitpy/common/config/committers.py
index fd9bdbb..50506c8 100644
--- a/Tools/Scripts/webkitpy/common/config/committers.py
+++ b/Tools/Scripts/webkitpy/common/config/committers.py
@@ -90,7 +90,7 @@ committers_unable_to_review = [
Committer("Brett Wilson", "brettw@chromium.org", "brettx"),
Committer("Cameron McCormack", "cam@webkit.org", "heycam"),
Committer("Carlos Garcia Campos", ["cgarcia@igalia.com", "carlosgc@gnome.org", "carlosgc@webkit.org"], "KaL"),
- Committer("Carol Szabo", "carol.szabo@nokia.com"),
+ Committer("Carol Szabo", "carol@webkit.org", "cszabo1"),
Committer("Chang Shu", ["cshu@webkit.org", "Chang.Shu@nokia.com"], "cshu"),
Committer("Chris Evans", "cevans@google.com"),
Committer("Chris Petersen", "cpetersen@apple.com", "cpetersen"),
@@ -129,6 +129,7 @@ committers_unable_to_review = [
Committer("Jakob Petsovits", ["jpetsovits@rim.com", "jpetso@gmx.at"], "jpetso"),
Committer("Jakub Wieczorek", "jwieczorek@webkit.org", "fawek"),
Committer("James Hawkins", ["jhawkins@chromium.org", "jhawkins@google.com"], "jhawkins"),
+ Committer("James Kozianski", ["koz@chromium.org", "koz@google.com"], "koz"),
Committer("James Simonsen", "simonjam@chromium.org", "simonjam"),
Committer("Jay Civelli", "jcivelli@chromium.org", "jcivelli"),
Committer("Jeff Miller", "jeffm@apple.com", "jeffm"),
@@ -204,8 +205,9 @@ committers_unable_to_review = [
Committer("Victor Wang", "victorw@chromium.org", "victorw"),
Committer("Vitaly Repeshko", "vitalyr@chromium.org"),
Committer("William Siegrist", "wsiegrist@apple.com", "wms"),
+ Committer("W. James MacLean", "wjmaclean@chromium.org", "wjmaclean"),
Committer("Xiaomei Ji", "xji@chromium.org", "xji"),
- Committer("Yael Aharon", "yael.aharon@nokia.com"),
+ Committer("Yael Aharon", "yael.aharon@nokia.com", "yael"),
Committer("Yaar Schnitman", ["yaar@chromium.org", "yaar@google.com"]),
Committer("Yong Li", ["yong.li.webkit@gmail.com", "yong.li@torchmobile.com"], "yong"),
Committer("Yongjun Zhang", "yongjun.zhang@nokia.com"),
diff --git a/Tools/Scripts/webkitpy/common/config/ports.py b/Tools/Scripts/webkitpy/common/config/ports.py
index 9a5a269..444a4ac 100644
--- a/Tools/Scripts/webkitpy/common/config/ports.py
+++ b/Tools/Scripts/webkitpy/common/config/ports.py
@@ -30,6 +30,7 @@
import os
import platform
+import sys
from webkitpy.common.system.executive import Executive
@@ -43,7 +44,13 @@ class WebKitPort(object):
@classmethod
def script_shell_command(cls, script_name):
- return [cls.script_path(script_name)]
+ script_path = cls.script_path(script_name)
+ # Win32 does not support shebang. We need to detect the interpreter ourself.
+ if sys.platform == 'win32':
+ interpreter = Executive.interpreter_for_script(script_path)
+ if interpreter:
+ return [interpreter, script_path]
+ return [script_path]
@staticmethod
def port(port_name):
@@ -83,6 +90,14 @@ class WebKitPort(object):
return cls.script_shell_command("update-webkit")
@classmethod
+ def check_webkit_style_command(cls):
+ return cls.script_shell_command("check-webkit-style")
+
+ @classmethod
+ def prepare_changelog_command(cls):
+ return cls.script_shell_command("prepare-ChangeLog")
+
+ @classmethod
def build_webkit_command(cls, build_style=None):
command = cls.script_shell_command("build-webkit")
if build_style == "debug":
diff --git a/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py b/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py
index 8daf92e..c781dfb 100644
--- a/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py
+++ b/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py
@@ -46,7 +46,7 @@ from webkitpy.common.config import committers
from webkitpy.common.net.credentials import Credentials
from webkitpy.common.system.user import User
from webkitpy.thirdparty.autoinstalled.mechanize import Browser
-from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup, SoupStrainer
+from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup, BeautifulStoneSoup, SoupStrainer
# FIXME: parse_bug_id should not be a free function.
@@ -74,7 +74,9 @@ def parse_bug_id_from_changelog(message):
match = re.search("^\s*" + Bugzilla.bug_url_long + "$", message, re.MULTILINE)
if match:
return int(match.group('bug_id'))
- return None
+ # We weren't able to find a bug URL in the format used by prepare-ChangeLog. Fall back to the
+ # first bug URL found anywhere in the message.
+ return parse_bug_id(message)
def timestamp():
return datetime.now().strftime("%Y%m%d%H%M%S")
@@ -218,7 +220,8 @@ class Bugzilla(object):
# script.
self.browser.set_handle_robots(False)
- # FIXME: Much of this should go into some sort of config module:
+ # FIXME: Much of this should go into some sort of config module,
+ # such as common.config.urls.
bug_server_host = "bugs.webkit.org"
bug_server_regex = "https?://%s/" % re.sub('\.', '\\.', bug_server_host)
bug_server_url = "https://%s/" % bug_server_host
@@ -270,7 +273,7 @@ class Bugzilla(object):
def _string_contents(self, soup):
# WebKit's bugzilla instance uses UTF-8.
- # BeautifulSoup always returns Unicode strings, however
+ # BeautifulStoneSoup always returns Unicode strings, however
# the .string method returns a (unicode) NavigableString.
# NavigableString can confuse other parts of the code, so we
# convert from NavigableString to a real unicode() object using unicode().
@@ -317,7 +320,7 @@ class Bugzilla(object):
return [Bug(self._parse_bug_dictionary_from_xml(unicode(bug_xml)), self) for bug_xml in soup('bug')]
def _parse_bug_dictionary_from_xml(self, page):
- soup = BeautifulSoup(page)
+ soup = BeautifulStoneSoup(page, convertEntities=BeautifulStoneSoup.XML_ENTITIES)
bug = {}
bug["id"] = int(soup.find("bug_id").string)
bug["title"] = self._string_contents(soup.find("short_desc"))
diff --git a/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py b/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py
index 2e75ca9..b996b7c 100644
--- a/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py
+++ b/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py
@@ -104,7 +104,7 @@ class BugzillaTest(unittest.TestCase):
<bug>
<bug_id>32585</bug_id>
<creation_ts>2009-12-15 15:17 PST</creation_ts>
- <short_desc>bug to test webkit-patch and commit-queue failures</short_desc>
+ <short_desc>bug to test webkit-patch&apos;s and commit-queue&apos;s failures</short_desc>
<delta_ts>2009-12-27 21:04:50 PST</delta_ts>
<reporter_accessible>1</reporter_accessible>
<cclist_accessible>1</cclist_accessible>
@@ -173,7 +173,7 @@ ZEZpbmlzaExvYWRXaXRoUmVhc29uOnJlYXNvbl07Cit9CisKIEBlbmQKIAogI2VuZGlmCg==
_expected_example_bug_parsing = {
"id" : 32585,
- "title" : u"bug to test webkit-patch and commit-queue failures",
+ "title" : u"bug to test webkit-patch's and commit-queue's failures",
"cc_emails" : ["foo@bar.com", "example@example.com"],
"reporter_email" : "eric@webkit.org",
"assigned_to_email" : "webkit-unassigned@lists.webkit.org",
@@ -203,7 +203,7 @@ ZEZpbmlzaExvYWRXaXRoUmVhc29uOnJlYXNvbl07Cit9CisKIEBlbmQKIAogI2VuZGlmCg==
'''
- self.assertEquals(None, parse_bug_id_from_changelog(commit_text))
+ self.assertEquals(56988, parse_bug_id_from_changelog(commit_text))
commit_text = '''
2011-03-23 Ojan Vafai <ojan@chromium.org>
@@ -218,6 +218,25 @@ ZEZpbmlzaExvYWRXaXRoUmVhc29uOnJlYXNvbl07Cit9CisKIEBlbmQKIAogI2VuZGlmCg==
self.assertEquals(12345, parse_bug_id_from_changelog(commit_text))
+ commit_text = '''
+2011-03-31 Adam Roben <aroben@apple.com>
+
+ Quote the executable path we pass to ::CreateProcessW
+
+ This will ensure that spaces in the path will be interpreted correctly.
+
+ Fixes <http://webkit.org/b/57569> Web process sometimes fails to launch when there are
+ spaces in its path
+
+ Reviewed by Steve Falkenburg.
+
+ * UIProcess/Launcher/win/ProcessLauncherWin.cpp:
+ (WebKit::ProcessLauncher::launchProcess): Surround the executable path in quotes.
+
+ '''
+
+ self.assertEquals(57569, parse_bug_id_from_changelog(commit_text))
+
# FIXME: This should move to a central location and be shared by more unit tests.
def _assert_dictionaries_equal(self, actual, expected):
diff --git a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py
index d23a6cc..5fdf184 100644
--- a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py
+++ b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py
@@ -267,7 +267,7 @@ class Build(object):
class BuildBot(object):
- # FIXME: This should move into some sort of webkit_config.py
+ # FIXME: This should move into common.config.urls.
default_host = "build.webkit.org"
def __init__(self, host=default_host):
diff --git a/Tools/Scripts/webkitpy/common/net/credentials.py b/Tools/Scripts/webkitpy/common/net/credentials.py
index 30480b3..d76405b 100644
--- a/Tools/Scripts/webkitpy/common/net/credentials.py
+++ b/Tools/Scripts/webkitpy/common/net/credentials.py
@@ -29,7 +29,6 @@
#
# Python module for reading stored web credentials from the OS.
-import getpass
import os
import platform
import re
@@ -149,7 +148,7 @@ class Credentials(object):
if not username:
username = User.prompt("%s login: " % self.host)
if not password:
- password = getpass.getpass("%s password for %s: " % (self.host, username))
+ password = User.prompt_password("%s password for %s: " % (self.host, username))
self._offer_to_store_credentials_in_keyring(username, password)
return (username, password)
diff --git a/Tools/Scripts/webkitpy/common/net/layouttestresults.py b/Tools/Scripts/webkitpy/common/net/layouttestresults.py
index 249ecc9..a0e8ae4 100644
--- a/Tools/Scripts/webkitpy/common/net/layouttestresults.py
+++ b/Tools/Scripts/webkitpy/common/net/layouttestresults.py
@@ -134,6 +134,19 @@ class LayoutTestResults(object):
def __init__(self, test_results):
self._test_results = test_results
+ self._failure_limit_count = None
+
+ # FIXME: run-webkit-tests should store the --exit-after-N-failures value
+ # (or some indication of early exit) somewhere in the results.html/results.json
+ # file. Until it does, callers should set the limit to
+ # --exit-after-N-failures value used in that run. Consumers of LayoutTestResults
+ # may use that value to know if absence from the failure list means PASS.
+ # https://bugs.webkit.org/show_bug.cgi?id=58481
+ def set_failure_limit_count(self, limit):
+ self._failure_limit_count = limit
+
+ def failure_limit_count(self):
+ return self._failure_limit_count
def test_results(self):
return self._test_results
diff --git a/Tools/Scripts/webkitpy/common/net/layouttestresults_unittest.py b/Tools/Scripts/webkitpy/common/net/layouttestresults_unittest.py
index 01b91b8..d25ad02 100644
--- a/Tools/Scripts/webkitpy/common/net/layouttestresults_unittest.py
+++ b/Tools/Scripts/webkitpy/common/net/layouttestresults_unittest.py
@@ -61,6 +61,12 @@ class LayoutTestResultsTest(unittest.TestCase):
</html>
"""
+ def test_set_failure_limit_count(self):
+ results = LayoutTestResults([])
+ self.assertEquals(results.failure_limit_count(), None)
+ results.set_failure_limit_count(10)
+ self.assertEquals(results.failure_limit_count(), 10)
+
def test_parse_layout_test_results(self):
failures = [test_failures.FailureMissingResult(), test_failures.FailureMissingImageHash(), test_failures.FailureMissingImage()]
testname = 'fast/repaint/no-caret-repaint-in-non-content-editable-element.html'
diff --git a/Tools/Scripts/webkitpy/common/net/statusserver.py b/Tools/Scripts/webkitpy/common/net/statusserver.py
index abd298a..9622c89 100644
--- a/Tools/Scripts/webkitpy/common/net/statusserver.py
+++ b/Tools/Scripts/webkitpy/common/net/statusserver.py
@@ -25,6 +25,8 @@
# 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.
+#
+# This the client designed to talk to Tools/QueueStatusServer.
from webkitpy.common.net.networktransaction import NetworkTransaction
from webkitpy.common.system.deprecated_logging import log
@@ -39,6 +41,7 @@ _log = logging.getLogger("webkitpy.common.net.statusserver")
class StatusServer:
+ # FIXME: This should probably move to common.config.urls.
default_host = "queues.webkit.org"
def __init__(self, host=default_host, browser=None, bot_id=None):
diff --git a/Tools/Scripts/webkitpy/common/system/executive.py b/Tools/Scripts/webkitpy/common/system/executive.py
index 02619db..7d198dd 100644
--- a/Tools/Scripts/webkitpy/common/system/executive.py
+++ b/Tools/Scripts/webkitpy/common/system/executive.py
@@ -45,6 +45,7 @@ import sys
import time
from webkitpy.common.system.deprecated_logging import tee
+from webkitpy.common.system.filesystem import FileSystem
from webkitpy.python24 import versioning
@@ -179,6 +180,22 @@ class Executive(object):
# machines.
return 2
+ @staticmethod
+ def interpreter_for_script(script_path, fs=FileSystem()):
+ lines = fs.read_text_file(script_path).splitlines()
+ if not len(lines):
+ return None
+ first_line = lines[0]
+ if not first_line.startswith('#!'):
+ return None
+ if first_line.find('python') > -1:
+ return sys.executable
+ if first_line.find('perl') > -1:
+ return 'perl'
+ if first_line.find('ruby') > -1:
+ return 'ruby'
+ return None
+
def kill_process(self, pid):
"""Attempts to kill the given pid.
Will fail silently if pid does not exist or insufficient permisssions."""
diff --git a/Tools/Scripts/webkitpy/common/system/executive_unittest.py b/Tools/Scripts/webkitpy/common/system/executive_unittest.py
index 1dadc36..9a14d6b 100644
--- a/Tools/Scripts/webkitpy/common/system/executive_unittest.py
+++ b/Tools/Scripts/webkitpy/common/system/executive_unittest.py
@@ -34,6 +34,7 @@ import sys
import unittest
from webkitpy.common.system.executive import Executive, run_command, ScriptError
+from webkitpy.common.system.filesystem_mock import MockFileSystem
from webkitpy.test import cat, echo
@@ -65,6 +66,33 @@ def never_ending_command():
class ExecutiveTest(unittest.TestCase):
+ def assert_interpreter_for_content(self, intepreter, content):
+ fs = MockFileSystem()
+ file_path = None
+ file_interpreter = None
+
+ tempfile, temp_name = fs.open_binary_tempfile('')
+ tempfile.write(content)
+ tempfile.close()
+ file_interpreter = Executive.interpreter_for_script(temp_name, fs)
+
+ self.assertEqual(file_interpreter, intepreter)
+
+ def test_interpreter_for_script(self):
+ self.assert_interpreter_for_content(None, '')
+ self.assert_interpreter_for_content(None, 'abcd\nefgh\nijklm')
+ self.assert_interpreter_for_content(None, '##/usr/bin/perl')
+ self.assert_interpreter_for_content('perl', '#!/usr/bin/env perl')
+ self.assert_interpreter_for_content('perl', '#!/usr/bin/env perl\nfirst\nsecond')
+ self.assert_interpreter_for_content('perl', '#!/usr/bin/perl')
+ self.assert_interpreter_for_content('perl', '#!/usr/bin/perl -w')
+ self.assert_interpreter_for_content(sys.executable, '#!/usr/bin/env python')
+ self.assert_interpreter_for_content(sys.executable, '#!/usr/bin/env python\nfirst\nsecond')
+ self.assert_interpreter_for_content(sys.executable, '#!/usr/bin/python')
+ self.assert_interpreter_for_content('ruby', '#!/usr/bin/env ruby')
+ self.assert_interpreter_for_content('ruby', '#!/usr/bin/env ruby\nfirst\nsecond')
+ self.assert_interpreter_for_content('ruby', '#!/usr/bin/ruby')
+
def test_run_command_with_bad_command(self):
def run_bad_command():
run_command(["foo_bar_command_blah"], error_handler=Executive.ignore_error, return_exit_code=True)
diff --git a/Tools/Scripts/webkitpy/common/system/filesystem.py b/Tools/Scripts/webkitpy/common/system/filesystem.py
index 1988546..58be03a 100644
--- a/Tools/Scripts/webkitpy/common/system/filesystem.py
+++ b/Tools/Scripts/webkitpy/common/system/filesystem.py
@@ -61,6 +61,10 @@ class FileSystem(object):
"""Wraps os.path.basename()."""
return os.path.basename(path)
+ def chdir(self, path):
+ """Wraps os.chdir()."""
+ return os.chdir(path)
+
def copyfile(self, source, destination):
"""Copies the contents of the file at the given path to the destination
path."""
@@ -108,6 +112,10 @@ class FileSystem(object):
files.append(self.join(dirpath, filename))
return files
+ def getcwd(self):
+ """Wraps os.getcwd()."""
+ return os.getcwd()
+
def glob(self, path):
"""Wraps glob.glob()."""
return glob.glob(path)
diff --git a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py
index a6d158a..3be5854 100644
--- a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py
+++ b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py
@@ -35,7 +35,7 @@ from webkitpy.common.system import ospath
class MockFileSystem(object):
- def __init__(self, files=None):
+ def __init__(self, files=None, cwd='/'):
"""Initializes a "mock" filesystem that can be used to completely
stub out a filesystem.
@@ -48,6 +48,8 @@ class MockFileSystem(object):
self.written_files = {}
self._sep = '/'
self.current_tmpno = 0
+ self.cwd = cwd
+ self.dirs = {}
def _get_sep(self):
return self._sep
@@ -61,13 +63,19 @@ class MockFileSystem(object):
return path.rsplit(self.sep, 1)
def abspath(self, path):
- if path.endswith(self.sep):
- return path[:-1]
- return path
+ if os.path.isabs(path):
+ return self.normpath(path)
+ return self.abspath(self.join(self.cwd, path))
def basename(self, path):
return self._split(path)[1]
+ def chdir(self, path):
+ path = self.normpath(path)
+ if not self.isdir(path):
+ raise OSError(errno.ENOENT, path, os.strerror(errno.ENOENT))
+ self.cwd = path
+
def copyfile(self, source, destination):
if not self.exists(source):
self._raise_not_found(source)
@@ -117,6 +125,9 @@ class MockFileSystem(object):
return files
+ def getcwd(self, path):
+ return self.cwd
+
def glob(self, path):
# FIXME: This only handles a wildcard '*' at the end of the path.
# Maybe it should handle more?
@@ -134,14 +145,18 @@ class MockFileSystem(object):
def isdir(self, path):
if path in self.files:
return False
- if not path.endswith(self.sep):
- path += self.sep
+ path = self.normpath(path)
+ if path in self.dirs:
+ return True
# We need to use a copy of the keys here in order to avoid switching
# to a different thread and potentially modifying the dict in
# mid-iteration.
files = self.files.keys()[:]
- return any(f.startswith(path) for f in files)
+ result = any(f.startswith(path) for f in files)
+ if result:
+ self.dirs[path] = True
+ return result
def join(self, *comps):
# FIXME: might want tests for this and/or a better comment about how
@@ -204,8 +219,9 @@ class MockFileSystem(object):
return TemporaryDirectory(fs=self, **kwargs)
def maybe_make_directory(self, *path):
- # FIXME: Implement such that subsequent calls to isdir() work?
- pass
+ norm_path = self.normpath(self.join(*path))
+ if not self.isdir(norm_path):
+ self.dirs[norm_path] = True
def move(self, source, destination):
if self.files[source] is None:
@@ -216,7 +232,9 @@ class MockFileSystem(object):
self.written_files[source] = None
def normpath(self, path):
- return path
+ # Like join(), relies on os.path functionality but normalizes the
+ # path separator to the mock one.
+ return re.sub(re.escape(os.path.sep), self.sep, os.path.normpath(path))
def open_binary_tempfile(self, suffix=''):
path = self._mktemp(suffix)
diff --git a/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py b/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py
index 8455d72..8d4f0cb 100644
--- a/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py
+++ b/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py
@@ -48,6 +48,23 @@ class FileSystemTest(unittest.TestCase):
self._missing_file = os.path.join(self._this_dir, 'missing_file.py')
self._this_file = os.path.join(self._this_dir, 'filesystem_unittest.py')
+ def test_chdir(self):
+ fs = FileSystem()
+ cwd = fs.getcwd()
+ newdir = '/'
+ if sys.platform == 'win32':
+ newdir = 'c:\\'
+ fs.chdir(newdir)
+ self.assertEquals(fs.getcwd(), newdir)
+ fs.chdir(cwd)
+
+ def test_chdir__notexists(self):
+ fs = FileSystem()
+ newdir = '/dirdoesnotexist'
+ if sys.platform == 'win32':
+ newdir = 'c:\\dirdoesnotexist'
+ self.assertRaises(OSError, fs.chdir, newdir)
+
def test_exists__true(self):
fs = FileSystem()
self.assertTrue(fs.exists(self._this_file))
@@ -56,6 +73,10 @@ class FileSystemTest(unittest.TestCase):
fs = FileSystem()
self.assertFalse(fs.exists(self._missing_file))
+ def test_getcwd(self):
+ fs = FileSystem()
+ self.assertTrue(fs.exists(fs.getcwd()))
+
def test_isdir__true(self):
fs = FileSystem()
self.assertTrue(fs.isdir(self._this_dir))
diff --git a/Tools/Scripts/webkitpy/common/system/user.py b/Tools/Scripts/webkitpy/common/system/user.py
index b79536c..aecb6ec 100644
--- a/Tools/Scripts/webkitpy/common/system/user.py
+++ b/Tools/Scripts/webkitpy/common/system/user.py
@@ -26,6 +26,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.
+import getpass
import logging
import os
import re
@@ -65,6 +66,10 @@ class User(object):
return response
@classmethod
+ def prompt_password(cls, message, repeat=1):
+ return cls.prompt(message, repeat=repeat, raw_input=getpass.getpass)
+
+ @classmethod
def prompt_with_list(cls, list_title, list_items, can_choose_multiple=False, raw_input=raw_input):
print list_title
i = 0