summaryrefslogtreecommitdiffstats
path: root/WebKitTools/Scripts/webkitpy/common
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-05-05 14:36:32 +0100
committerBen Murdoch <benm@google.com>2011-05-10 15:38:30 +0100
commitf05b935882198ccf7d81675736e3aeb089c5113a (patch)
tree4ea0ca838d9ef1b15cf17ddb3928efb427c7e5a1 /WebKitTools/Scripts/webkitpy/common
parent60fbdcc62bced8db2cb1fd233cc4d1e4ea17db1b (diff)
downloadexternal_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.zip
external_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.tar.gz
external_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.tar.bz2
Merge WebKit at r74534: Initial merge by git.
Change-Id: I6ccd1154fa1b19c2ec2a66878eb675738735f1eb
Diffstat (limited to 'WebKitTools/Scripts/webkitpy/common')
-rw-r--r--WebKitTools/Scripts/webkitpy/common/__init__.py1
-rw-r--r--WebKitTools/Scripts/webkitpy/common/array_stream.py66
-rw-r--r--WebKitTools/Scripts/webkitpy/common/array_stream_unittest.py78
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/__init__.py3
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/api.py160
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/api_unittest.py196
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/changelog.py195
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/changelog_unittest.py203
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/commitinfo.py93
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/commitinfo_unittest.py61
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/diff_parser.py181
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/diff_parser_unittest.py146
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/scm.py915
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py1291
-rw-r--r--WebKitTools/Scripts/webkitpy/common/config/__init__.py1
-rw-r--r--WebKitTools/Scripts/webkitpy/common/config/build.py138
-rw-r--r--WebKitTools/Scripts/webkitpy/common/config/build_unittest.py64
-rw-r--r--WebKitTools/Scripts/webkitpy/common/config/committers.py331
-rw-r--r--WebKitTools/Scripts/webkitpy/common/config/committers_unittest.py72
-rw-r--r--WebKitTools/Scripts/webkitpy/common/config/committervalidator.py120
-rw-r--r--WebKitTools/Scripts/webkitpy/common/config/committervalidator_unittest.py43
-rw-r--r--WebKitTools/Scripts/webkitpy/common/config/irc.py31
-rw-r--r--WebKitTools/Scripts/webkitpy/common/config/ports.py249
-rw-r--r--WebKitTools/Scripts/webkitpy/common/config/ports_unittest.py76
-rw-r--r--WebKitTools/Scripts/webkitpy/common/memoized.py55
-rw-r--r--WebKitTools/Scripts/webkitpy/common/memoized_unittest.py65
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/__init__.py1
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/bugzilla/__init__.py8
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/bugzilla/attachment.py114
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/bugzilla/bug.py105
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/bugzilla/bug_unittest.py40
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py674
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py342
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/buildbot.py452
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/buildbot_unittest.py410
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/credentials.py155
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/credentials_unittest.py176
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/failuremap.py84
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/failuremap_unittest.py76
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/irc/__init__.py1
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/irc/ircbot.py91
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/irc/ircproxy.py62
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/irc/ircproxy_unittest.py43
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/layouttestresults.py90
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/layouttestresults_unittest.py77
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/networktransaction.py72
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/networktransaction_unittest.py93
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/regressionwindow.py51
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/statusserver.py160
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/statusserver_unittest.py43
-rw-r--r--WebKitTools/Scripts/webkitpy/common/newstringio.py40
-rw-r--r--WebKitTools/Scripts/webkitpy/common/newstringio_unittest.py46
-rw-r--r--WebKitTools/Scripts/webkitpy/common/prettypatch.py66
-rw-r--r--WebKitTools/Scripts/webkitpy/common/prettypatch_unittest.py70
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/__init__.py1
-rwxr-xr-xWebKitTools/Scripts/webkitpy/common/system/autoinstall.py517
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/deprecated_logging.py91
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/deprecated_logging_unittest.py60
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/executive.py399
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/executive_mock.py59
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py151
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/file_lock.py83
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/file_lock_unittest.py61
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/filesystem.py117
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/filesystem_mock.py80
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/filesystem_unittest.py157
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/fileutils.py33
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/logtesting.py258
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/logutils.py207
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/logutils_unittest.py142
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/ospath.py83
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/ospath_unittest.py62
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/outputcapture.py86
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/path.py138
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/path_unittest.py105
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/user.py143
-rw-r--r--WebKitTools/Scripts/webkitpy/common/system/user_unittest.py109
-rw-r--r--WebKitTools/Scripts/webkitpy/common/thread/__init__.py1
-rw-r--r--WebKitTools/Scripts/webkitpy/common/thread/messagepump.py59
-rw-r--r--WebKitTools/Scripts/webkitpy/common/thread/messagepump_unittest.py83
-rw-r--r--WebKitTools/Scripts/webkitpy/common/thread/threadedmessagequeue.py54
-rw-r--r--WebKitTools/Scripts/webkitpy/common/thread/threadedmessagequeue_unittest.py53
82 files changed, 0 insertions, 11868 deletions
diff --git a/WebKitTools/Scripts/webkitpy/common/__init__.py b/WebKitTools/Scripts/webkitpy/common/__init__.py
deleted file mode 100644
index ef65bee..0000000
--- a/WebKitTools/Scripts/webkitpy/common/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Required for Python to search this directory for module files
diff --git a/WebKitTools/Scripts/webkitpy/common/array_stream.py b/WebKitTools/Scripts/webkitpy/common/array_stream.py
deleted file mode 100644
index e425d02..0000000
--- a/WebKitTools/Scripts/webkitpy/common/array_stream.py
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/python
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Package that private an array-based implementation of a stream."""
-
-
-class ArrayStream(object):
- """Simple class that implmements a stream interface on top of an array.
-
- This is used primarily by unit test classes to mock output streams. It
- performs a similar function to StringIO, but (a) it is write-only, and
- (b) it can be used to retrieve each individual write(); StringIO
- concatenates all of the writes together.
- """
-
- def __init__(self):
- self._contents = []
-
- def write(self, msg):
- """Implement stream.write() by appending to the stream's contents."""
- self._contents.append(msg)
-
- def get(self):
- """Return the contents of a stream (as an array)."""
- return self._contents
-
- def reset(self):
- """Empty the stream."""
- self._contents = []
-
- def empty(self):
- """Return whether the stream is empty."""
- return (len(self._contents) == 0)
-
- def flush(self):
- """Flush the stream (a no-op implemented for compatibility)."""
- pass
-
- def __repr__(self):
- return '<ArrayStream: ' + str(self._contents) + '>'
diff --git a/WebKitTools/Scripts/webkitpy/common/array_stream_unittest.py b/WebKitTools/Scripts/webkitpy/common/array_stream_unittest.py
deleted file mode 100644
index 1a9b34a..0000000
--- a/WebKitTools/Scripts/webkitpy/common/array_stream_unittest.py
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/python
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Unit tests for array_stream.py."""
-
-import pdb
-import unittest
-
-from webkitpy.common.array_stream import ArrayStream
-
-
-class ArrayStreamTest(unittest.TestCase):
- def assertEmpty(self, a_stream):
- self.assertTrue(a_stream.empty())
-
- def assertNotEmpty(self, a_stream):
- self.assertFalse(a_stream.empty())
-
- def assertContentsMatch(self, a_stream, contents):
- self.assertEquals(a_stream.get(), contents)
-
- def test_basics(self):
- a = ArrayStream()
- self.assertEmpty(a)
- self.assertContentsMatch(a, [])
-
- a.flush()
- self.assertEmpty(a)
- self.assertContentsMatch(a, [])
-
- a.write("foo")
- a.write("bar")
- self.assertNotEmpty(a)
- self.assertContentsMatch(a, ["foo", "bar"])
-
- a.flush()
- self.assertNotEmpty(a)
- self.assertContentsMatch(a, ["foo", "bar"])
-
- a.reset()
- self.assertEmpty(a)
- self.assertContentsMatch(a, [])
-
- self.assertEquals(str(a), "<ArrayStream: []>")
-
- a.write("foo")
- self.assertNotEmpty(a)
- self.assertContentsMatch(a, ["foo"])
- self.assertEquals(str(a), "<ArrayStream: ['foo']>")
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/__init__.py b/WebKitTools/Scripts/webkitpy/common/checkout/__init__.py
deleted file mode 100644
index 597dcbd..0000000
--- a/WebKitTools/Scripts/webkitpy/common/checkout/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# Required for Python to search this directory for module files
-
-from api import Checkout
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/api.py b/WebKitTools/Scripts/webkitpy/common/checkout/api.py
deleted file mode 100644
index dbe1e84..0000000
--- a/WebKitTools/Scripts/webkitpy/common/checkout/api.py
+++ /dev/null
@@ -1,160 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import os
-import StringIO
-
-from webkitpy.common.checkout.changelog import ChangeLog
-from webkitpy.common.checkout.commitinfo import CommitInfo
-from webkitpy.common.checkout.scm import CommitMessage
-from webkitpy.common.memoized import memoized
-from webkitpy.common.net.bugzilla import parse_bug_id
-from webkitpy.common.system.executive import Executive, run_command, ScriptError
-from webkitpy.common.system.deprecated_logging import log
-
-
-# This class represents the WebKit-specific parts of the checkout (like
-# ChangeLogs).
-# FIXME: Move a bunch of ChangeLog-specific processing from SCM to this object.
-class Checkout(object):
- def __init__(self, scm):
- self._scm = scm
-
- def _is_path_to_changelog(self, path):
- return os.path.basename(path) == "ChangeLog"
-
- def _latest_entry_for_changelog_at_revision(self, changelog_path, revision):
- changelog_contents = self._scm.contents_at_revision(changelog_path, revision)
- # contents_at_revision returns a byte array (str()), but we know
- # that ChangeLog files are utf-8. parse_latest_entry_from_file
- # expects a file-like object which vends unicode(), so we decode here.
- changelog_file = StringIO.StringIO(changelog_contents.decode("utf-8"))
- return ChangeLog.parse_latest_entry_from_file(changelog_file)
-
- def changelog_entries_for_revision(self, revision):
- changed_files = self._scm.changed_files_for_revision(revision)
- return [self._latest_entry_for_changelog_at_revision(path, revision) for path in changed_files if self._is_path_to_changelog(path)]
-
- @memoized
- def commit_info_for_revision(self, revision):
- committer_email = self._scm.committer_email_for_revision(revision)
- changelog_entries = self.changelog_entries_for_revision(revision)
- # Assume for now that the first entry has everything we need:
- # FIXME: This will throw an exception if there were no ChangeLogs.
- if not len(changelog_entries):
- return None
- changelog_entry = changelog_entries[0]
- changelog_data = {
- "bug_id": parse_bug_id(changelog_entry.contents()),
- "author_name": changelog_entry.author_name(),
- "author_email": changelog_entry.author_email(),
- "author": changelog_entry.author(),
- "reviewer_text": changelog_entry.reviewer_text(),
- "reviewer": changelog_entry.reviewer(),
- }
- # We could pass the changelog_entry instead of a dictionary here, but that makes
- # mocking slightly more involved, and would make aggregating data from multiple
- # entries more difficult to wire in if we need to do that in the future.
- return CommitInfo(revision, committer_email, changelog_data)
-
- def bug_id_for_revision(self, revision):
- return self.commit_info_for_revision(revision).bug_id()
-
- def _modified_files_matching_predicate(self, git_commit, predicate, changed_files=None):
- # SCM returns paths relative to scm.checkout_root
- # Callers (especially those using the ChangeLog class) may
- # expect absolute paths, so this method returns absolute paths.
- if not changed_files:
- changed_files = self._scm.changed_files(git_commit)
- absolute_paths = [os.path.join(self._scm.checkout_root, path) for path in changed_files]
- return [path for path in absolute_paths if predicate(path)]
-
- def modified_changelogs(self, git_commit, changed_files=None):
- return self._modified_files_matching_predicate(git_commit, self._is_path_to_changelog, changed_files=changed_files)
-
- 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):
- 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"
- "http://webkit.org/coding/contributing.html")
-
- changelog_messages = []
- for changelog_path in changelog_paths:
- log("Parsing ChangeLog: %s" % changelog_path)
- changelog_entry = ChangeLog(changelog_path).latest_entry()
- if not changelog_entry:
- raise ScriptError(message="Failed to parse ChangeLog: %s" % os.path.abspath(changelog_path))
- changelog_messages.append(changelog_entry.contents())
-
- # FIXME: We should sort and label the ChangeLog messages like commit-log-editor does.
- return CommitMessage("".join(changelog_messages).splitlines())
-
- def recent_commit_infos_for_files(self, paths):
- revisions = set(sum(map(self._scm.revisions_changing_file, paths), []))
- return set(map(self.commit_info_for_revision, revisions))
-
- def suggested_reviewers(self, git_commit, changed_files=None):
- changed_files = self.modified_non_changelogs(git_commit, changed_files)
- commit_infos = self.recent_commit_infos_for_files(changed_files)
- reviewers = [commit_info.reviewer() for commit_info in commit_infos if commit_info.reviewer()]
- reviewers.extend([commit_info.author() for commit_info in commit_infos if commit_info.author() and commit_info.author().can_review])
- return sorted(set(reviewers))
-
- def bug_id_for_this_commit(self, git_commit, changed_files=None):
- try:
- return parse_bug_id(self.commit_message_for_this_commit(git_commit, changed_files).message())
- except ScriptError, e:
- pass # We might not have ChangeLogs.
-
- def apply_patch(self, patch, force=False):
- # 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')]
- if patch.reviewer():
- args += ['--reviewer', patch.reviewer().full_name]
- if force:
- args.append('--force')
- run_command(args, input=patch.contents())
-
- def apply_reverse_diff(self, revision):
- self._scm.apply_reverse_diff(revision)
-
- # We revert the ChangeLogs because removing lines from a ChangeLog
- # doesn't make sense. ChangeLogs are append only.
- changelog_paths = self.modified_changelogs(git_commit=None)
- if len(changelog_paths):
- self._scm.revert_files(changelog_paths)
-
- conflicts = self._scm.conflicted_files()
- if len(conflicts):
- raise ScriptError(message="Failed to apply reverse diff for revision %s because of the following conflicts:\n%s" % (revision, "\n".join(conflicts)))
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/api_unittest.py b/WebKitTools/Scripts/webkitpy/common/checkout/api_unittest.py
deleted file mode 100644
index 1f97abd..0000000
--- a/WebKitTools/Scripts/webkitpy/common/checkout/api_unittest.py
+++ /dev/null
@@ -1,196 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-from __future__ import with_statement
-
-import codecs
-import os
-import shutil
-import tempfile
-import unittest
-
-from webkitpy.common.checkout.api import Checkout
-from webkitpy.common.checkout.changelog import ChangeLogEntry
-from webkitpy.common.checkout.scm import detect_scm_system, CommitMessage
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.thirdparty.mock import Mock
-
-
-# FIXME: Copied from scm_unittest.py
-def write_into_file_at_path(file_path, contents, encoding="utf-8"):
- with codecs.open(file_path, "w", encoding) as file:
- file.write(contents)
-
-
-_changelog1entry1 = u"""2010-03-25 Tor Arne Vestb\u00f8 <vestbo@webkit.org>
-
- Unreviewed build fix to un-break webkit-patch land.
-
- Move commit_message_for_this_commit from scm to checkout
- https://bugs.webkit.org/show_bug.cgi?id=36629
-
- * Scripts/webkitpy/common/checkout/api.py: import scm.CommitMessage
-"""
-_changelog1entry2 = u"""2010-03-25 Adam Barth <abarth@webkit.org>
-
- Reviewed by Eric Seidel.
-
- Move commit_message_for_this_commit from scm to checkout
- https://bugs.webkit.org/show_bug.cgi?id=36629
-
- * Scripts/webkitpy/common/checkout/api.py:
-"""
-_changelog1 = u"\n".join([_changelog1entry1, _changelog1entry2])
-_changelog2 = u"""2010-03-25 Tor Arne Vestb\u00f8 <vestbo@webkit.org>
-
- Unreviewed build fix to un-break webkit-patch land.
-
- Second part of this complicated change.
-
- * Path/To/Complicated/File: Added.
-
-2010-03-25 Adam Barth <abarth@webkit.org>
-
- Reviewed by Eric Seidel.
-
- Filler change.
-"""
-
-class CommitMessageForThisCommitTest(unittest.TestCase):
- expected_commit_message = u"""2010-03-25 Tor Arne Vestb\u00f8 <vestbo@webkit.org>
-
- Unreviewed build fix to un-break webkit-patch land.
-
- Move commit_message_for_this_commit from scm to checkout
- https://bugs.webkit.org/show_bug.cgi?id=36629
-
- * Scripts/webkitpy/common/checkout/api.py: import scm.CommitMessage
-2010-03-25 Tor Arne Vestb\u00f8 <vestbo@webkit.org>
-
- Unreviewed build fix to un-break webkit-patch land.
-
- Second part of this complicated change.
-
- * Path/To/Complicated/File: Added.
-"""
-
- def setUp(self):
- self.temp_dir = tempfile.mkdtemp(suffix="changelogs")
- self.old_cwd = os.getcwd()
- os.chdir(self.temp_dir)
- write_into_file_at_path("ChangeLog1", _changelog1)
- write_into_file_at_path("ChangeLog2", _changelog2)
-
- def tearDown(self):
- shutil.rmtree(self.temp_dir, ignore_errors=True)
- os.chdir(self.old_cwd)
-
- # FIXME: This should not need to touch the file system, however
- # ChangeLog is difficult to mock at current.
- def test_commit_message_for_this_commit(self):
- checkout = Checkout(None)
- checkout.modified_changelogs = lambda git_commit, changed_files=None: ["ChangeLog1", "ChangeLog2"]
- output = OutputCapture()
- expected_stderr = "Parsing ChangeLog: ChangeLog1\nParsing ChangeLog: ChangeLog2\n"
- commit_message = output.assert_outputs(self, checkout.commit_message_for_this_commit,
- kwargs={"git_commit": None}, expected_stderr=expected_stderr)
- self.assertEqual(commit_message.message(), self.expected_commit_message)
-
-
-class CheckoutTest(unittest.TestCase):
- def test_latest_entry_for_changelog_at_revision(self):
- scm = Mock()
- def mock_contents_at_revision(changelog_path, revision):
- self.assertEqual(changelog_path, "foo")
- self.assertEqual(revision, "bar")
- # contents_at_revision is expected to return a byte array (str)
- # so we encode our unicode ChangeLog down to a utf-8 stream.
- return _changelog1.encode("utf-8")
- scm.contents_at_revision = mock_contents_at_revision
- checkout = Checkout(scm)
- entry = checkout._latest_entry_for_changelog_at_revision("foo", "bar")
- self.assertEqual(entry.contents(), _changelog1entry1)
-
- def test_commit_info_for_revision(self):
- scm = Mock()
- scm.committer_email_for_revision = lambda revision: "committer@example.com"
- checkout = Checkout(scm)
- checkout.changelog_entries_for_revision = lambda revision: [ChangeLogEntry(_changelog1entry1)]
- commitinfo = checkout.commit_info_for_revision(4)
- self.assertEqual(commitinfo.bug_id(), 36629)
- self.assertEqual(commitinfo.author_name(), u"Tor Arne Vestb\u00f8")
- self.assertEqual(commitinfo.author_email(), "vestbo@webkit.org")
- self.assertEqual(commitinfo.reviewer_text(), None)
- self.assertEqual(commitinfo.reviewer(), None)
- self.assertEqual(commitinfo.committer_email(), "committer@example.com")
- self.assertEqual(commitinfo.committer(), None)
-
- checkout.changelog_entries_for_revision = lambda revision: []
- self.assertEqual(checkout.commit_info_for_revision(1), None)
-
- def test_bug_id_for_revision(self):
- scm = Mock()
- scm.committer_email_for_revision = lambda revision: "committer@example.com"
- checkout = Checkout(scm)
- checkout.changelog_entries_for_revision = lambda revision: [ChangeLogEntry(_changelog1entry1)]
- self.assertEqual(checkout.bug_id_for_revision(4), 36629)
-
- def test_bug_id_for_this_commit(self):
- scm = Mock()
- checkout = Checkout(scm)
- checkout.commit_message_for_this_commit = lambda git_commit, changed_files=None: CommitMessage(ChangeLogEntry(_changelog1entry1).contents().splitlines())
- self.assertEqual(checkout.bug_id_for_this_commit(git_commit=None), 36629)
-
- def test_modified_changelogs(self):
- scm = Mock()
- scm.checkout_root = "/foo/bar"
- scm.changed_files = lambda git_commit: ["file1", "ChangeLog", "relative/path/ChangeLog"]
- checkout = Checkout(scm)
- expected_changlogs = ["/foo/bar/ChangeLog", "/foo/bar/relative/path/ChangeLog"]
- self.assertEqual(checkout.modified_changelogs(git_commit=None), expected_changlogs)
-
- def test_suggested_reviewers(self):
- def mock_changelog_entries_for_revision(revision):
- if revision % 2 == 0:
- return [ChangeLogEntry(_changelog1entry1)]
- return [ChangeLogEntry(_changelog1entry2)]
-
- def mock_revisions_changing_file(path, limit=5):
- if path.endswith("ChangeLog"):
- return [3]
- return [4, 8]
-
- scm = Mock()
- scm.checkout_root = "/foo/bar"
- scm.changed_files = lambda git_commit: ["file1", "file2", "relative/path/ChangeLog"]
- scm.revisions_changing_file = mock_revisions_changing_file
- checkout = Checkout(scm)
- checkout.changelog_entries_for_revision = mock_changelog_entries_for_revision
- reviewers = checkout.suggested_reviewers(git_commit=None)
- reviewer_names = [reviewer.full_name for reviewer in reviewers]
- self.assertEqual(reviewer_names, [u'Tor Arne Vestb\xf8'])
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/changelog.py b/WebKitTools/Scripts/webkitpy/common/checkout/changelog.py
deleted file mode 100644
index 40657eb..0000000
--- a/WebKitTools/Scripts/webkitpy/common/checkout/changelog.py
+++ /dev/null
@@ -1,195 +0,0 @@
-# Copyright (C) 2009, 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# WebKit's Python module for parsing and modifying ChangeLog files
-
-import codecs
-import fileinput # inplace file editing for set_reviewer_in_changelog
-import os.path
-import re
-import textwrap
-
-from webkitpy.common.system.deprecated_logging import log
-from webkitpy.common.config.committers import CommitterList
-from webkitpy.common.net.bugzilla import parse_bug_id
-
-
-def view_source_url(revision_number):
- # FIMXE: This doesn't really belong in this file, but we don't have a
- # better home for it yet.
- # Maybe eventually a webkit_config.py?
- return "http://trac.webkit.org/changeset/%s" % revision_number
-
-
-class ChangeLogEntry(object):
- # e.g. 2009-06-03 Eric Seidel <eric@webkit.org>
- date_line_regexp = r'^(?P<date>\d{4}-\d{2}-\d{2})\s+(?P<name>.+?)\s+<(?P<email>[^<>]+)>$'
-
- def __init__(self, contents, committer_list=CommitterList()):
- self._contents = contents
- self._committer_list = committer_list
- self._parse_entry()
-
- def _parse_entry(self):
- match = re.match(self.date_line_regexp, self._contents, re.MULTILINE)
- if not match:
- log("WARNING: Creating invalid ChangeLogEntry:\n%s" % self._contents)
-
- # FIXME: group("name") does not seem to be Unicode? Probably due to self._contents not being unicode.
- self._author_name = match.group("name") if match else None
- self._author_email = match.group("email") if match else None
-
- match = re.search("^\s+Reviewed by (?P<reviewer>.*?)[\.,]?\s*$", self._contents, re.MULTILINE) # Discard everything after the first period
- self._reviewer_text = match.group("reviewer") if match else None
-
- self._reviewer = self._committer_list.committer_by_name(self._reviewer_text)
- self._author = self._committer_list.committer_by_email(self._author_email) or self._committer_list.committer_by_name(self._author_name)
-
- def author_name(self):
- return self._author_name
-
- def author_email(self):
- return self._author_email
-
- def author(self):
- return self._author # Might be None
-
- # FIXME: Eventually we would like to map reviwer names to reviewer objects.
- # See https://bugs.webkit.org/show_bug.cgi?id=26533
- def reviewer_text(self):
- return self._reviewer_text
-
- def reviewer(self):
- return self._reviewer # Might be None
-
- def contents(self):
- return self._contents
-
- def bug_id(self):
- return parse_bug_id(self._contents)
-
-
-# FIXME: Various methods on ChangeLog should move into ChangeLogEntry instead.
-class ChangeLog(object):
-
- def __init__(self, path):
- self.path = path
-
- _changelog_indent = " " * 8
-
- @staticmethod
- def parse_latest_entry_from_file(changelog_file):
- """changelog_file must be a file-like object which returns
- unicode strings. Use codecs.open or StringIO(unicode())
- to pass file objects to this class."""
- date_line_regexp = re.compile(ChangeLogEntry.date_line_regexp)
- entry_lines = []
- # The first line should be a date line.
- first_line = changelog_file.readline()
- assert(isinstance(first_line, unicode))
- if not date_line_regexp.match(first_line):
- return None
- entry_lines.append(first_line)
-
- for line in changelog_file:
- # If we've hit the next entry, return.
- if date_line_regexp.match(line):
- # Remove the extra newline at the end
- return ChangeLogEntry(''.join(entry_lines[:-1]))
- entry_lines.append(line)
- return None # We never found a date line!
-
- def latest_entry(self):
- # ChangeLog files are always UTF-8, we read them in as such to support Reviewers with unicode in their names.
- changelog_file = codecs.open(self.path, "r", "utf-8")
- try:
- return self.parse_latest_entry_from_file(changelog_file)
- finally:
- changelog_file.close()
-
- # _wrap_line and _wrap_lines exist to work around
- # http://bugs.python.org/issue1859
-
- def _wrap_line(self, line):
- return textwrap.fill(line,
- width=70,
- initial_indent=self._changelog_indent,
- # Don't break urls which may be longer than width.
- break_long_words=False,
- subsequent_indent=self._changelog_indent)
-
- # Workaround as suggested by guido in
- # http://bugs.python.org/issue1859#msg60040
-
- def _wrap_lines(self, message):
- lines = [self._wrap_line(line) for line in message.splitlines()]
- return "\n".join(lines)
-
- # This probably does not belong in changelogs.py
- def _message_for_revert(self, revision, reason, bug_url):
- message = "Unreviewed, rolling out r%s.\n" % revision
- message += "%s\n" % view_source_url(revision)
- if bug_url:
- message += "%s\n" % bug_url
- # Add an extra new line after the rollout links, before any reason.
- message += "\n"
- if reason:
- message += "%s\n\n" % reason
- return self._wrap_lines(message)
-
- def update_for_revert(self, revision, reason, bug_url=None):
- reviewed_by_regexp = re.compile(
- "%sReviewed by NOBODY \(OOPS!\)\." % self._changelog_indent)
- removing_boilerplate = False
- # inplace=1 creates a backup file and re-directs stdout to the file
- for line in fileinput.FileInput(self.path, inplace=1):
- if reviewed_by_regexp.search(line):
- message_lines = self._message_for_revert(revision,
- reason,
- bug_url)
- print reviewed_by_regexp.sub(message_lines, line),
- # Remove all the ChangeLog boilerplate between the Reviewed by
- # line and the first changed file.
- removing_boilerplate = True
- elif removing_boilerplate:
- if line.find('*') >= 0: # each changed file is preceded by a *
- removing_boilerplate = False
-
- if not removing_boilerplate:
- print line,
-
- def set_reviewer(self, reviewer):
- # inplace=1 creates a backup file and re-directs stdout to the file
- for line in fileinput.FileInput(self.path, inplace=1):
- # Trailing comma suppresses printing newline
- print line.replace("NOBODY (OOPS!)", reviewer.encode("utf-8")),
-
- def set_short_description_and_bug_url(self, short_description, bug_url):
- message = "%s\n %s" % (short_description, bug_url)
- for line in fileinput.FileInput(self.path, inplace=1):
- print line.replace("Need a short description and bug URL (OOPS!)", message.encode("utf-8")),
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/changelog_unittest.py b/WebKitTools/Scripts/webkitpy/common/checkout/changelog_unittest.py
deleted file mode 100644
index 6aeb1f8..0000000
--- a/WebKitTools/Scripts/webkitpy/common/checkout/changelog_unittest.py
+++ /dev/null
@@ -1,203 +0,0 @@
-# Copyright (C) 2009 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-from __future__ import with_statement
-
-import codecs
-import os
-import tempfile
-import unittest
-
-from StringIO import StringIO
-
-from webkitpy.common.checkout.changelog import *
-
-
-class ChangeLogTest(unittest.TestCase):
-
- _example_entry = u'''2009-08-17 Peter Kasting <pkasting@google.com>
-
- Reviewed by Tor Arne Vestb\xf8.
-
- https://bugs.webkit.org/show_bug.cgi?id=27323
- Only add Cygwin to the path when it isn't already there. This avoids
- causing problems for people who purposefully have non-Cygwin versions of
- executables like svn in front of the Cygwin ones in their paths.
-
- * DumpRenderTree/win/DumpRenderTree.vcproj:
- * DumpRenderTree/win/ImageDiff.vcproj:
- * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
-'''
-
- # More example text than we need. Eventually we need to support parsing this all and write tests for the parsing.
- _example_changelog = u"""2009-08-17 Tor Arne Vestb\xf8 <vestbo@webkit.org>
-
- <http://webkit.org/b/28393> check-webkit-style: add check for use of std::max()/std::min() instead of MAX()/MIN()
-
- Reviewed by David Levin.
-
- * Scripts/modules/cpp_style.py:
- (_ERROR_CATEGORIES): Added 'runtime/max_min_macros'.
- (check_max_min_macros): Added. Returns level 4 error when MAX()
- and MIN() macros are used in header files and C++ source files.
- (check_style): Added call to check_max_min_macros().
- * Scripts/modules/cpp_style_unittest.py: Added unit tests.
- (test_max_macro): Added.
- (test_min_macro): Added.
-
-2009-08-16 David Kilzer <ddkilzer@apple.com>
-
- Backed out r47343 which was mistakenly committed
-
- * Scripts/bugzilla-tool:
- * Scripts/modules/scm.py:
-
-2009-06-18 Darin Adler <darin@apple.com>
-
- Rubber stamped by Mark Rowe.
-
- * DumpRenderTree/mac/DumpRenderTreeWindow.mm:
- (-[DumpRenderTreeWindow close]): Resolved crashes seen during regression
- tests. The close method can be called on a window that's already closed
- so we can't assert here.
-
-== Rolled over to ChangeLog-2009-06-16 ==
-"""
-
- def test_latest_entry_parse(self):
- changelog_contents = u"%s\n%s" % (self._example_entry, self._example_changelog)
- changelog_file = StringIO(changelog_contents)
- latest_entry = ChangeLog.parse_latest_entry_from_file(changelog_file)
- self.assertEquals(latest_entry.contents(), self._example_entry)
- self.assertEquals(latest_entry.author_name(), "Peter Kasting")
- self.assertEquals(latest_entry.author_email(), "pkasting@google.com")
- self.assertEquals(latest_entry.reviewer_text(), u"Tor Arne Vestb\xf8")
- self.assertTrue(latest_entry.reviewer()) # Make sure that our UTF8-based lookup of Tor works.
-
- @staticmethod
- def _write_tmp_file_with_contents(byte_array):
- assert(isinstance(byte_array, str))
- (file_descriptor, file_path) = tempfile.mkstemp() # NamedTemporaryFile always deletes the file on close in python < 2.6
- with os.fdopen(file_descriptor, "w") as file:
- file.write(byte_array)
- return file_path
-
- @staticmethod
- def _read_file_contents(file_path, encoding):
- with codecs.open(file_path, "r", encoding) as file:
- return file.read()
-
- _new_entry_boilerplate = '''2009-08-19 Eric Seidel <eric@webkit.org>
-
- Reviewed by NOBODY (OOPS!).
-
- Need a short description and bug URL (OOPS!)
-
- * Scripts/bugzilla-tool:
-'''
-
- def test_set_reviewer(self):
- changelog_contents = u"%s\n%s" % (self._new_entry_boilerplate, self._example_changelog)
- changelog_path = self._write_tmp_file_with_contents(changelog_contents.encode("utf-8"))
- reviewer_name = 'Test Reviewer'
- ChangeLog(changelog_path).set_reviewer(reviewer_name)
- actual_contents = self._read_file_contents(changelog_path, "utf-8")
- expected_contents = changelog_contents.replace('NOBODY (OOPS!)', reviewer_name)
- os.remove(changelog_path)
- self.assertEquals(actual_contents, expected_contents)
-
- def test_set_short_description_and_bug_url(self):
- changelog_contents = u"%s\n%s" % (self._new_entry_boilerplate, self._example_changelog)
- changelog_path = self._write_tmp_file_with_contents(changelog_contents.encode("utf-8"))
- short_description = "A short description"
- bug_url = "http://example.com/b/2344"
- ChangeLog(changelog_path).set_short_description_and_bug_url(short_description, bug_url)
- actual_contents = self._read_file_contents(changelog_path, "utf-8")
- expected_message = "%s\n %s" % (short_description, bug_url)
- expected_contents = changelog_contents.replace("Need a short description and bug URL (OOPS!)", expected_message)
- os.remove(changelog_path)
- self.assertEquals(actual_contents, expected_contents)
-
- _revert_message = """ Unreviewed, rolling out r12345.
- http://trac.webkit.org/changeset/12345
- http://example.com/123
-
- This is a very long reason which should be long enough so that
- _message_for_revert will need to wrap it. We'll also include
- a
- https://veryveryveryveryverylongbugurl.com/reallylongbugthingy.cgi?bug_id=12354
- link so that we can make sure we wrap that right too.
-"""
-
- def test_message_for_revert(self):
- changelog = ChangeLog("/fake/path")
- long_reason = "This is a very long reason which should be long enough so that _message_for_revert will need to wrap it. We'll also include a https://veryveryveryveryverylongbugurl.com/reallylongbugthingy.cgi?bug_id=12354 link so that we can make sure we wrap that right too."
- message = changelog._message_for_revert(12345, long_reason, "http://example.com/123")
- self.assertEquals(message, self._revert_message)
-
- _revert_entry_with_bug_url = '''2009-08-19 Eric Seidel <eric@webkit.org>
-
- Unreviewed, rolling out r12345.
- http://trac.webkit.org/changeset/12345
- http://example.com/123
-
- Reason
-
- * Scripts/bugzilla-tool:
-'''
-
- _revert_entry_without_bug_url = '''2009-08-19 Eric Seidel <eric@webkit.org>
-
- Unreviewed, rolling out r12345.
- http://trac.webkit.org/changeset/12345
-
- Reason
-
- * Scripts/bugzilla-tool:
-'''
-
- def _assert_update_for_revert_output(self, args, expected_entry):
- changelog_contents = u"%s\n%s" % (self._new_entry_boilerplate, self._example_changelog)
- changelog_path = self._write_tmp_file_with_contents(changelog_contents.encode("utf-8"))
- changelog = ChangeLog(changelog_path)
- changelog.update_for_revert(*args)
- actual_entry = changelog.latest_entry()
- os.remove(changelog_path)
- self.assertEquals(actual_entry.contents(), expected_entry)
- self.assertEquals(actual_entry.reviewer_text(), None)
- # These checks could be removed to allow this to work on other entries:
- self.assertEquals(actual_entry.author_name(), "Eric Seidel")
- self.assertEquals(actual_entry.author_email(), "eric@webkit.org")
-
- def test_update_for_revert(self):
- self._assert_update_for_revert_output([12345, "Reason"], self._revert_entry_without_bug_url)
- self._assert_update_for_revert_output([12345, "Reason", "http://example.com/123"], self._revert_entry_with_bug_url)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/commitinfo.py b/WebKitTools/Scripts/webkitpy/common/checkout/commitinfo.py
deleted file mode 100644
index 448d530..0000000
--- a/WebKitTools/Scripts/webkitpy/common/checkout/commitinfo.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# WebKit's python module for holding information on a commit
-
-from webkitpy.common.checkout.changelog import view_source_url
-from webkitpy.common.config.committers import CommitterList
-
-
-class CommitInfo(object):
- def __init__(self, revision, committer_email, changelog_data, committer_list=CommitterList()):
- self._revision = revision
- self._committer_email = committer_email
- self._bug_id = changelog_data["bug_id"]
- self._author_name = changelog_data["author_name"]
- self._author_email = changelog_data["author_email"]
- self._author = changelog_data["author"]
- self._reviewer_text = changelog_data["reviewer_text"]
- self._reviewer = changelog_data["reviewer"]
-
- # Derived values:
- self._committer = committer_list.committer_by_email(committer_email)
-
- def revision(self):
- return self._revision
-
- def committer(self):
- return self._committer # None if committer isn't in committers.py
-
- def committer_email(self):
- return self._committer_email
-
- def bug_id(self):
- return self._bug_id # May be None
-
- def author(self):
- return self._author # May be None
-
- def author_name(self):
- return self._author_name
-
- def author_email(self):
- return self._author_email
-
- def reviewer(self):
- return self._reviewer # May be None
-
- def reviewer_text(self):
- return self._reviewer_text # May be None
-
- def responsible_parties(self):
- responsible_parties = [
- self.committer(),
- self.author(),
- self.reviewer(),
- ]
- return set([party for party in responsible_parties if party]) # Filter out None
-
- # FIXME: It is slightly lame that this "view" method is on this "model" class (in MVC terms)
- def blame_string(self, bugs):
- string = "r%s:\n" % self.revision()
- string += " %s\n" % view_source_url(self.revision())
- string += " Bug: %s (%s)\n" % (self.bug_id(), bugs.bug_url_for_bug_id(self.bug_id()))
- author_line = "\"%s\" <%s>" % (self.author_name(), self.author_email())
- string += " Author: %s\n" % (self.author() or author_line)
- string += " Reviewer: %s\n" % (self.reviewer() or self.reviewer_text())
- string += " Committer: %s" % self.committer()
- return string
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/commitinfo_unittest.py b/WebKitTools/Scripts/webkitpy/common/checkout/commitinfo_unittest.py
deleted file mode 100644
index f58e6f1..0000000
--- a/WebKitTools/Scripts/webkitpy/common/checkout/commitinfo_unittest.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from webkitpy.common.checkout.commitinfo import CommitInfo
-from webkitpy.common.config.committers import CommitterList, Committer, Reviewer
-
-class CommitInfoTest(unittest.TestCase):
-
- def test_commit_info_creation(self):
- author = Committer("Author", "author@example.com")
- committer = Committer("Committer", "committer@example.com")
- reviewer = Reviewer("Reviewer", "reviewer@example.com")
- committer_list = CommitterList(committers=[author, committer], reviewers=[reviewer])
-
- changelog_data = {
- "bug_id": 1234,
- "author_name": "Committer",
- "author_email": "author@example.com",
- "author": author,
- "reviewer_text": "Reviewer",
- "reviewer": reviewer,
- }
- commit = CommitInfo(123, "committer@example.com", changelog_data, committer_list)
-
- self.assertEqual(commit.revision(), 123)
- self.assertEqual(commit.bug_id(), 1234)
- self.assertEqual(commit.author_name(), "Committer")
- self.assertEqual(commit.author_email(), "author@example.com")
- self.assertEqual(commit.author(), author)
- self.assertEqual(commit.reviewer_text(), "Reviewer")
- self.assertEqual(commit.reviewer(), reviewer)
- self.assertEqual(commit.committer(), committer)
- self.assertEqual(commit.committer_email(), "committer@example.com")
- self.assertEqual(commit.responsible_parties(), set([author, committer, reviewer]))
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/diff_parser.py b/WebKitTools/Scripts/webkitpy/common/checkout/diff_parser.py
deleted file mode 100644
index a6ea756..0000000
--- a/WebKitTools/Scripts/webkitpy/common/checkout/diff_parser.py
+++ /dev/null
@@ -1,181 +0,0 @@
-# Copyright (C) 2009 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""WebKit's Python module for interacting with patches."""
-
-import logging
-import re
-
-_log = logging.getLogger("webkitpy.common.checkout.diff_parser")
-
-
-# FIXME: This is broken. We should compile our regexps up-front
-# instead of using a custom cache.
-_regexp_compile_cache = {}
-
-
-# FIXME: This function should be removed.
-def match(pattern, string):
- """Matches the string with the pattern, caching the compiled regexp."""
- if not pattern in _regexp_compile_cache:
- _regexp_compile_cache[pattern] = re.compile(pattern)
- return _regexp_compile_cache[pattern].match(string)
-
-
-# FIXME: This belongs on DiffParser (e.g. as to_svn_diff()).
-def git_diff_to_svn_diff(line):
- """Converts a git formatted diff line to a svn formatted line.
-
- Args:
- line: A string representing a line of the diff.
- """
- # FIXME: This list should be a class member on DiffParser.
- # These regexp patterns should be compiled once instead of every time.
- conversion_patterns = (("^diff --git \w/(.+) \w/(?P<FilePath>.+)", lambda matched: "Index: " + matched.group('FilePath') + "\n"),
- ("^new file.*", lambda matched: "\n"),
- ("^index [0-9a-f]{7}\.\.[0-9a-f]{7} [0-9]{6}", lambda matched: "===================================================================\n"),
- ("^--- \w/(?P<FilePath>.+)", lambda matched: "--- " + matched.group('FilePath') + "\n"),
- ("^\+\+\+ \w/(?P<FilePath>.+)", lambda matched: "+++ " + matched.group('FilePath') + "\n"))
-
- for pattern, conversion in conversion_patterns:
- matched = match(pattern, line)
- if matched:
- return conversion(matched)
- return line
-
-
-# FIXME: This method belongs on DiffParser
-def get_diff_converter(first_diff_line):
- """Gets a converter function of diff lines.
-
- Args:
- first_diff_line: The first filename line of a diff file.
- If this line is git formatted, we'll return a
- converter from git to SVN.
- """
- if match(r"^diff --git \w/", first_diff_line):
- return git_diff_to_svn_diff
- return lambda input: input
-
-
-_INITIAL_STATE = 1
-_DECLARED_FILE_PATH = 2
-_PROCESSING_CHUNK = 3
-
-
-class DiffFile(object):
- """Contains the information for one file in a patch.
-
- The field "lines" is a list which contains tuples in this format:
- (deleted_line_number, new_line_number, line_string)
- If deleted_line_number is zero, it means this line is newly added.
- If new_line_number is zero, it means this line is deleted.
- """
- # FIXME: Tuples generally grow into classes. We should consider
- # adding a DiffLine object.
-
- def added_or_modified_line_numbers(self):
- # This logic was moved from patchreader.py, but may not be
- # the right API for this object long-term.
- return [line[1] for line in self.lines if not line[0]]
-
- def __init__(self, filename):
- self.filename = filename
- self.lines = []
-
- def add_new_line(self, line_number, line):
- self.lines.append((0, line_number, line))
-
- def add_deleted_line(self, line_number, line):
- self.lines.append((line_number, 0, line))
-
- def add_unchanged_line(self, deleted_line_number, new_line_number, line):
- self.lines.append((deleted_line_number, new_line_number, line))
-
-
-class DiffParser(object):
- """A parser for a patch file.
-
- The field "files" is a dict whose key is the filename and value is
- a DiffFile object.
- """
-
- # FIXME: This function is way too long and needs to be broken up.
- def __init__(self, diff_input):
- """Parses a diff.
-
- Args:
- diff_input: An iterable object.
- """
- state = _INITIAL_STATE
-
- self.files = {}
- current_file = None
- old_diff_line = None
- new_diff_line = None
- for line in diff_input:
- line = line.rstrip("\n")
- if state == _INITIAL_STATE:
- transform_line = get_diff_converter(line)
- line = transform_line(line)
-
- file_declaration = match(r"^Index: (?P<FilePath>.+)", line)
- if file_declaration:
- filename = file_declaration.group('FilePath')
- current_file = DiffFile(filename)
- self.files[filename] = current_file
- state = _DECLARED_FILE_PATH
- continue
-
- lines_changed = match(r"^@@ -(?P<OldStartLine>\d+)(,\d+)? \+(?P<NewStartLine>\d+)(,\d+)? @@", line)
- if lines_changed:
- if state != _DECLARED_FILE_PATH and state != _PROCESSING_CHUNK:
- _log.error('Unexpected line change without file path '
- 'declaration: %r' % line)
- old_diff_line = int(lines_changed.group('OldStartLine'))
- new_diff_line = int(lines_changed.group('NewStartLine'))
- state = _PROCESSING_CHUNK
- continue
-
- if state == _PROCESSING_CHUNK:
- if line.startswith('+'):
- current_file.add_new_line(new_diff_line, line[1:])
- new_diff_line += 1
- elif line.startswith('-'):
- current_file.add_deleted_line(old_diff_line, line[1:])
- old_diff_line += 1
- elif line.startswith(' '):
- current_file.add_unchanged_line(old_diff_line, new_diff_line, line[1:])
- old_diff_line += 1
- new_diff_line += 1
- elif line == '\\ No newline at end of file':
- # Nothing to do. We may still have some added lines.
- pass
- else:
- _log.error('Unexpected diff format when parsing a '
- 'chunk: %r' % line)
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/diff_parser_unittest.py b/WebKitTools/Scripts/webkitpy/common/checkout/diff_parser_unittest.py
deleted file mode 100644
index 7eb0eab..0000000
--- a/WebKitTools/Scripts/webkitpy/common/checkout/diff_parser_unittest.py
+++ /dev/null
@@ -1,146 +0,0 @@
-# Copyright (C) 2009 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-import diff_parser
-import re
-
-
-class DiffParserTest(unittest.TestCase):
-
- _PATCH = '''diff --git a/WebCore/rendering/style/StyleFlexibleBoxData.h b/WebCore/rendering/style/StyleFlexibleBoxData.h
-index f5d5e74..3b6aa92 100644
---- a/WebCore/rendering/style/StyleFlexibleBoxData.h
-+++ b/WebCore/rendering/style/StyleFlexibleBoxData.h
-@@ -47,7 +47,6 @@ public:
-
- unsigned align : 3; // EBoxAlignment
- unsigned pack: 3; // EBoxAlignment
-- unsigned orient: 1; // EBoxOrient
- unsigned lines : 1; // EBoxLines
-
- private:
-diff --git a/WebCore/rendering/style/StyleRareInheritedData.cpp b/WebCore/rendering/style/StyleRareInheritedData.cpp
-index ce21720..324929e 100644
---- a/WebCore/rendering/style/StyleRareInheritedData.cpp
-+++ b/WebCore/rendering/style/StyleRareInheritedData.cpp
-@@ -39,6 +39,7 @@ StyleRareInheritedData::StyleRareInheritedData()
- , textSizeAdjust(RenderStyle::initialTextSizeAdjust())
- , resize(RenderStyle::initialResize())
- , userSelect(RenderStyle::initialUserSelect())
-+ , boxOrient(RenderStyle::initialBoxOrient())
- {
- }
-
-@@ -58,6 +59,7 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o)
- , textSizeAdjust(o.textSizeAdjust)
- , resize(o.resize)
- , userSelect(o.userSelect)
-+ , boxOrient(o.boxOrient)
- {
- }
-
-@@ -81,7 +83,8 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
- && khtmlLineBreak == o.khtmlLineBreak
- && textSizeAdjust == o.textSizeAdjust
- && resize == o.resize
-- && userSelect == o.userSelect;
-+ && userSelect == o.userSelect
-+ && boxOrient == o.boxOrient;
- }
-
- bool StyleRareInheritedData::shadowDataEquivalent(const StyleRareInheritedData& o) const
-diff --git a/LayoutTests/platform/mac/fast/flexbox/box-orient-button-expected.checksum b/LayoutTests/platform/mac/fast/flexbox/box-orient-button-expected.checksum
-new file mode 100644
-index 0000000..6db26bd
---- /dev/null
-+++ b/LayoutTests/platform/mac/fast/flexbox/box-orient-button-expected.checksum
-@@ -0,0 +1 @@
-+61a373ee739673a9dcd7bac62b9f182e
-\ No newline at end of file
-'''
-
- def test_diff_parser(self, parser = None):
- if not parser:
- parser = diff_parser.DiffParser(self._PATCH.splitlines())
- self.assertEquals(3, len(parser.files))
-
- self.assertTrue('WebCore/rendering/style/StyleFlexibleBoxData.h' in parser.files)
- diff = parser.files['WebCore/rendering/style/StyleFlexibleBoxData.h']
- self.assertEquals(7, len(diff.lines))
- # The first two unchaged lines.
- self.assertEquals((47, 47), diff.lines[0][0:2])
- self.assertEquals('', diff.lines[0][2])
- self.assertEquals((48, 48), diff.lines[1][0:2])
- self.assertEquals(' unsigned align : 3; // EBoxAlignment', diff.lines[1][2])
- # The deleted line
- self.assertEquals((50, 0), diff.lines[3][0:2])
- self.assertEquals(' unsigned orient: 1; // EBoxOrient', diff.lines[3][2])
-
- # The first file looks OK. Let's check the next, more complicated file.
- self.assertTrue('WebCore/rendering/style/StyleRareInheritedData.cpp' in parser.files)
- diff = parser.files['WebCore/rendering/style/StyleRareInheritedData.cpp']
- # There are 3 chunks.
- self.assertEquals(7 + 7 + 9, len(diff.lines))
- # Around an added line.
- self.assertEquals((60, 61), diff.lines[9][0:2])
- self.assertEquals((0, 62), diff.lines[10][0:2])
- self.assertEquals((61, 63), diff.lines[11][0:2])
- # Look through the last chunk, which contains both add's and delete's.
- self.assertEquals((81, 83), diff.lines[14][0:2])
- self.assertEquals((82, 84), diff.lines[15][0:2])
- self.assertEquals((83, 85), diff.lines[16][0:2])
- self.assertEquals((84, 0), diff.lines[17][0:2])
- self.assertEquals((0, 86), diff.lines[18][0:2])
- self.assertEquals((0, 87), diff.lines[19][0:2])
- self.assertEquals((85, 88), diff.lines[20][0:2])
- self.assertEquals((86, 89), diff.lines[21][0:2])
- self.assertEquals((87, 90), diff.lines[22][0:2])
-
- # Check if a newly added file is correctly handled.
- diff = parser.files['LayoutTests/platform/mac/fast/flexbox/box-orient-button-expected.checksum']
- self.assertEquals(1, len(diff.lines))
- self.assertEquals((0, 1), diff.lines[0][0:2])
-
- def test_git_mnemonicprefix(self):
- p = re.compile(r' ([a|b])/')
-
- prefixes = [
- { 'a' : 'i', 'b' : 'w' }, # git-diff (compares the (i)ndex and the (w)ork tree)
- { 'a' : 'c', 'b' : 'w' }, # git-diff HEAD (compares a (c)ommit and the (w)ork tree)
- { 'a' : 'c', 'b' : 'i' }, # git diff --cached (compares a (c)ommit and the (i)ndex)
- { 'a' : 'o', 'b' : 'w' }, # git-diff HEAD:file1 file2 (compares an (o)bject and a (w)ork tree entity)
- { 'a' : '1', 'b' : '2' }, # git diff --no-index a b (compares two non-git things (1) and (2))
- ]
-
- for prefix in prefixes:
- patch = p.sub(lambda x: " %s/" % prefix[x.group(1)], self._PATCH)
- self.test_diff_parser(diff_parser.DiffParser(patch.splitlines()))
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/scm.py b/WebKitTools/Scripts/webkitpy/common/checkout/scm.py
deleted file mode 100644
index d39b8b4..0000000
--- a/WebKitTools/Scripts/webkitpy/common/checkout/scm.py
+++ /dev/null
@@ -1,915 +0,0 @@
-# Copyright (c) 2009, Google Inc. All rights reserved.
-# Copyright (c) 2009 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Python module for interacting with an SCM system (like SVN or Git)
-
-import os
-import re
-import sys
-import shutil
-
-from webkitpy.common.system.executive import Executive, run_command, ScriptError
-from webkitpy.common.system.deprecated_logging import error, log
-from webkitpy.common.memoized import memoized
-
-
-def find_checkout_root():
- """Returns the current checkout root (as determined by default_scm().
-
- Returns the absolute path to the top of the WebKit checkout, or None
- if it cannot be determined.
-
- """
- scm_system = default_scm()
- if scm_system:
- return scm_system.checkout_root
- return None
-
-
-def default_scm():
- """Return the default SCM object as determined by the CWD and running code.
-
- Returns the default SCM object for the current working directory; if the
- CWD is not in a checkout, then we attempt to figure out if the SCM module
- itself is part of a checkout, and return that one. If neither is part of
- a checkout, None is returned.
-
- """
- cwd = os.getcwd()
- scm_system = detect_scm_system(cwd)
- if not scm_system:
- script_directory = os.path.dirname(os.path.abspath(__file__))
- scm_system = detect_scm_system(script_directory)
- if scm_system:
- log("The current directory (%s) is not a WebKit checkout, using %s" % (cwd, scm_system.checkout_root))
- else:
- error("FATAL: Failed to determine the SCM system for either %s or %s" % (cwd, script_directory))
- return scm_system
-
-
-def detect_scm_system(path):
- absolute_path = os.path.abspath(path)
-
- if SVN.in_working_directory(absolute_path):
- return SVN(cwd=absolute_path)
-
- if Git.in_working_directory(absolute_path):
- return Git(cwd=absolute_path)
-
- return None
-
-
-def first_non_empty_line_after_index(lines, index=0):
- first_non_empty_line = index
- for line in lines[index:]:
- if re.match("^\s*$", line):
- first_non_empty_line += 1
- else:
- break
- return first_non_empty_line
-
-
-class CommitMessage:
- def __init__(self, message):
- self.message_lines = message[first_non_empty_line_after_index(message, 0):]
-
- def body(self, lstrip=False):
- lines = self.message_lines[first_non_empty_line_after_index(self.message_lines, 1):]
- if lstrip:
- lines = [line.lstrip() for line in lines]
- return "\n".join(lines) + "\n"
-
- def description(self, lstrip=False, strip_url=False):
- line = self.message_lines[0]
- if lstrip:
- line = line.lstrip()
- if strip_url:
- line = re.sub("^(\s*)<.+> ", "\1", line)
- return line
-
- def message(self):
- return "\n".join(self.message_lines) + "\n"
-
-
-class CheckoutNeedsUpdate(ScriptError):
- def __init__(self, script_args, exit_code, output, cwd):
- ScriptError.__init__(self, script_args=script_args, exit_code=exit_code, output=output, cwd=cwd)
-
-
-def commit_error_handler(error):
- if re.search("resource out of date", error.output):
- raise CheckoutNeedsUpdate(script_args=error.script_args, exit_code=error.exit_code, output=error.output, cwd=error.cwd)
- Executive.default_error_handler(error)
-
-
-class AuthenticationError(Exception):
- def __init__(self, server_host):
- self.server_host = server_host
-
-
-class AmbiguousCommitError(Exception):
- def __init__(self, num_local_commits, working_directory_is_clean):
- self.num_local_commits = num_local_commits
- self.working_directory_is_clean = working_directory_is_clean
-
-
-# SCM methods are expected to return paths relative to self.checkout_root.
-class SCM:
- def __init__(self, cwd):
- self.cwd = cwd
- self.checkout_root = self.find_checkout_root(self.cwd)
- self.dryrun = False
-
- # A wrapper used by subclasses to create processes.
- def run(self, args, cwd=None, input=None, error_handler=None, return_exit_code=False, return_stderr=True, decode_output=True):
- # FIXME: We should set cwd appropriately.
- # FIXME: We should use Executive.
- return run_command(args,
- cwd=cwd,
- input=input,
- error_handler=error_handler,
- return_exit_code=return_exit_code,
- return_stderr=return_stderr,
- decode_output=decode_output)
-
- # SCM always returns repository relative path, but sometimes we need
- # absolute paths to pass to rm, etc.
- def absolute_path(self, repository_relative_path):
- return os.path.join(self.checkout_root, repository_relative_path)
-
- # FIXME: This belongs in Checkout, not SCM.
- def scripts_directory(self):
- return os.path.join(self.checkout_root, "WebKitTools", "Scripts")
-
- # FIXME: This belongs in Checkout, not SCM.
- def script_path(self, script_name):
- return os.path.join(self.scripts_directory(), script_name)
-
- def ensure_clean_working_directory(self, force_clean):
- if not force_clean and not self.working_directory_is_clean():
- # FIXME: Shouldn't this use cwd=self.checkout_root?
- print self.run(self.status_command(), error_handler=Executive.ignore_error)
- raise ScriptError(message="Working directory has modifications, pass --force-clean or --no-clean to continue.")
-
- log("Cleaning working directory")
- self.clean_working_directory()
-
- def ensure_no_local_commits(self, force):
- if not self.supports_local_commits():
- return
- commits = self.local_commits()
- if not len(commits):
- return
- if not force:
- error("Working directory has local commits, pass --force-clean to continue.")
- self.discard_local_commits()
-
- def run_status_and_extract_filenames(self, status_command, status_regexp):
- filenames = []
- # We run with cwd=self.checkout_root so that returned-paths are root-relative.
- for line in self.run(status_command, cwd=self.checkout_root).splitlines():
- match = re.search(status_regexp, line)
- if not match:
- continue
- # status = match.group('status')
- filename = match.group('filename')
- filenames.append(filename)
- return filenames
-
- def strip_r_from_svn_revision(self, svn_revision):
- match = re.match("^r(?P<svn_revision>\d+)", unicode(svn_revision))
- if (match):
- return match.group('svn_revision')
- return svn_revision
-
- def svn_revision_from_commit_text(self, commit_text):
- match = re.search(self.commit_success_regexp(), commit_text, re.MULTILINE)
- return match.group('svn_revision')
-
- @staticmethod
- def _subclass_must_implement():
- raise NotImplementedError("subclasses must implement")
-
- @staticmethod
- def in_working_directory(path):
- SCM._subclass_must_implement()
-
- @staticmethod
- def find_checkout_root(path):
- SCM._subclass_must_implement()
-
- @staticmethod
- def commit_success_regexp():
- SCM._subclass_must_implement()
-
- def working_directory_is_clean(self):
- self._subclass_must_implement()
-
- def clean_working_directory(self):
- self._subclass_must_implement()
-
- def status_command(self):
- self._subclass_must_implement()
-
- def add(self, path, return_exit_code=False):
- self._subclass_must_implement()
-
- def delete(self, path):
- self._subclass_must_implement()
-
- def changed_files(self, git_commit=None):
- self._subclass_must_implement()
-
- def changed_files_for_revision(self, revision):
- self._subclass_must_implement()
-
- def revisions_changing_file(self, path, limit=5):
- self._subclass_must_implement()
-
- def added_files(self):
- self._subclass_must_implement()
-
- def conflicted_files(self):
- self._subclass_must_implement()
-
- def display_name(self):
- self._subclass_must_implement()
-
- def create_patch(self, git_commit=None, changed_files=[]):
- self._subclass_must_implement()
-
- def committer_email_for_revision(self, revision):
- self._subclass_must_implement()
-
- def contents_at_revision(self, path, revision):
- self._subclass_must_implement()
-
- def diff_for_revision(self, revision):
- self._subclass_must_implement()
-
- def diff_for_file(self, path, log=None):
- self._subclass_must_implement()
-
- def show_head(self, path):
- self._subclass_must_implement()
-
- def apply_reverse_diff(self, revision):
- self._subclass_must_implement()
-
- def revert_files(self, file_paths):
- self._subclass_must_implement()
-
- def commit_with_message(self, message, username=None, git_commit=None, force_squash=False):
- self._subclass_must_implement()
-
- def svn_commit_log(self, svn_revision):
- self._subclass_must_implement()
-
- def last_svn_commit_log(self):
- self._subclass_must_implement()
-
- # Subclasses must indicate if they support local commits,
- # but the SCM baseclass will only call local_commits methods when this is true.
- @staticmethod
- def supports_local_commits():
- SCM._subclass_must_implement()
-
- def remote_merge_base():
- SCM._subclass_must_implement()
-
- def commit_locally_with_message(self, message):
- error("Your source control manager does not support local commits.")
-
- def discard_local_commits(self):
- pass
-
- def local_commits(self):
- return []
-
-
-class SVN(SCM):
- # FIXME: We should move these values to a WebKit-specific config. file.
- svn_server_host = "svn.webkit.org"
- svn_server_realm = "<http://svn.webkit.org:80> Mac OS Forge"
-
- def __init__(self, cwd):
- SCM.__init__(self, cwd)
- self._bogus_dir = None
-
- @staticmethod
- def in_working_directory(path):
- return os.path.isdir(os.path.join(path, '.svn'))
-
- @classmethod
- def find_uuid(cls, path):
- if not cls.in_working_directory(path):
- return None
- return cls.value_from_svn_info(path, 'Repository UUID')
-
- @classmethod
- def value_from_svn_info(cls, path, field_name):
- svn_info_args = ['svn', 'info', path]
- info_output = run_command(svn_info_args).rstrip()
- match = re.search("^%s: (?P<value>.+)$" % field_name, info_output, re.MULTILINE)
- if not match:
- raise ScriptError(script_args=svn_info_args, message='svn info did not contain a %s.' % field_name)
- return match.group('value')
-
- @staticmethod
- def find_checkout_root(path):
- uuid = SVN.find_uuid(path)
- # If |path| is not in a working directory, we're supposed to return |path|.
- if not uuid:
- return path
- # Search up the directory hierarchy until we find a different UUID.
- last_path = None
- while True:
- if uuid != SVN.find_uuid(path):
- return last_path
- last_path = path
- (path, last_component) = os.path.split(path)
- if last_path == path:
- return None
-
- @staticmethod
- 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'])
-
- def working_directory_is_clean(self):
- return self.run(["svn", "diff"], cwd=self.checkout_root, decode_output=False) == ""
-
- def clean_working_directory(self):
- # Make sure there are no locks lying around from a previously aborted svn invocation.
- # This is slightly dangerous, as it's possible the user is running another svn process
- # on this checkout at the same time. However, it's much more likely that we're running
- # under windows and svn just sucks (or the user interrupted svn and it failed to clean up).
- self.run(["svn", "cleanup"], cwd=self.checkout_root)
-
- # svn revert -R is not as awesome as git reset --hard.
- # It will leave added files around, causing later svn update
- # calls to fail on the bots. We make this mirror git reset --hard
- # by deleting any added files as well.
- added_files = reversed(sorted(self.added_files()))
- # added_files() returns directories for SVN, we walk the files in reverse path
- # length order so that we remove files before we try to remove the directories.
- self.run(["svn", "revert", "-R", "."], cwd=self.checkout_root)
- for path in added_files:
- # This is robust against cwd != self.checkout_root
- absolute_path = self.absolute_path(path)
- # Completely lame that there is no easy way to remove both types with one call.
- if os.path.isdir(path):
- os.rmdir(absolute_path)
- else:
- os.remove(absolute_path)
-
- def status_command(self):
- return ['svn', 'status']
-
- def _status_regexp(self, expected_types):
- field_count = 6 if self.svn_version() > "1.6" else 5
- return "^(?P<status>[%s]).{%s} (?P<filename>.+)$" % (expected_types, field_count)
-
- def _add_parent_directories(self, path):
- """Does 'svn add' to the path and its parents."""
- if self.in_working_directory(path):
- return
- dirname = os.path.dirname(path)
- # We have dirname directry - ensure it added.
- if dirname != path:
- self._add_parent_directories(dirname)
- self.add(path)
-
- def add(self, path, return_exit_code=False):
- self._add_parent_directories(os.path.dirname(os.path.abspath(path)))
- return self.run(["svn", "add", path], return_exit_code=return_exit_code)
-
- def delete(self, path):
- parent, base = os.path.split(os.path.abspath(path))
- return self.run(["svn", "delete", "--force", base], cwd=parent)
-
- def changed_files(self, git_commit=None):
- return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("ACDMR"))
-
- def changed_files_for_revision(self, revision):
- # As far as I can tell svn diff --summarize output looks just like svn status output.
- # No file contents printed, thus utf-8 auto-decoding in self.run is fine.
- status_command = ["svn", "diff", "--summarize", "-c", revision]
- return self.run_status_and_extract_filenames(status_command, self._status_regexp("ACDMR"))
-
- def revisions_changing_file(self, path, limit=5):
- revisions = []
- # svn log will exit(1) (and thus self.run will raise) if the path does not exist.
- log_command = ['svn', 'log', '--quiet', '--limit=%s' % limit, path]
- for line in self.run(log_command, cwd=self.checkout_root).splitlines():
- match = re.search('^r(?P<revision>\d+) ', line)
- if not match:
- continue
- revisions.append(int(match.group('revision')))
- return revisions
-
- def conflicted_files(self):
- return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("C"))
-
- def added_files(self):
- return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("A"))
-
- def deleted_files(self):
- return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("D"))
-
- @staticmethod
- def supports_local_commits():
- return False
-
- def display_name(self):
- return "svn"
-
- # FIXME: This method should be on Checkout.
- def create_patch(self, git_commit=None, changed_files=[]):
- """Returns a byte array (str()) representing the patch file.
- Patch files are effectively binary since they may contain
- files of multiple different encodings."""
- return self.run([self.script_path("svn-create-patch")] + changed_files,
- cwd=self.checkout_root, return_stderr=False,
- decode_output=False)
-
- def committer_email_for_revision(self, revision):
- return self.run(["svn", "propget", "svn:author", "--revprop", "-r", revision]).rstrip()
-
- def contents_at_revision(self, path, revision):
- """Returns a byte array (str()) containing the contents
- of path @ revision in the repository."""
- remote_path = "%s/%s" % (self._repository_url(), path)
- return self.run(["svn", "cat", "-r", revision, remote_path], decode_output=False)
-
- def diff_for_revision(self, revision):
- # FIXME: This should probably use cwd=self.checkout_root
- return self.run(['svn', 'diff', '-c', revision])
-
- def _bogus_dir_name(self):
- if sys.platform.startswith("win"):
- parent_dir = tempfile.gettempdir()
- else:
- parent_dir = sys.path[0] # tempdir is not secure.
- return os.path.join(parent_dir, "temp_svn_config")
-
- def _setup_bogus_dir(self, log):
- self._bogus_dir = self._bogus_dir_name()
- if not os.path.exists(self._bogus_dir):
- os.mkdir(self._bogus_dir)
- self._delete_bogus_dir = True
- else:
- self._delete_bogus_dir = False
- if log:
- log.debug(' Html: temp config dir: "%s".', self._bogus_dir)
-
- def _teardown_bogus_dir(self, log):
- if self._delete_bogus_dir:
- shutil.rmtree(self._bogus_dir, True)
- if log:
- log.debug(' Html: removed temp config dir: "%s".', self._bogus_dir)
- self._bogus_dir = None
-
- def diff_for_file(self, path, log=None):
- self._setup_bogus_dir(log)
- try:
- args = ['svn', 'diff']
- if self._bogus_dir:
- args += ['--config-dir', self._bogus_dir]
- args.append(path)
- return self.run(args)
- finally:
- self._teardown_bogus_dir(log)
-
- def show_head(self, path):
- return self.run(['svn', 'cat', '-r', 'BASE', path], decode_output=False)
-
- def _repository_url(self):
- return self.value_from_svn_info(self.checkout_root, 'URL')
-
- def apply_reverse_diff(self, revision):
- # '-c -revision' applies the inverse diff of 'revision'
- svn_merge_args = ['svn', 'merge', '--non-interactive', '-c', '-%s' % revision, self._repository_url()]
- log("WARNING: svn merge has been known to take more than 10 minutes to complete. It is recommended you use git for rollouts.")
- log("Running '%s'" % " ".join(svn_merge_args))
- # FIXME: Should this use cwd=self.checkout_root?
- self.run(svn_merge_args)
-
- def revert_files(self, file_paths):
- # 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):
- # git-commit and force are not used by SVN.
- if self.dryrun:
- # 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."
-
- svn_commit_args = ["svn", "commit"]
-
- if not username and not self.has_authorization_for_realm():
- raise AuthenticationError(self.svn_server_host)
- if username:
- svn_commit_args.extend(["--username", username])
-
- svn_commit_args.extend(["-m", message])
- # FIXME: Should this use cwd=self.checkout_root?
- return self.run(svn_commit_args, error_handler=commit_error_handler)
-
- def svn_commit_log(self, svn_revision):
- svn_revision = self.strip_r_from_svn_revision(svn_revision)
- return self.run(['svn', 'log', '--non-interactive', '--revision', svn_revision])
-
- def last_svn_commit_log(self):
- # BASE is the checkout revision, HEAD is the remote repository revision
- # http://svnbook.red-bean.com/en/1.0/ch03s03.html
- return self.svn_commit_log('BASE')
-
- def propset(self, pname, pvalue, path):
- dir, base = os.path.split(path)
- return self.run(['svn', 'pset', pname, pvalue, base], cwd=dir)
-
- def propget(self, pname, path):
- dir, base = os.path.split(path)
- return self.run(['svn', 'pget', pname, base], cwd=dir).encode('utf-8').rstrip("\n")
-
-
-# All git-specific logic should go here.
-class Git(SCM):
- def __init__(self, cwd):
- SCM.__init__(self, cwd)
-
- @classmethod
- def in_working_directory(cls, path):
- return run_command(['git', 'rev-parse', '--is-inside-work-tree'], cwd=path, error_handler=Executive.ignore_error).rstrip() == "true"
-
- @classmethod
- def find_checkout_root(cls, path):
- # "git rev-parse --show-cdup" would be another way to get to the root
- (checkout_root, dot_git) = os.path.split(run_command(['git', 'rev-parse', '--git-dir'], cwd=(path or "./")))
- # If we were using 2.6 # checkout_root = os.path.relpath(checkout_root, path)
- if not os.path.isabs(checkout_root): # Sometimes git returns relative paths
- checkout_root = os.path.join(path, checkout_root)
- return checkout_root
-
- @classmethod
- def to_object_name(cls, filepath):
- root_end_with_slash = os.path.join(cls.find_checkout_root(os.path.dirname(filepath)), '')
- return filepath.replace(root_end_with_slash, '')
-
- @classmethod
- def read_git_config(cls, key):
- # FIXME: This should probably use cwd=self.checkout_root.
- # Pass --get-all for cases where the config has multiple values
- return run_command(["git", "config", "--get-all", key],
- error_handler=Executive.ignore_error).rstrip('\n')
-
- @staticmethod
- def commit_success_regexp():
- return "^Committed r(?P<svn_revision>\d+)$"
-
- def discard_local_commits(self):
- # FIXME: This should probably use cwd=self.checkout_root
- self.run(['git', 'reset', '--hard', self.remote_branch_ref()])
-
- def local_commits(self):
- # FIXME: This should probably use cwd=self.checkout_root
- return self.run(['git', 'log', '--pretty=oneline', 'HEAD...' + self.remote_branch_ref()]).splitlines()
-
- def rebase_in_progress(self):
- return os.path.exists(os.path.join(self.checkout_root, '.git/rebase-apply'))
-
- def working_directory_is_clean(self):
- # FIXME: This should probably use cwd=self.checkout_root
- return self.run(['git', 'diff', 'HEAD', '--name-only']) == ""
-
- def clean_working_directory(self):
- # FIXME: These should probably use cwd=self.checkout_root.
- # Could run git clean here too, but that wouldn't match working_directory_is_clean
- self.run(['git', 'reset', '--hard', 'HEAD'])
- # Aborting rebase even though this does not match working_directory_is_clean
- if self.rebase_in_progress():
- self.run(['git', 'rebase', '--abort'])
-
- def status_command(self):
- # git status returns non-zero when there are changes, so we use git diff name --name-status HEAD instead.
- # No file contents printed, thus utf-8 autodecoding in self.run is fine.
- return ["git", "diff", "--name-status", "HEAD"]
-
- def _status_regexp(self, expected_types):
- return '^(?P<status>[%s])\t(?P<filename>.+)$' % expected_types
-
- def add(self, path, return_exit_code=False):
- return self.run(["git", "add", path], return_exit_code=return_exit_code)
-
- def delete(self, path):
- return self.run(["git", "rm", "-f", path])
-
- def _assert_synced(self):
- if len(run_command(['git', 'rev-list', '--max-count=1', self.remote_branch_ref(), '^HEAD'])):
- raise ScriptError(message="Not fully merged/rebased to %s. This branch needs to be synced first." % self.remote_branch_ref())
-
- def merge_base(self, git_commit):
- if git_commit:
- # Special-case HEAD.. to mean working-copy changes only.
- if git_commit.upper() == 'HEAD..':
- return 'HEAD'
-
- if '..' not in git_commit:
- git_commit = git_commit + "^.." + git_commit
- return git_commit
-
- self._assert_synced()
- return self.remote_merge_base()
-
- def changed_files(self, git_commit=None):
- status_command = ['git', 'diff', '-r', '--name-status', '-C', '-M', "--no-ext-diff", "--full-index", self.merge_base(git_commit)]
- return self.run_status_and_extract_filenames(status_command, self._status_regexp("ADM"))
-
- def _changes_files_for_commit(self, git_commit):
- # --pretty="format:" makes git show not print the commit log header,
- changed_files = self.run(["git", "show", "--pretty=format:", "--name-only", git_commit]).splitlines()
- # instead it just prints a blank line at the top, so we skip the blank line:
- return changed_files[1:]
-
- def changed_files_for_revision(self, revision):
- commit_id = self.git_commit_from_svn_revision(revision)
- return self._changes_files_for_commit(commit_id)
-
- def revisions_changing_file(self, path, limit=5):
- # git rev-list head --remove-empty --limit=5 -- path would be equivalent.
- commit_ids = self.run(["git", "log", "--remove-empty", "--pretty=format:%H", "-%s" % limit, "--", path]).splitlines()
- return filter(lambda revision: revision, map(self.svn_revision_from_git_commit, commit_ids))
-
- def conflicted_files(self):
- # We do not need to pass decode_output for this diff command
- # as we're passing --name-status which does not output any data.
- status_command = ['git', 'diff', '--name-status', '-C', '-M', '--diff-filter=U']
- return self.run_status_and_extract_filenames(status_command, self._status_regexp("U"))
-
- def added_files(self):
- return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("A"))
-
- def deleted_files(self):
- return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("D"))
-
- @staticmethod
- def supports_local_commits():
- return True
-
- def display_name(self):
- return "git"
-
- def create_patch(self, git_commit=None, changed_files=[]):
- """Returns a byte array (str()) representing the patch file.
- Patch files are effectively binary since they may contain
- files of multiple different encodings."""
- return self.run(['git', 'diff', '--binary', "--no-ext-diff", "--full-index", "-M", self.merge_base(git_commit), "--"] + changed_files, decode_output=False, cwd=self.checkout_root)
-
- def _run_git_svn_find_rev(self, arg):
- # git svn find-rev always exits 0, even when the revision or commit is not found.
- return self.run(['git', 'svn', 'find-rev', arg], cwd=self.checkout_root).rstrip()
-
- def _string_to_int_or_none(self, string):
- try:
- return int(string)
- except ValueError, e:
- return None
-
- @memoized
- def git_commit_from_svn_revision(self, svn_revision):
- git_commit = self._run_git_svn_find_rev('r%s' % svn_revision)
- if not git_commit:
- # FIXME: Alternatively we could offer to update the checkout? Or return None?
- raise ScriptError(message='Failed to find git commit for revision %s, your checkout likely needs an update.' % svn_revision)
- return git_commit
-
- @memoized
- def svn_revision_from_git_commit(self, git_commit):
- svn_revision = self._run_git_svn_find_rev(git_commit)
- return self._string_to_int_or_none(svn_revision)
-
- def contents_at_revision(self, path, revision):
- """Returns a byte array (str()) containing the contents
- of path @ revision in the repository."""
- return self.run(["git", "show", "%s:%s" % (self.git_commit_from_svn_revision(revision), path)], decode_output=False)
-
- def diff_for_revision(self, revision):
- git_commit = self.git_commit_from_svn_revision(revision)
- return self.create_patch(git_commit)
-
- def diff_for_file(self, path, log=None):
- return self.run(['git', 'diff', 'HEAD', '--', path])
-
- def show_head(self, path):
- return self.run(['git', 'show', 'HEAD:' + self.to_object_name(path)], decode_output=False)
-
- def committer_email_for_revision(self, revision):
- git_commit = self.git_commit_from_svn_revision(revision)
- committer_email = self.run(["git", "log", "-1", "--pretty=format:%ce", git_commit])
- # Git adds an extra @repository_hash to the end of every committer email, remove it:
- return committer_email.rsplit("@", 1)[0]
-
- def apply_reverse_diff(self, revision):
- # Assume the revision is an svn revision.
- git_commit = self.git_commit_from_svn_revision(revision)
- # I think this will always fail due to ChangeLogs.
- self.run(['git', 'revert', '--no-commit', git_commit], error_handler=Executive.ignore_error)
-
- def revert_files(self, file_paths):
- self.run(['git', 'checkout', 'HEAD'] + file_paths)
-
- def _assert_can_squash(self, working_directory_is_clean):
- squash = Git.read_git_config('webkit-patch.commit-should-always-squash')
- should_squash = squash and squash.lower() == "true"
-
- if not should_squash:
- # Only warn if there are actually multiple commits to squash.
- num_local_commits = len(self.local_commits())
- 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):
- # Username is ignored during Git commits.
- working_directory_is_clean = self.working_directory_is_clean()
-
- if git_commit:
- # Special-case HEAD.. to mean working-copy changes only.
- if git_commit.upper() == 'HEAD..':
- 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')
-
- # Need working directory changes to be committed so we can checkout the merge branch.
- if not working_directory_is_clean:
- # FIXME: webkit-patch land will modify the ChangeLogs to correct the reviewer.
- # 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)
-
- if not force_squash:
- self._assert_can_squash(working_directory_is_clean)
- self._assert_synced()
- self.run(['git', 'reset', '--soft', self.remote_branch_ref()])
- self.commit_locally_with_message(message)
- return self.push_local_commits_to_server()
-
- def _commit_on_branch(self, message, git_commit):
- 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])
-
- # We want to squash all this branch's commits into one commit with the proper description.
- # We do this by doing a "merge --squash" into a new commit branch, then dcommitting that.
- MERGE_BRANCH_NAME = 'webkit-patch-land'
- self.delete_branch(MERGE_BRANCH_NAME)
-
- # We might be in a directory that's present in this branch but not in the
- # trunk. Move up to the top of the tree so that git commands that expect a
- # valid CWD won't fail after we check out the merge branch.
- os.chdir(self.checkout_root)
-
- # Stuff our change into the merge branch.
- # We wrap in a try...finally block so if anything goes wrong, we clean up the branches.
- commit_succeeded = True
- try:
- self.run(['git', 'checkout', '-q', '-b', MERGE_BRANCH_NAME, self.remote_branch_ref()])
-
- for commit in commit_ids:
- # We're on a different branch now, so convert "head" to the branch name.
- commit = re.sub(r'(?i)head', branch_name, commit)
- # FIXME: Once changed_files and create_patch are modified to separately handle each
- # commit in a commit range, commit each cherry pick so they'll get dcommitted separately.
- self.run(['git', 'cherry-pick', '--no-commit', commit])
-
- self.run(['git', 'commit', '-m', message])
- output = self.push_local_commits_to_server()
- except Exception, e:
- log("COMMIT FAILED: " + str(e))
- output = "Commit failed."
- commit_succeeded = False
- finally:
- # And then swap back to the original branch and clean up.
- self.clean_working_directory()
- self.run(['git', 'checkout', '-q', branch_name])
- self.delete_branch(MERGE_BRANCH_NAME)
-
- return output
-
- def svn_commit_log(self, svn_revision):
- svn_revision = self.strip_r_from_svn_revision(svn_revision)
- return self.run(['git', 'svn', 'log', '-r', svn_revision])
-
- def last_svn_commit_log(self):
- return self.run(['git', 'svn', 'log', '--limit=1'])
-
- # Git-specific methods:
- def _branch_ref_exists(self, branch_ref):
- return self.run(['git', 'show-ref', '--quiet', '--verify', branch_ref], return_exit_code=True) == 0
-
- def delete_branch(self, branch_name):
- if self._branch_ref_exists('refs/heads/' + branch_name):
- self.run(['git', 'branch', '-D', branch_name])
-
- def remote_merge_base(self):
- return self.run(['git', 'merge-base', self.remote_branch_ref(), 'HEAD']).strip()
-
- def remote_branch_ref(self):
- # Use references so that we can avoid collisions, e.g. we don't want to operate on refs/heads/trunk if it exists.
- remote_branch_refs = Git.read_git_config('svn-remote.svn.fetch')
- if not remote_branch_refs:
- remote_master_ref = 'refs/remotes/origin/master'
- if not self._branch_ref_exists(remote_master_ref):
- raise ScriptError(message="Can't find a branch to diff against. svn-remote.svn.fetch is not in the git config and %s does not exist" % remote_master_ref)
- return remote_master_ref
-
- # FIXME: What's the right behavior when there are multiple svn-remotes listed?
- # For now, just use the first one.
- first_remote_branch_ref = remote_branch_refs.split('\n')[0]
- return first_remote_branch_ref.split(':')[1]
-
- def commit_locally_with_message(self, message):
- self.run(['git', 'commit', '--all', '-F', '-'], input=message)
-
- def push_local_commits_to_server(self):
- dcommit_command = ['git', 'svn', 'dcommit']
- if self.dryrun:
- dcommit_command.append('--dry-run')
- output = self.run(dcommit_command, error_handler=commit_error_handler)
- # 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:
- # no args : rev-list trunk..HEAD
- # A..B : rev-list A..B
- # A...B : error!
- # A B : [A, B] (different from git diff, which would use "rev-list A..B")
- def commit_ids_from_commitish_arguments(self, args):
- if not len(args):
- args.append('%s..HEAD' % self.remote_branch_ref())
-
- commit_ids = []
- for commitish in args:
- if '...' in commitish:
- raise ScriptError(message="'...' is not supported (found in '%s'). Did you mean '..'?" % commitish)
- elif '..' in commitish:
- commit_ids += reversed(self.run(['git', 'rev-list', commitish]).splitlines())
- else:
- # Turn single commits or branch or tag names into commit ids.
- commit_ids += self.run(['git', 'rev-parse', '--revs-only', commitish]).splitlines()
- return commit_ids
-
- def commit_message_for_local_commit(self, commit_id):
- commit_lines = self.run(['git', 'cat-file', 'commit', commit_id]).splitlines()
-
- # Skip the git headers.
- first_line_after_headers = 0
- for line in commit_lines:
- first_line_after_headers += 1
- if line == "":
- break
- return CommitMessage(commit_lines[first_line_after_headers:])
-
- def files_changed_summary_for_commit(self, commit_id):
- return self.run(['git', 'diff-tree', '--shortstat', '--no-commit-id', commit_id])
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py b/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py
deleted file mode 100644
index 46a2acf..0000000
--- a/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py
+++ /dev/null
@@ -1,1291 +0,0 @@
-# Copyright (C) 2009 Google Inc. All rights reserved.
-# Copyright (C) 2009 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-from __future__ import with_statement
-
-import base64
-import codecs
-import getpass
-import os
-import os.path
-import re
-import stat
-import sys
-import subprocess
-import tempfile
-import unittest
-import urllib
-import shutil
-
-from datetime import date
-from webkitpy.common.checkout.api import Checkout
-from webkitpy.common.checkout.scm import detect_scm_system, SCM, SVN, CheckoutNeedsUpdate, commit_error_handler, AuthenticationError, AmbiguousCommitError, find_checkout_root, default_scm
-from webkitpy.common.config.committers import Committer # FIXME: This should not be needed
-from webkitpy.common.net.bugzilla import Attachment # FIXME: This should not be needed
-from webkitpy.common.system.executive import Executive, run_command, ScriptError
-from webkitpy.common.system.outputcapture import OutputCapture
-
-# Eventually we will want to write tests which work for both scms. (like update_webkit, changed_files, etc.)
-# Perhaps through some SCMTest base-class which both SVNTest and GitTest inherit from.
-
-# FIXME: This should be unified into one of the executive.py commands!
-# Callers could use run_and_throw_if_fail(args, cwd=cwd, quiet=True)
-def run_silent(args, cwd=None):
- # Note: Not thread safe: http://bugs.python.org/issue2320
- process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)
- process.communicate() # ignore output
- exit_code = process.wait()
- if exit_code:
- raise ScriptError('Failed to run "%s" exit_code: %d cwd: %s' % (args, exit_code, cwd))
-
-
-def write_into_file_at_path(file_path, contents, encoding="utf-8"):
- if encoding:
- with codecs.open(file_path, "w", encoding) as file:
- file.write(contents)
- else:
- with open(file_path, "w") as file:
- file.write(contents)
-
-
-def read_from_path(file_path, encoding="utf-8"):
- with codecs.open(file_path, "r", encoding) as file:
- return file.read()
-
-
-def _make_diff(command, *args):
- # We use this wrapper to disable output decoding. diffs should be treated as
- # binary files since they may include text files of multiple differnet encodings.
- return run_command([command, "diff"] + list(args), decode_output=False)
-
-
-def _svn_diff(*args):
- return _make_diff("svn", *args)
-
-
-def _git_diff(*args):
- return _make_diff("git", *args)
-
-
-# Exists to share svn repository creation code between the git and svn tests
-class SVNTestRepository:
- @classmethod
- def _svn_add(cls, path):
- run_command(["svn", "add", path])
-
- @classmethod
- def _svn_commit(cls, message):
- run_command(["svn", "commit", "--quiet", "--message", message])
-
- @classmethod
- def _setup_test_commits(cls, test_object):
- # Add some test commits
- os.chdir(test_object.svn_checkout_path)
-
- write_into_file_at_path("test_file", "test1")
- cls._svn_add("test_file")
- cls._svn_commit("initial commit")
-
- write_into_file_at_path("test_file", "test1test2")
- # This used to be the last commit, but doing so broke
- # GitTest.test_apply_git_patch which use the inverse diff of the last commit.
- # svn-apply fails to remove directories in Git, see:
- # https://bugs.webkit.org/show_bug.cgi?id=34871
- os.mkdir("test_dir")
- # Slash should always be the right path separator since we use cygwin on Windows.
- test_file3_path = "test_dir/test_file3"
- write_into_file_at_path(test_file3_path, "third file")
- cls._svn_add("test_dir")
- cls._svn_commit("second commit")
-
- write_into_file_at_path("test_file", "test1test2test3\n")
- write_into_file_at_path("test_file2", "second file")
- cls._svn_add("test_file2")
- cls._svn_commit("third commit")
-
- # This 4th commit is used to make sure that our patch file handling
- # code correctly treats patches as binary and does not attempt to
- # decode them assuming they're utf-8.
- write_into_file_at_path("test_file", u"latin1 test: \u00A0\n", "latin1")
- write_into_file_at_path("test_file2", u"utf-8 test: \u00A0\n", "utf-8")
- cls._svn_commit("fourth commit")
-
- # svn does not seem to update after commit as I would expect.
- run_command(['svn', 'update'])
-
- @classmethod
- def setup(cls, test_object):
- # Create an test SVN repository
- test_object.svn_repo_path = tempfile.mkdtemp(suffix="svn_test_repo")
- test_object.svn_repo_url = "file://%s" % test_object.svn_repo_path # Not sure this will work on windows
- # git svn complains if we don't pass --pre-1.5-compatible, not sure why:
- # Expected FS format '2'; found format '3' at /usr/local/libexec/git-core//git-svn line 1477
- run_command(['svnadmin', 'create', '--pre-1.5-compatible', test_object.svn_repo_path])
-
- # Create a test svn checkout
- test_object.svn_checkout_path = tempfile.mkdtemp(suffix="svn_test_checkout")
- run_command(['svn', 'checkout', '--quiet', test_object.svn_repo_url, test_object.svn_checkout_path])
-
- # Create and checkout a trunk dir to match the standard svn configuration to match git-svn's expectations
- os.chdir(test_object.svn_checkout_path)
- os.mkdir('trunk')
- cls._svn_add('trunk')
- # We can add tags and branches as well if we ever need to test those.
- cls._svn_commit('add trunk')
-
- # Change directory out of the svn checkout so we can delete the checkout directory.
- # _setup_test_commits will CD back to the svn checkout directory.
- os.chdir('/')
- run_command(['rm', '-rf', test_object.svn_checkout_path])
- run_command(['svn', 'checkout', '--quiet', test_object.svn_repo_url + '/trunk', test_object.svn_checkout_path])
-
- cls._setup_test_commits(test_object)
-
- @classmethod
- def tear_down(cls, test_object):
- run_command(['rm', '-rf', test_object.svn_repo_path])
- run_command(['rm', '-rf', test_object.svn_checkout_path])
-
- # Now that we've deleted the checkout paths, cwddir may be invalid
- # Change back to a valid directory so that later calls to os.getcwd() do not fail.
- os.chdir(detect_scm_system(os.path.dirname(__file__)).checkout_root)
-
-
-class StandaloneFunctionsTest(unittest.TestCase):
- """This class tests any standalone/top-level functions in the package."""
- def setUp(self):
- self.orig_cwd = os.path.abspath(os.getcwd())
- self.orig_abspath = os.path.abspath
-
- # We capture but ignore the output from stderr to reduce unwanted
- # logging.
- self.output = OutputCapture()
- self.output.capture_output()
-
- def tearDown(self):
- os.chdir(self.orig_cwd)
- os.path.abspath = self.orig_abspath
- self.output.restore_output()
-
- def test_find_checkout_root(self):
- # Test from inside the tree.
- os.chdir(sys.path[0])
- dir = find_checkout_root()
- self.assertNotEqual(dir, None)
- self.assertTrue(os.path.exists(dir))
-
- # Test from outside the tree.
- os.chdir(os.path.expanduser("~"))
- dir = find_checkout_root()
- self.assertNotEqual(dir, None)
- self.assertTrue(os.path.exists(dir))
-
- # Mock out abspath() to test being not in a checkout at all.
- os.path.abspath = lambda x: "/"
- self.assertRaises(SystemExit, find_checkout_root)
- os.path.abspath = self.orig_abspath
-
- def test_default_scm(self):
- # Test from inside the tree.
- os.chdir(sys.path[0])
- scm = default_scm()
- self.assertNotEqual(scm, None)
-
- # Test from outside the tree.
- os.chdir(os.path.expanduser("~"))
- dir = find_checkout_root()
- self.assertNotEqual(dir, None)
-
- # Mock out abspath() to test being not in a checkout at all.
- os.path.abspath = lambda x: "/"
- self.assertRaises(SystemExit, default_scm)
- os.path.abspath = self.orig_abspath
-
-# For testing the SCM baseclass directly.
-class SCMClassTests(unittest.TestCase):
- def setUp(self):
- self.dev_null = open(os.devnull, "w") # Used to make our Popen calls quiet.
-
- def tearDown(self):
- self.dev_null.close()
-
- def test_run_command_with_pipe(self):
- input_process = subprocess.Popen(['echo', 'foo\nbar'], stdout=subprocess.PIPE, stderr=self.dev_null)
- self.assertEqual(run_command(['grep', 'bar'], input=input_process.stdout), "bar\n")
-
- # Test the non-pipe case too:
- self.assertEqual(run_command(['grep', 'bar'], input="foo\nbar"), "bar\n")
-
- command_returns_non_zero = ['/bin/sh', '--invalid-option']
- # Test when the input pipe process fails.
- input_process = subprocess.Popen(command_returns_non_zero, stdout=subprocess.PIPE, stderr=self.dev_null)
- self.assertTrue(input_process.poll() != 0)
- self.assertRaises(ScriptError, run_command, ['grep', 'bar'], input=input_process.stdout)
-
- # Test when the run_command process fails.
- input_process = subprocess.Popen(['echo', 'foo\nbar'], stdout=subprocess.PIPE, stderr=self.dev_null) # grep shows usage and calls exit(2) when called w/o arguments.
- self.assertRaises(ScriptError, run_command, command_returns_non_zero, input=input_process.stdout)
-
- def test_error_handlers(self):
- git_failure_message="Merge conflict during commit: Your file or directory 'WebCore/ChangeLog' is probably out-of-date: resource out of date; try updating at /usr/local/libexec/git-core//git-svn line 469"
- svn_failure_message="""svn: Commit failed (details follow):
-svn: File or directory 'ChangeLog' is out of date; try updating
-svn: resource out of date; try updating
-"""
- command_does_not_exist = ['does_not_exist', 'invalid_option']
- self.assertRaises(OSError, run_command, command_does_not_exist)
- self.assertRaises(OSError, run_command, command_does_not_exist, error_handler=Executive.ignore_error)
-
- command_returns_non_zero = ['/bin/sh', '--invalid-option']
- self.assertRaises(ScriptError, run_command, command_returns_non_zero)
- # Check if returns error text:
- self.assertTrue(run_command(command_returns_non_zero, error_handler=Executive.ignore_error))
-
- self.assertRaises(CheckoutNeedsUpdate, commit_error_handler, ScriptError(output=git_failure_message))
- self.assertRaises(CheckoutNeedsUpdate, commit_error_handler, ScriptError(output=svn_failure_message))
- self.assertRaises(ScriptError, commit_error_handler, ScriptError(output='blah blah blah'))
-
-
-# GitTest and SVNTest inherit from this so any test_ methods here will be run once for this class and then once for each subclass.
-class SCMTest(unittest.TestCase):
- def _create_patch(self, patch_contents):
- # FIXME: This code is brittle if the Attachment API changes.
- attachment = Attachment({"bug_id": 12345}, None)
- attachment.contents = lambda: patch_contents
-
- joe_cool = Committer(name="Joe Cool", email_or_emails=None)
- attachment.reviewer = lambda: joe_cool
-
- return attachment
-
- def _setup_webkittools_scripts_symlink(self, local_scm):
- webkit_scm = detect_scm_system(os.path.dirname(os.path.abspath(__file__)))
- webkit_scripts_directory = webkit_scm.scripts_directory()
- local_scripts_directory = local_scm.scripts_directory()
- os.mkdir(os.path.dirname(local_scripts_directory))
- os.symlink(webkit_scripts_directory, local_scripts_directory)
-
- # Tests which both GitTest and SVNTest should run.
- # FIXME: There must be a simpler way to add these w/o adding a wrapper method to both subclasses
-
- def _shared_test_changed_files(self):
- write_into_file_at_path("test_file", "changed content")
- self.assertEqual(self.scm.changed_files(), ["test_file"])
- write_into_file_at_path("test_dir/test_file3", "new stuff")
- self.assertEqual(self.scm.changed_files(), ["test_dir/test_file3", "test_file"])
- old_cwd = os.getcwd()
- os.chdir("test_dir")
- # Validate that changed_files does not change with our cwd, see bug 37015.
- self.assertEqual(self.scm.changed_files(), ["test_dir/test_file3", "test_file"])
- os.chdir(old_cwd)
-
- def _shared_test_added_files(self):
- write_into_file_at_path("test_file", "changed content")
- self.assertEqual(self.scm.added_files(), [])
-
- write_into_file_at_path("added_file", "new stuff")
- self.scm.add("added_file")
-
- os.mkdir("added_dir")
- write_into_file_at_path("added_dir/added_file2", "new stuff")
- self.scm.add("added_dir")
-
- # SVN reports directory changes, Git does not.
- added_files = self.scm.added_files()
- if "added_dir" in added_files:
- added_files.remove("added_dir")
- self.assertEqual(added_files, ["added_dir/added_file2", "added_file"])
-
- # Test also to make sure clean_working_directory removes added files
- self.scm.clean_working_directory()
- self.assertEqual(self.scm.added_files(), [])
- self.assertFalse(os.path.exists("added_file"))
- self.assertFalse(os.path.exists("added_dir"))
-
- def _shared_test_changed_files_for_revision(self):
- # SVN reports directory changes, Git does not.
- changed_files = self.scm.changed_files_for_revision(3)
- if "test_dir" in changed_files:
- changed_files.remove("test_dir")
- self.assertEqual(changed_files, ["test_dir/test_file3", "test_file"])
- self.assertEqual(sorted(self.scm.changed_files_for_revision(4)), sorted(["test_file", "test_file2"])) # Git and SVN return different orders.
- self.assertEqual(self.scm.changed_files_for_revision(2), ["test_file"])
-
- def _shared_test_contents_at_revision(self):
- self.assertEqual(self.scm.contents_at_revision("test_file", 3), "test1test2")
- self.assertEqual(self.scm.contents_at_revision("test_file", 4), "test1test2test3\n")
-
- # Verify that contents_at_revision returns a byte array, aka str():
- self.assertEqual(self.scm.contents_at_revision("test_file", 5), u"latin1 test: \u00A0\n".encode("latin1"))
- self.assertEqual(self.scm.contents_at_revision("test_file2", 5), u"utf-8 test: \u00A0\n".encode("utf-8"))
-
- self.assertEqual(self.scm.contents_at_revision("test_file2", 4), "second file")
- # Files which don't exist:
- # Currently we raise instead of returning None because detecting the difference between
- # "file not found" and any other error seems impossible with svn (git seems to expose such through the return code).
- self.assertRaises(ScriptError, self.scm.contents_at_revision, "test_file2", 2)
- self.assertRaises(ScriptError, self.scm.contents_at_revision, "does_not_exist", 2)
-
- def _shared_test_revisions_changing_file(self):
- self.assertEqual(self.scm.revisions_changing_file("test_file"), [5, 4, 3, 2])
- self.assertRaises(ScriptError, self.scm.revisions_changing_file, "non_existent_file")
-
- def _shared_test_committer_email_for_revision(self):
- self.assertEqual(self.scm.committer_email_for_revision(3), getpass.getuser()) # Committer "email" will be the current user
-
- def _shared_test_reverse_diff(self):
- self._setup_webkittools_scripts_symlink(self.scm) # Git's apply_reverse_diff uses resolve-ChangeLogs
- # Only test the simple case, as any other will end up with conflict markers.
- self.scm.apply_reverse_diff('5')
- self.assertEqual(read_from_path('test_file'), "test1test2test3\n")
-
- def _shared_test_diff_for_revision(self):
- # Patch formats are slightly different between svn and git, so just regexp for things we know should be there.
- r3_patch = self.scm.diff_for_revision(4)
- self.assertTrue(re.search('test3', r3_patch))
- self.assertFalse(re.search('test4', r3_patch))
- self.assertTrue(re.search('test2', r3_patch))
- self.assertTrue(re.search('test2', self.scm.diff_for_revision(3)))
-
- def _shared_test_svn_apply_git_patch(self):
- self._setup_webkittools_scripts_symlink(self.scm)
- git_binary_addition = """diff --git a/fizzbuzz7.gif b/fizzbuzz7.gif
-new file mode 100644
-index 0000000000000000000000000000000000000000..64a9532e7794fcd791f6f12157406d90
-60151690
-GIT binary patch
-literal 512
-zcmZ?wbhEHbRAx|MU|?iW{Kxc~?KofD;ckY;H+&5HnHl!!GQMD7h+sU{_)e9f^V3c?
-zhJP##HdZC#4K}7F68@!1jfWQg2daCm-gs#3|JREDT>c+pG4L<_2;w##WMO#ysPPap
-zLqpAf1OE938xAsSp4!5f-o><?VKe(#0jEcwfHGF4%M1^kRs14oVBp2ZEL{E1N<-zJ
-zsfLmOtKta;2_;2c#^S1-8cf<nb!QnGl>c!Xe6RXvrEtAWBvSDTgTO1j3vA31Puw!A
-zs(87q)j_mVDTqBo-P+03-P5mHCEnJ+x}YdCuS7#bCCyePUe(ynK+|4b-3qK)T?Z&)
-zYG+`tl4h?GZv_$t82}X4*DTE|$;{DEiPyF@)U-1+FaX++T9H{&%cag`W1|zVP@`%b
-zqiSkp6{BTpWTkCr!=<C6Q=?#~R8^JfrliAF6Q^gV9Iup8RqCXqqhqC`qsyhk<-nlB
-z00f{QZvfK&|Nm#oZ0TQl`Yr$BIa6A@16O26ud7H<QM=xl`toLKnz-3h@9c9q&wm|X
-z{89I|WPyD!*M?gv?q`;L=2YFeXrJQNti4?}s!zFo=5CzeBxC69xA<zrjP<wUcCRh4
-ptUl-ZG<%a~#LwkIWv&q!KSCH7tQ8cJDiw+|GV?MN)RjY50RTb-xvT&H
-
-literal 0
-HcmV?d00001
-
-"""
- self.checkout.apply_patch(self._create_patch(git_binary_addition))
- added = read_from_path('fizzbuzz7.gif', encoding=None)
- self.assertEqual(512, len(added))
- self.assertTrue(added.startswith('GIF89a'))
- self.assertTrue('fizzbuzz7.gif' in self.scm.changed_files())
-
- # The file already exists.
- self.assertRaises(ScriptError, self.checkout.apply_patch, self._create_patch(git_binary_addition))
-
- git_binary_modification = """diff --git a/fizzbuzz7.gif b/fizzbuzz7.gif
-index 64a9532e7794fcd791f6f12157406d9060151690..323fae03f4606ea9991df8befbb2fca7
-GIT binary patch
-literal 7
-OcmYex&reD$;sO8*F9L)B
-
-literal 512
-zcmZ?wbhEHbRAx|MU|?iW{Kxc~?KofD;ckY;H+&5HnHl!!GQMD7h+sU{_)e9f^V3c?
-zhJP##HdZC#4K}7F68@!1jfWQg2daCm-gs#3|JREDT>c+pG4L<_2;w##WMO#ysPPap
-zLqpAf1OE938xAsSp4!5f-o><?VKe(#0jEcwfHGF4%M1^kRs14oVBp2ZEL{E1N<-zJ
-zsfLmOtKta;2_;2c#^S1-8cf<nb!QnGl>c!Xe6RXvrEtAWBvSDTgTO1j3vA31Puw!A
-zs(87q)j_mVDTqBo-P+03-P5mHCEnJ+x}YdCuS7#bCCyePUe(ynK+|4b-3qK)T?Z&)
-zYG+`tl4h?GZv_$t82}X4*DTE|$;{DEiPyF@)U-1+FaX++T9H{&%cag`W1|zVP@`%b
-zqiSkp6{BTpWTkCr!=<C6Q=?#~R8^JfrliAF6Q^gV9Iup8RqCXqqhqC`qsyhk<-nlB
-z00f{QZvfK&|Nm#oZ0TQl`Yr$BIa6A@16O26ud7H<QM=xl`toLKnz-3h@9c9q&wm|X
-z{89I|WPyD!*M?gv?q`;L=2YFeXrJQNti4?}s!zFo=5CzeBxC69xA<zrjP<wUcCRh4
-ptUl-ZG<%a~#LwkIWv&q!KSCH7tQ8cJDiw+|GV?MN)RjY50RTb-xvT&H
-
-"""
- self.checkout.apply_patch(self._create_patch(git_binary_modification))
- modified = read_from_path('fizzbuzz7.gif', encoding=None)
- self.assertEqual('foobar\n', modified)
- self.assertTrue('fizzbuzz7.gif' in self.scm.changed_files())
-
- # Applying the same modification should fail.
- self.assertRaises(ScriptError, self.checkout.apply_patch, self._create_patch(git_binary_modification))
-
- git_binary_deletion = """diff --git a/fizzbuzz7.gif b/fizzbuzz7.gif
-deleted file mode 100644
-index 323fae0..0000000
-GIT binary patch
-literal 0
-HcmV?d00001
-
-literal 7
-OcmYex&reD$;sO8*F9L)B
-
-"""
- self.checkout.apply_patch(self._create_patch(git_binary_deletion))
- self.assertFalse(os.path.exists('fizzbuzz7.gif'))
- self.assertFalse('fizzbuzz7.gif' in self.scm.changed_files())
-
- # Cannot delete again.
- self.assertRaises(ScriptError, self.checkout.apply_patch, self._create_patch(git_binary_deletion))
-
- def _shared_test_add_recursively(self):
- os.mkdir("added_dir")
- write_into_file_at_path("added_dir/added_file", "new stuff")
- self.scm.add("added_dir/added_file")
- self.assertTrue("added_dir/added_file" in self.scm.added_files())
-
-class SVNTest(SCMTest):
-
- @staticmethod
- def _set_date_and_reviewer(changelog_entry):
- # Joe Cool matches the reviewer set in SCMTest._create_patch
- changelog_entry = changelog_entry.replace('REVIEWER_HERE', 'Joe Cool')
- # svn-apply will update ChangeLog entries with today's date.
- return changelog_entry.replace('DATE_HERE', date.today().isoformat())
-
- def test_svn_apply(self):
- first_entry = """2009-10-26 Eric Seidel <eric@webkit.org>
-
- Reviewed by Foo Bar.
-
- Most awesome change ever.
-
- * scm_unittest.py:
-"""
- intermediate_entry = """2009-10-27 Eric Seidel <eric@webkit.org>
-
- Reviewed by Baz Bar.
-
- A more awesomer change yet!
-
- * scm_unittest.py:
-"""
- one_line_overlap_patch = """Index: ChangeLog
-===================================================================
---- ChangeLog (revision 5)
-+++ ChangeLog (working copy)
-@@ -1,5 +1,13 @@
- 2009-10-26 Eric Seidel <eric@webkit.org>
-
-+ Reviewed by NOBODY (OOPS!).
-+
-+ Second most awesome change ever.
-+
-+ * scm_unittest.py:
-+
-+2009-10-26 Eric Seidel <eric@webkit.org>
-+
- Reviewed by Foo Bar.
-
- Most awesome change ever.
-"""
- one_line_overlap_entry = """DATE_HERE Eric Seidel <eric@webkit.org>
-
- Reviewed by REVIEWER_HERE.
-
- Second most awesome change ever.
-
- * scm_unittest.py:
-"""
- two_line_overlap_patch = """Index: ChangeLog
-===================================================================
---- ChangeLog (revision 5)
-+++ ChangeLog (working copy)
-@@ -2,6 +2,14 @@
-
- Reviewed by Foo Bar.
-
-+ Second most awesome change ever.
-+
-+ * scm_unittest.py:
-+
-+2009-10-26 Eric Seidel <eric@webkit.org>
-+
-+ Reviewed by Foo Bar.
-+
- Most awesome change ever.
-
- * scm_unittest.py:
-"""
- two_line_overlap_entry = """DATE_HERE Eric Seidel <eric@webkit.org>
-
- Reviewed by Foo Bar.
-
- Second most awesome change ever.
-
- * scm_unittest.py:
-"""
- write_into_file_at_path('ChangeLog', first_entry)
- run_command(['svn', 'add', 'ChangeLog'])
- run_command(['svn', 'commit', '--quiet', '--message', 'ChangeLog commit'])
-
- # Patch files were created against just 'first_entry'.
- # Add a second commit to make svn-apply have to apply the patches with fuzz.
- changelog_contents = "%s\n%s" % (intermediate_entry, first_entry)
- write_into_file_at_path('ChangeLog', changelog_contents)
- run_command(['svn', 'commit', '--quiet', '--message', 'Intermediate commit'])
-
- self._setup_webkittools_scripts_symlink(self.scm)
- self.checkout.apply_patch(self._create_patch(one_line_overlap_patch))
- expected_changelog_contents = "%s\n%s" % (self._set_date_and_reviewer(one_line_overlap_entry), changelog_contents)
- self.assertEquals(read_from_path('ChangeLog'), expected_changelog_contents)
-
- self.scm.revert_files(['ChangeLog'])
- self.checkout.apply_patch(self._create_patch(two_line_overlap_patch))
- expected_changelog_contents = "%s\n%s" % (self._set_date_and_reviewer(two_line_overlap_entry), changelog_contents)
- self.assertEquals(read_from_path('ChangeLog'), expected_changelog_contents)
-
- def setUp(self):
- SVNTestRepository.setup(self)
- os.chdir(self.svn_checkout_path)
- self.scm = detect_scm_system(self.svn_checkout_path)
- # For historical reasons, we test some checkout code here too.
- self.checkout = Checkout(self.scm)
-
- def tearDown(self):
- SVNTestRepository.tear_down(self)
-
- def test_detect_scm_system_relative_url(self):
- scm = detect_scm_system(".")
- # I wanted to assert that we got the right path, but there was some
- # crazy magic with temp folder names that I couldn't figure out.
- self.assertTrue(scm.checkout_root)
-
- def test_create_patch_is_full_patch(self):
- test_dir_path = os.path.join(self.svn_checkout_path, "test_dir2")
- os.mkdir(test_dir_path)
- test_file_path = os.path.join(test_dir_path, 'test_file2')
- write_into_file_at_path(test_file_path, 'test content')
- run_command(['svn', 'add', 'test_dir2'])
-
- # create_patch depends on 'svn-create-patch', so make a dummy version.
- scripts_path = os.path.join(self.svn_checkout_path, 'WebKitTools', 'Scripts')
- os.makedirs(scripts_path)
- create_patch_path = os.path.join(scripts_path, 'svn-create-patch')
- write_into_file_at_path(create_patch_path, '#!/bin/sh\necho $PWD') # We could pass -n to prevent the \n, but not all echo accept -n.
- os.chmod(create_patch_path, stat.S_IXUSR | stat.S_IRUSR)
-
- # Change into our test directory and run the create_patch command.
- os.chdir(test_dir_path)
- scm = detect_scm_system(test_dir_path)
- self.assertEqual(scm.checkout_root, self.svn_checkout_path) # Sanity check that detection worked right.
- patch_contents = scm.create_patch()
- # Our fake 'svn-create-patch' returns $PWD instead of a patch, check that it was executed from the root of the repo.
- self.assertEqual("%s\n" % os.path.realpath(scm.checkout_root), patch_contents) # Add a \n because echo adds a \n.
-
- def test_detection(self):
- scm = detect_scm_system(self.svn_checkout_path)
- self.assertEqual(scm.display_name(), "svn")
- self.assertEqual(scm.supports_local_commits(), False)
-
- def test_apply_small_binary_patch(self):
- patch_contents = """Index: test_file.swf
-===================================================================
-Cannot display: file marked as a binary type.
-svn:mime-type = application/octet-stream
-
-Property changes on: test_file.swf
-___________________________________________________________________
-Name: svn:mime-type
- + application/octet-stream
-
-
-Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
-"""
- expected_contents = base64.b64decode("Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==")
- self._setup_webkittools_scripts_symlink(self.scm)
- patch_file = self._create_patch(patch_contents)
- self.checkout.apply_patch(patch_file)
- actual_contents = read_from_path("test_file.swf", encoding=None)
- self.assertEqual(actual_contents, expected_contents)
-
- def test_apply_svn_patch(self):
- scm = detect_scm_system(self.svn_checkout_path)
- patch = self._create_patch(_svn_diff("-r5:4"))
- self._setup_webkittools_scripts_symlink(scm)
- Checkout(scm).apply_patch(patch)
-
- def test_apply_svn_patch_force(self):
- scm = detect_scm_system(self.svn_checkout_path)
- patch = self._create_patch(_svn_diff("-r3:5"))
- self._setup_webkittools_scripts_symlink(scm)
- self.assertRaises(ScriptError, Checkout(scm).apply_patch, patch, force=True)
-
- def test_commit_logs(self):
- # Commits have dates and usernames in them, so we can't just direct compare.
- self.assertTrue(re.search('fourth commit', self.scm.last_svn_commit_log()))
- self.assertTrue(re.search('second commit', self.scm.svn_commit_log(3)))
-
- def _shared_test_commit_with_message(self, username=None):
- write_into_file_at_path('test_file', 'more test content')
- 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_text_parsing(self):
- self._shared_test_commit_with_message()
-
- def test_commit_with_username(self):
- self._shared_test_commit_with_message("dbates@webkit.org")
-
- def test_commit_without_authorization(self):
- self.scm.has_authorization_for_realm = lambda: False
- self.assertRaises(AuthenticationError, self._shared_test_commit_with_message)
-
- def test_has_authorization_for_realm(self):
- scm = detect_scm_system(self.svn_checkout_path)
- 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)
- 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))
- os.remove(fake_webkit_auth_file)
- os.rmdir(svn_config_dir_path)
- os.rmdir(fake_home_dir)
-
- def test_not_have_authorization_for_realm(self):
- scm = detect_scm_system(self.svn_checkout_path)
- 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))
- os.rmdir(svn_config_dir_path)
- os.rmdir(fake_home_dir)
-
- def test_reverse_diff(self):
- self._shared_test_reverse_diff()
-
- def test_diff_for_revision(self):
- self._shared_test_diff_for_revision()
-
- def test_svn_apply_git_patch(self):
- self._shared_test_svn_apply_git_patch()
-
- def test_changed_files(self):
- self._shared_test_changed_files()
-
- def test_changed_files_for_revision(self):
- self._shared_test_changed_files_for_revision()
-
- def test_added_files(self):
- self._shared_test_added_files()
-
- def test_contents_at_revision(self):
- self._shared_test_contents_at_revision()
-
- def test_revisions_changing_file(self):
- self._shared_test_revisions_changing_file()
-
- def test_committer_email_for_revision(self):
- self._shared_test_committer_email_for_revision()
-
- def test_add_recursively(self):
- self._shared_test_add_recursively()
-
- def test_delete(self):
- os.chdir(self.svn_checkout_path)
- self.scm.delete("test_file")
- self.assertTrue("test_file" in self.scm.deleted_files())
-
- def test_propset_propget(self):
- filepath = os.path.join(self.svn_checkout_path, "test_file")
- expected_mime_type = "x-application/foo-bar"
- self.scm.propset("svn:mime-type", expected_mime_type, filepath)
- self.assertEqual(expected_mime_type, self.scm.propget("svn:mime-type", filepath))
-
- def test_show_head(self):
- write_into_file_at_path("test_file", u"Hello!", "utf-8")
- SVNTestRepository._svn_commit("fourth commit")
- self.assertEqual("Hello!", self.scm.show_head('test_file'))
-
- def test_show_head_binary(self):
- data = "\244"
- write_into_file_at_path("binary_file", data, encoding=None)
- self.scm.add("binary_file")
- self.scm.commit_with_message("a test commit")
- self.assertEqual(data, self.scm.show_head('binary_file'))
-
- def do_test_diff_for_file(self):
- write_into_file_at_path('test_file', 'some content')
- self.scm.commit_with_message("a test commit")
- diff = self.scm.diff_for_file('test_file')
- self.assertEqual(diff, "")
-
- write_into_file_at_path("test_file", "changed content")
- diff = self.scm.diff_for_file('test_file')
- self.assertTrue("-some content" in diff)
- self.assertTrue("+changed content" in diff)
-
- def clean_bogus_dir(self):
- self.bogus_dir = self.scm._bogus_dir_name()
- if os.path.exists(self.bogus_dir):
- shutil.rmtree(self.bogus_dir)
-
- def test_diff_for_file_with_existing_bogus_dir(self):
- self.clean_bogus_dir()
- os.mkdir(self.bogus_dir)
- self.do_test_diff_for_file()
- self.assertTrue(os.path.exists(self.bogus_dir))
- shutil.rmtree(self.bogus_dir)
-
- def test_diff_for_file_with_missing_bogus_dir(self):
- self.clean_bogus_dir()
- self.do_test_diff_for_file()
- self.assertFalse(os.path.exists(self.bogus_dir))
-
- def test_svn_lock(self):
- svn_root_lock_path = ".svn/lock"
- write_into_file_at_path(svn_root_lock_path, "", "utf-8")
- # webkit-patch uses a Checkout object and runs update-webkit, just use svn update here.
- self.assertRaises(ScriptError, run_command, ['svn', 'update'])
- self.scm.clean_working_directory()
- self.assertFalse(os.path.exists(svn_root_lock_path))
- run_command(['svn', 'update']) # Should succeed and not raise.
-
-
-class GitTest(SCMTest):
-
- def setUp(self):
- """Sets up fresh git repository with one commit. Then setups a second git
- repo that tracks the first one."""
- self.original_dir = os.getcwd()
-
- self.untracking_checkout_path = tempfile.mkdtemp(suffix="git_test_checkout2")
- run_command(['git', 'init', self.untracking_checkout_path])
-
- os.chdir(self.untracking_checkout_path)
- write_into_file_at_path('foo_file', 'foo')
- run_command(['git', 'add', 'foo_file'])
- run_command(['git', 'commit', '-am', 'dummy commit'])
- self.untracking_scm = detect_scm_system(self.untracking_checkout_path)
-
- self.tracking_git_checkout_path = tempfile.mkdtemp(suffix="git_test_checkout")
- run_command(['git', 'clone', '--quiet', self.untracking_checkout_path, self.tracking_git_checkout_path])
- os.chdir(self.tracking_git_checkout_path)
- self.tracking_scm = detect_scm_system(self.tracking_git_checkout_path)
-
- def tearDown(self):
- # Change back to a valid directory so that later calls to os.getcwd() do not fail.
- os.chdir(self.original_dir)
- run_command(['rm', '-rf', self.tracking_git_checkout_path])
- run_command(['rm', '-rf', self.untracking_checkout_path])
-
- def test_remote_branch_ref(self):
- self.assertEqual(self.tracking_scm.remote_branch_ref(), 'refs/remotes/origin/master')
-
- os.chdir(self.untracking_checkout_path)
- self.assertRaises(ScriptError, self.untracking_scm.remote_branch_ref)
-
- def test_multiple_remotes(self):
- run_command(['git', 'config', '--add', 'svn-remote.svn.fetch', 'trunk:remote1'])
- run_command(['git', 'config', '--add', 'svn-remote.svn.fetch', 'trunk:remote2'])
- self.assertEqual(self.tracking_scm.remote_branch_ref(), 'remote1')
-
-class GitSVNTest(SCMTest):
-
- def _setup_git_checkout(self):
- self.git_checkout_path = tempfile.mkdtemp(suffix="git_test_checkout")
- # --quiet doesn't make git svn silent, so we use run_silent to redirect output
- run_silent(['git', 'svn', 'clone', '-T', 'trunk', self.svn_repo_url, self.git_checkout_path])
- os.chdir(self.git_checkout_path)
-
- def _tear_down_git_checkout(self):
- # Change back to a valid directory so that later calls to os.getcwd() do not fail.
- os.chdir(self.original_dir)
- run_command(['rm', '-rf', self.git_checkout_path])
-
- def setUp(self):
- self.original_dir = os.getcwd()
-
- SVNTestRepository.setup(self)
- self._setup_git_checkout()
- self.scm = detect_scm_system(self.git_checkout_path)
- # For historical reasons, we test some checkout code here too.
- self.checkout = Checkout(self.scm)
-
- def tearDown(self):
- SVNTestRepository.tear_down(self)
- self._tear_down_git_checkout()
-
- def test_detection(self):
- scm = detect_scm_system(self.git_checkout_path)
- self.assertEqual(scm.display_name(), "git")
- self.assertEqual(scm.supports_local_commits(), True)
-
- def test_read_git_config(self):
- key = 'test.git-config'
- value = 'git-config value'
- run_command(['git', 'config', key, value])
- self.assertEqual(self.scm.read_git_config(key), value)
-
- def test_local_commits(self):
- test_file = os.path.join(self.git_checkout_path, 'test_file')
- write_into_file_at_path(test_file, 'foo')
- run_command(['git', 'commit', '-a', '-m', 'local commit'])
-
- self.assertEqual(len(self.scm.local_commits()), 1)
-
- def test_discard_local_commits(self):
- test_file = os.path.join(self.git_checkout_path, 'test_file')
- write_into_file_at_path(test_file, 'foo')
- run_command(['git', 'commit', '-a', '-m', 'local commit'])
-
- self.assertEqual(len(self.scm.local_commits()), 1)
- self.scm.discard_local_commits()
- self.assertEqual(len(self.scm.local_commits()), 0)
-
- def test_delete_branch(self):
- new_branch = 'foo'
-
- run_command(['git', 'checkout', '-b', new_branch])
- self.assertEqual(run_command(['git', 'symbolic-ref', 'HEAD']).strip(), 'refs/heads/' + new_branch)
-
- run_command(['git', 'checkout', '-b', 'bar'])
- self.scm.delete_branch(new_branch)
-
- self.assertFalse(re.search(r'foo', run_command(['git', 'branch'])))
-
- def test_remote_merge_base(self):
- # Diff to merge-base should include working-copy changes,
- # which the diff to svn_branch.. doesn't.
- test_file = os.path.join(self.git_checkout_path, 'test_file')
- write_into_file_at_path(test_file, 'foo')
-
- diff_to_common_base = _git_diff(self.scm.remote_branch_ref() + '..')
- diff_to_merge_base = _git_diff(self.scm.remote_merge_base())
-
- self.assertFalse(re.search(r'foo', diff_to_common_base))
- self.assertTrue(re.search(r'foo', diff_to_merge_base))
-
- def test_rebase_in_progress(self):
- svn_test_file = os.path.join(self.svn_checkout_path, 'test_file')
- write_into_file_at_path(svn_test_file, "svn_checkout")
- run_command(['svn', 'commit', '--message', 'commit to conflict with git commit'], cwd=self.svn_checkout_path)
-
- git_test_file = os.path.join(self.git_checkout_path, 'test_file')
- write_into_file_at_path(git_test_file, "git_checkout")
- run_command(['git', 'commit', '-a', '-m', 'commit to be thrown away by rebase abort'])
-
- # --quiet doesn't make git svn silent, so use run_silent to redirect output
- self.assertRaises(ScriptError, run_silent, ['git', 'svn', '--quiet', 'rebase']) # Will fail due to a conflict leaving us mid-rebase.
-
- scm = detect_scm_system(self.git_checkout_path)
- self.assertTrue(scm.rebase_in_progress())
-
- # Make sure our cleanup works.
- scm.clean_working_directory()
- self.assertFalse(scm.rebase_in_progress())
-
- # Make sure cleanup doesn't throw when no rebase is in progress.
- scm.clean_working_directory()
-
- def test_commitish_parsing(self):
- scm = detect_scm_system(self.git_checkout_path)
-
- # Multiple revisions are cherry-picked.
- self.assertEqual(len(scm.commit_ids_from_commitish_arguments(['HEAD~2'])), 1)
- self.assertEqual(len(scm.commit_ids_from_commitish_arguments(['HEAD', 'HEAD~2'])), 2)
-
- # ... is an invalid range specifier
- self.assertRaises(ScriptError, scm.commit_ids_from_commitish_arguments, ['trunk...HEAD'])
-
- def test_commitish_order(self):
- scm = detect_scm_system(self.git_checkout_path)
-
- commit_range = 'HEAD~3..HEAD'
-
- actual_commits = scm.commit_ids_from_commitish_arguments([commit_range])
- expected_commits = []
- expected_commits += reversed(run_command(['git', 'rev-list', commit_range]).splitlines())
-
- self.assertEqual(actual_commits, expected_commits)
-
- def test_apply_git_patch(self):
- scm = detect_scm_system(self.git_checkout_path)
- # We carefullly pick a diff which does not have a directory addition
- # as currently svn-apply will error out when trying to remove directories
- # in Git: https://bugs.webkit.org/show_bug.cgi?id=34871
- patch = self._create_patch(_git_diff('HEAD..HEAD^'))
- self._setup_webkittools_scripts_symlink(scm)
- Checkout(scm).apply_patch(patch)
-
- def test_apply_git_patch_force(self):
- scm = detect_scm_system(self.git_checkout_path)
- patch = self._create_patch(_git_diff('HEAD~2..HEAD'))
- self._setup_webkittools_scripts_symlink(scm)
- self.assertRaises(ScriptError, Checkout(scm).apply_patch, patch, force=True)
-
- def test_commit_text_parsing(self):
- write_into_file_at_path('test_file', 'more test content')
- 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'])
- scm = detect_scm_system(self.git_checkout_path)
- commit_text = scm.commit_with_message("yet another test commit")
-
- self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
- svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
- self.assertTrue(re.search(r'test_file_commit1', svn_log))
-
- def _one_local_commit(self):
- write_into_file_at_path('test_file_commit1', 'more test content')
- run_command(['git', 'add', 'test_file_commit1'])
- self.scm.commit_locally_with_message("another test commit")
-
- def _one_local_commit_plus_working_copy_changes(self):
- self._one_local_commit()
- write_into_file_at_path('test_file_commit2', 'still more test content')
- run_command(['git', 'add', 'test_file_commit2'])
-
- def _two_local_commits(self):
- self._one_local_commit()
- write_into_file_at_path('test_file_commit2', 'still more test content')
- run_command(['git', 'add', 'test_file_commit2'])
- self.scm.commit_locally_with_message("yet another test commit")
-
- def _three_local_commits(self):
- write_into_file_at_path('test_file_commit0', 'more test content')
- run_command(['git', 'add', 'test_file_commit0'])
- self.scm.commit_locally_with_message("another test commit")
- self._two_local_commits()
-
- def test_revisions_changing_files_with_local_commit(self):
- self._one_local_commit()
- self.assertEquals(self.scm.revisions_changing_file('test_file_commit1'), [])
-
- def test_commit_with_message(self):
- self._one_local_commit_plus_working_copy_changes()
- scm = detect_scm_system(self.git_checkout_path)
- self.assertRaises(AmbiguousCommitError, scm.commit_with_message, "yet another test commit")
- commit_text = scm.commit_with_message("yet another test commit", force_squash=True)
-
- self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
- svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
- self.assertTrue(re.search(r'test_file_commit2', svn_log))
- self.assertTrue(re.search(r'test_file_commit1', svn_log))
-
- def test_commit_with_message_git_commit(self):
- self._two_local_commits()
-
- scm = detect_scm_system(self.git_checkout_path)
- commit_text = scm.commit_with_message("another test commit", git_commit="HEAD^")
- self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
-
- svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
- self.assertTrue(re.search(r'test_file_commit1', svn_log))
- self.assertFalse(re.search(r'test_file_commit2', svn_log))
-
- def test_commit_with_message_git_commit_range(self):
- self._three_local_commits()
-
- scm = detect_scm_system(self.git_checkout_path)
- commit_text = scm.commit_with_message("another test commit", git_commit="HEAD~2..HEAD")
- self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
-
- svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
- self.assertFalse(re.search(r'test_file_commit0', svn_log))
- self.assertTrue(re.search(r'test_file_commit1', svn_log))
- self.assertTrue(re.search(r'test_file_commit2', svn_log))
-
- def test_changed_files_working_copy_only(self):
- self._one_local_commit_plus_working_copy_changes()
- scm = detect_scm_system(self.git_checkout_path)
- commit_text = scm.commit_with_message("another test commit", git_commit="HEAD..")
- self.assertFalse(re.search(r'test_file_commit1', svn_log))
- self.assertTrue(re.search(r'test_file_commit2', svn_log))
-
- def test_commit_with_message_only_local_commit(self):
- self._one_local_commit()
- scm = detect_scm_system(self.git_checkout_path)
- commit_text = scm.commit_with_message("another test commit")
- svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
- self.assertTrue(re.search(r'test_file_commit1', svn_log))
-
- def test_commit_with_message_multiple_local_commits_and_working_copy(self):
- self._two_local_commits()
- write_into_file_at_path('test_file_commit1', 'working copy change')
- scm = detect_scm_system(self.git_checkout_path)
-
- self.assertRaises(AmbiguousCommitError, scm.commit_with_message, "another test commit")
- commit_text = scm.commit_with_message("another test commit", force_squash=True)
-
- self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
- svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
- self.assertTrue(re.search(r'test_file_commit2', svn_log))
- self.assertTrue(re.search(r'test_file_commit1', svn_log))
-
- def test_commit_with_message_git_commit_and_working_copy(self):
- self._two_local_commits()
- write_into_file_at_path('test_file_commit1', 'working copy change')
- scm = detect_scm_system(self.git_checkout_path)
- self.assertRaises(ScriptError, scm.commit_with_message, "another test commit", git_commit="HEAD^")
-
- def test_commit_with_message_multiple_local_commits_always_squash(self):
- self._two_local_commits()
- scm = detect_scm_system(self.git_checkout_path)
- scm._assert_can_squash = lambda working_directory_is_clean: True
- commit_text = scm.commit_with_message("yet another test commit")
- self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
-
- svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
- self.assertTrue(re.search(r'test_file_commit2', svn_log))
- self.assertTrue(re.search(r'test_file_commit1', svn_log))
-
- def test_commit_with_message_multiple_local_commits(self):
- self._two_local_commits()
- scm = detect_scm_system(self.git_checkout_path)
- self.assertRaises(AmbiguousCommitError, scm.commit_with_message, "yet another test commit")
- commit_text = scm.commit_with_message("yet another test commit", force_squash=True)
-
- self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
-
- svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
- self.assertTrue(re.search(r'test_file_commit2', svn_log))
- self.assertTrue(re.search(r'test_file_commit1', svn_log))
-
- def test_commit_with_message_not_synced(self):
- run_command(['git', 'checkout', '-b', 'my-branch', 'trunk~3'])
- self._two_local_commits()
- scm = detect_scm_system(self.git_checkout_path)
- self.assertRaises(AmbiguousCommitError, scm.commit_with_message, "another test commit")
- self.assertRaises(ScriptError, scm.commit_with_message, "another test commit", force_squash=True)
-
- def test_remote_branch_ref(self):
- self.assertEqual(self.scm.remote_branch_ref(), 'refs/remotes/trunk')
-
- def test_reverse_diff(self):
- self._shared_test_reverse_diff()
-
- def test_diff_for_revision(self):
- self._shared_test_diff_for_revision()
-
- def test_svn_apply_git_patch(self):
- self._shared_test_svn_apply_git_patch()
-
- def test_create_patch_local_plus_working_copy(self):
- self._one_local_commit_plus_working_copy_changes()
- scm = detect_scm_system(self.git_checkout_path)
- patch = scm.create_patch()
- self.assertTrue(re.search(r'test_file_commit1', patch))
- self.assertTrue(re.search(r'test_file_commit2', patch))
-
- def test_create_patch(self):
- self._one_local_commit_plus_working_copy_changes()
- scm = detect_scm_system(self.git_checkout_path)
- patch = scm.create_patch()
- self.assertTrue(re.search(r'test_file_commit2', patch))
- self.assertTrue(re.search(r'test_file_commit1', patch))
-
- def test_create_patch_with_changed_files(self):
- self._one_local_commit_plus_working_copy_changes()
- scm = detect_scm_system(self.git_checkout_path)
- patch = scm.create_patch(changed_files=['test_file_commit2'])
- self.assertTrue(re.search(r'test_file_commit2', patch))
-
- def test_create_patch_with_rm_and_changed_files(self):
- self._one_local_commit_plus_working_copy_changes()
- scm = detect_scm_system(self.git_checkout_path)
- os.remove('test_file_commit1')
- patch = scm.create_patch()
- patch_with_changed_files = scm.create_patch(changed_files=['test_file_commit1', 'test_file_commit2'])
- self.assertEquals(patch, patch_with_changed_files)
-
- def test_create_patch_git_commit(self):
- self._two_local_commits()
- scm = detect_scm_system(self.git_checkout_path)
- patch = scm.create_patch(git_commit="HEAD^")
- self.assertTrue(re.search(r'test_file_commit1', patch))
- self.assertFalse(re.search(r'test_file_commit2', patch))
-
- def test_create_patch_git_commit_range(self):
- self._three_local_commits()
- scm = detect_scm_system(self.git_checkout_path)
- patch = scm.create_patch(git_commit="HEAD~2..HEAD")
- self.assertFalse(re.search(r'test_file_commit0', patch))
- self.assertTrue(re.search(r'test_file_commit2', patch))
- self.assertTrue(re.search(r'test_file_commit1', patch))
-
- def test_create_patch_working_copy_only(self):
- self._one_local_commit_plus_working_copy_changes()
- scm = detect_scm_system(self.git_checkout_path)
- patch = scm.create_patch(git_commit="HEAD..")
- self.assertFalse(re.search(r'test_file_commit1', patch))
- self.assertTrue(re.search(r'test_file_commit2', patch))
-
- def test_create_patch_multiple_local_commits(self):
- self._two_local_commits()
- scm = detect_scm_system(self.git_checkout_path)
- patch = scm.create_patch()
- self.assertTrue(re.search(r'test_file_commit2', patch))
- self.assertTrue(re.search(r'test_file_commit1', patch))
-
- def test_create_patch_not_synced(self):
- run_command(['git', 'checkout', '-b', 'my-branch', 'trunk~3'])
- self._two_local_commits()
- scm = detect_scm_system(self.git_checkout_path)
- self.assertRaises(ScriptError, scm.create_patch)
-
- def test_create_binary_patch(self):
- # Create a git binary patch and check the contents.
- scm = detect_scm_system(self.git_checkout_path)
- test_file_name = 'binary_file'
- test_file_path = os.path.join(self.git_checkout_path, test_file_name)
- file_contents = ''.join(map(chr, range(256)))
- write_into_file_at_path(test_file_path, file_contents, encoding=None)
- run_command(['git', 'add', test_file_name])
- patch = scm.create_patch()
- self.assertTrue(re.search(r'\nliteral 0\n', patch))
- self.assertTrue(re.search(r'\nliteral 256\n', patch))
-
- # Check if we can apply the created patch.
- run_command(['git', 'rm', '-f', test_file_name])
- self._setup_webkittools_scripts_symlink(scm)
- self.checkout.apply_patch(self._create_patch(patch))
- self.assertEqual(file_contents, read_from_path(test_file_path, encoding=None))
-
- # Check if we can create a patch from a local commit.
- write_into_file_at_path(test_file_path, file_contents, encoding=None)
- run_command(['git', 'add', test_file_name])
- run_command(['git', 'commit', '-m', 'binary diff'])
- patch_from_local_commit = scm.create_patch('HEAD')
- self.assertTrue(re.search(r'\nliteral 0\n', patch_from_local_commit))
- self.assertTrue(re.search(r'\nliteral 256\n', patch_from_local_commit))
-
- def test_changed_files_local_plus_working_copy(self):
- self._one_local_commit_plus_working_copy_changes()
- scm = detect_scm_system(self.git_checkout_path)
- files = scm.changed_files()
- self.assertTrue('test_file_commit1' in files)
- self.assertTrue('test_file_commit2' in files)
-
- def test_changed_files_git_commit(self):
- self._two_local_commits()
- scm = detect_scm_system(self.git_checkout_path)
- files = scm.changed_files(git_commit="HEAD^")
- self.assertTrue('test_file_commit1' in files)
- self.assertFalse('test_file_commit2' in files)
-
- def test_changed_files_git_commit_range(self):
- self._three_local_commits()
- scm = detect_scm_system(self.git_checkout_path)
- files = scm.changed_files(git_commit="HEAD~2..HEAD")
- self.assertTrue('test_file_commit0' not in files)
- self.assertTrue('test_file_commit1' in files)
- self.assertTrue('test_file_commit2' in files)
-
- def test_changed_files_working_copy_only(self):
- self._one_local_commit_plus_working_copy_changes()
- scm = detect_scm_system(self.git_checkout_path)
- files = scm.changed_files(git_commit="HEAD..")
- self.assertFalse('test_file_commit1' in files)
- self.assertTrue('test_file_commit2' in files)
-
- def test_changed_files_multiple_local_commits(self):
- self._two_local_commits()
- scm = detect_scm_system(self.git_checkout_path)
- files = scm.changed_files()
- self.assertTrue('test_file_commit2' in files)
- self.assertTrue('test_file_commit1' in files)
-
- def test_changed_files_not_synced(self):
- run_command(['git', 'checkout', '-b', 'my-branch', 'trunk~3'])
- self._two_local_commits()
- scm = detect_scm_system(self.git_checkout_path)
- self.assertRaises(ScriptError, scm.changed_files)
-
- def test_changed_files(self):
- self._shared_test_changed_files()
-
- def test_changed_files_for_revision(self):
- self._shared_test_changed_files_for_revision()
-
- def test_contents_at_revision(self):
- self._shared_test_contents_at_revision()
-
- def test_revisions_changing_file(self):
- self._shared_test_revisions_changing_file()
-
- def test_added_files(self):
- self._shared_test_added_files()
-
- def test_committer_email_for_revision(self):
- self._shared_test_committer_email_for_revision()
-
- def test_add_recursively(self):
- self._shared_test_add_recursively()
-
- def test_delete(self):
- self._two_local_commits()
- self.scm.delete('test_file_commit1')
- self.assertTrue("test_file_commit1" in self.scm.deleted_files())
-
- def test_to_object_name(self):
- relpath = 'test_file_commit1'
- fullpath = os.path.join(self.git_checkout_path, relpath)
- self._two_local_commits()
- self.assertEqual(relpath, self.scm.to_object_name(fullpath))
-
- def test_show_head(self):
- self._two_local_commits()
- self.assertEqual("more test content", self.scm.show_head('test_file_commit1'))
-
- def test_show_head_binary(self):
- self._two_local_commits()
- data = "\244"
- write_into_file_at_path("binary_file", data, encoding=None)
- self.scm.add("binary_file")
- self.scm.commit_locally_with_message("a test commit")
- self.assertEqual(data, self.scm.show_head('binary_file'))
-
- def test_diff_for_file(self):
- self._two_local_commits()
- write_into_file_at_path('test_file_commit1', "Updated", encoding=None)
-
- diff = self.scm.diff_for_file('test_file_commit1')
- cached_diff = self.scm.diff_for_file('test_file_commit1')
- self.assertTrue("+Updated" in diff)
- self.assertTrue("-more test content" in diff)
-
- self.scm.add('test_file_commit1')
-
- cached_diff = self.scm.diff_for_file('test_file_commit1')
- self.assertTrue("+Updated" in cached_diff)
- self.assertTrue("-more test content" in cached_diff)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/config/__init__.py b/WebKitTools/Scripts/webkitpy/common/config/__init__.py
deleted file mode 100644
index ef65bee..0000000
--- a/WebKitTools/Scripts/webkitpy/common/config/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Required for Python to search this directory for module files
diff --git a/WebKitTools/Scripts/webkitpy/common/config/build.py b/WebKitTools/Scripts/webkitpy/common/config/build.py
deleted file mode 100644
index c45f122..0000000
--- a/WebKitTools/Scripts/webkitpy/common/config/build.py
+++ /dev/null
@@ -1,138 +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.
-
-"""Functions relating to building WebKit"""
-
-import re
-
-
-def _should_file_trigger_build(target_platform, file):
- # The directories and patterns lists below map directory names or
- # regexp patterns to the bot platforms for which they should trigger a
- # build. Mapping to the empty list means that no builds should be
- # triggered on any platforms. Earlier directories/patterns take
- # precendence over later ones.
-
- # FIXME: The patterns below have only been verified to be correct on
- # Windows. We should implement this for other platforms and start using
- # it for their bots. Someone familiar with each platform will have to
- # figure out what the right set of directories/patterns is for that
- # platform.
- assert(target_platform == "win")
-
- directories = [
- # Directories that shouldn't trigger builds on any bots.
- ("BugsSite", []),
- ("PageLoadTests", []),
- ("PlanetWebKit", []),
- ("WebCore/manual-tests", []),
- ("WebKitExamplePlugins", []),
- ("WebKitSite", []),
- ("android", []),
- ("brew", []),
- ("efl", []),
- ("haiku", []),
- ("iphone", []),
- ("opengl", []),
- ("opentype", []),
- ("openvg", []),
- ("wx", []),
- ("wince", []),
-
- # Directories that should trigger builds on only some bots.
- ("JavaScriptGlue", ["mac"]),
- ("LayoutTests/platform/mac", ["mac", "win"]),
- ("LayoutTests/platform/mac-snowleopard", ["mac-snowleopard", "win"]),
- ("WebCore/image-decoders", ["chromium"]),
- ("cairo", ["gtk", "wincairo"]),
- ("cf", ["chromium-mac", "mac", "qt", "win"]),
- ("chromium", ["chromium"]),
- ("cocoa", ["chromium-mac", "mac"]),
- ("curl", ["gtk", "wincairo"]),
- ("gobject", ["gtk"]),
- ("gpu", ["chromium", "mac"]),
- ("gstreamer", ["gtk"]),
- ("gtk", ["gtk"]),
- ("mac", ["chromium-mac", "mac"]),
- ("mac-leopard", ["mac-leopard"]),
- ("mac-snowleopard", ["mac-snowleopard"]),
- ("mac-wk2", ["mac-snowleopard", "win"]),
- ("objc", ["mac"]),
- ("qt", ["qt"]),
- ("skia", ["chromium"]),
- ("soup", ["gtk"]),
- ("v8", ["chromium"]),
- ("win", ["chromium-win", "win"]),
- ]
- patterns = [
- # Patterns that shouldn't trigger builds on any bots.
- (r"(?:^|/)Makefile$", []),
- (r"/ARM", []),
- (r"/CMake.*", []),
- (r"/ChangeLog.*$", []),
- (r"/LICENSE[^/]+$", []),
- (r"ARM(?:v7)?\.(?:cpp|h)$", []),
- (r"MIPS\.(?:cpp|h)$", []),
- (r"WinCE\.(?:cpp|h|mm)$", []),
- (r"\.(?:bkl|mk)$", []),
-
- # Patterns that should trigger builds on only some bots.
- (r"/GNUmakefile\.am$", ["gtk"]),
- (r"/\w+Chromium\w*\.(?:cpp|h|mm)$", ["chromium"]),
- (r"Mac\.(?:cpp|h|mm)$", ["mac"]),
- (r"\.exp$", ["mac"]),
- (r"\.gypi?", ["chromium"]),
- (r"\.order$", ["mac"]),
- (r"\.pr[io]$", ["qt"]),
- (r"\.xcconfig$", ["mac"]),
- (r"\.xcodeproj/", ["mac"]),
- ]
-
- base_platform = target_platform.split("-")[0]
-
- # See if the file is in one of the known directories.
- for directory, platforms in directories:
- if re.search(r"(?:^|/)%s/" % directory, file):
- return target_platform in platforms or base_platform in platforms
-
- # See if the file matches a known pattern.
- for pattern, platforms in patterns:
- if re.search(pattern, file):
- return target_platform in platforms or base_platform in platforms
-
- # See if the file is a platform-specific test result.
- match = re.match("LayoutTests/platform/(?P<platform>[^/]+)/", file)
- if match:
- # See if the file is a test result for this platform, our base
- # platform, or one of our sub-platforms.
- return match.group("platform") in (target_platform, base_platform) or match.group("platform").startswith("%s-" % target_platform)
-
- # The file isn't one we know about specifically, so we should assume we
- # have to build.
- return True
-
-
-def should_build(target_platform, changed_files):
- """Returns true if the changed files affect the given platform, and
- thus a build should be performed. target_platform should be one of the
- platforms used in the build.webkit.org master's config.json file."""
- return any(_should_file_trigger_build(target_platform, file) for file in changed_files)
diff --git a/WebKitTools/Scripts/webkitpy/common/config/build_unittest.py b/WebKitTools/Scripts/webkitpy/common/config/build_unittest.py
deleted file mode 100644
index 3e70ff0..0000000
--- a/WebKitTools/Scripts/webkitpy/common/config/build_unittest.py
+++ /dev/null
@@ -1,64 +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 unittest
-
-from webkitpy.common.config import build
-
-
-class ShouldBuildTest(unittest.TestCase):
- _should_build_tests = [
- (["BugsSite/foo", "WebCore/bar"], ["*"]),
- (["BugsSite/foo"], []),
- (["JavaScriptCore/JavaScriptCore.xcodeproj/foo"], ["mac-leopard", "mac-snowleopard"]),
- (["JavaScriptGlue/foo", "WebCore/bar"], ["*"]),
- (["JavaScriptGlue/foo"], ["mac-leopard", "mac-snowleopard"]),
- (["LayoutTests/foo"], ["*"]),
- (["LayoutTests/platform/chromium-linux/foo"], ["chromium-linux"]),
- (["LayoutTests/platform/chromium-win/fast/compact/001-expected.txt"], ["chromium-win"]),
- (["LayoutTests/platform/mac-leopard/foo"], ["mac-leopard"]),
- (["LayoutTests/platform/mac-snowleopard/foo"], ["mac-snowleopard", "win"]),
- (["LayoutTests/platform/mac-wk2/Skipped"], ["mac-snowleopard", "win"]),
- (["LayoutTests/platform/mac/foo"], ["mac-leopard", "mac-snowleopard", "win"]),
- (["LayoutTests/platform/win-xp/foo"], ["win"]),
- (["LayoutTests/platform/win-wk2/foo"], ["win"]),
- (["LayoutTests/platform/win/foo"], ["win"]),
- (["WebCore/mac/foo"], ["chromium-mac", "mac-leopard", "mac-snowleopard"]),
- (["WebCore/win/foo"], ["chromium-win", "win"]),
- (["WebCore/platform/graphics/gpu/foo"], ["mac-leopard", "mac-snowleopard"]),
- (["WebCore/platform/wx/wxcode/win/foo"], []),
- (["WebCore/rendering/RenderThemeMac.mm", "WebCore/rendering/RenderThemeMac.h"], ["mac-leopard", "mac-snowleopard"]),
- (["WebCore/rendering/RenderThemeChromiumLinux.h"], ["chromium-linux"]),
- (["WebCore/rendering/RenderThemeWinCE.h"], []),
- ]
-
- def test_should_build(self):
- for files, platforms in self._should_build_tests:
- # FIXME: We should test more platforms here once
- # build._should_file_trigger_build is implemented for them.
- for platform in ["win"]:
- should_build = platform in platforms or "*" in platforms
- self.assertEqual(build.should_build(platform, files), should_build, "%s should%s have built but did%s (files: %s)" % (platform, "" if should_build else "n't", "n't" if should_build else "", str(files)))
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/config/committers.py b/WebKitTools/Scripts/webkitpy/common/config/committers.py
deleted file mode 100644
index b451721..0000000
--- a/WebKitTools/Scripts/webkitpy/common/config/committers.py
+++ /dev/null
@@ -1,331 +0,0 @@
-# Copyright (c) 2009, 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# WebKit's Python module for committer and reviewer validation
-
-
-class Committer:
-
- def __init__(self, name, email_or_emails, irc_nickname=None):
- self.full_name = name
- if isinstance(email_or_emails, str):
- self.emails = [email_or_emails]
- else:
- self.emails = email_or_emails
- self.irc_nickname = irc_nickname
- self.can_review = False
-
- def bugzilla_email(self):
- # FIXME: We're assuming the first email is a valid bugzilla email,
- # which might not be right.
- return self.emails[0]
-
- def __str__(self):
- return '"%s" <%s>' % (self.full_name, self.emails[0])
-
-
-class Reviewer(Committer):
-
- def __init__(self, name, email_or_emails, irc_nickname=None):
- Committer.__init__(self, name, email_or_emails, irc_nickname)
- self.can_review = True
-
-
-# This is intended as a canonical, machine-readable list of all non-reviewer
-# committers for WebKit. If your name is missing here and you are a committer,
-# please add it. No review needed. All reviewers are committers, so this list
-# is only of committers who are not reviewers.
-
-
-committers_unable_to_review = [
- Committer("Aaron Boodman", "aa@chromium.org", "aboodman"),
- Committer("Abhishek Arya", "inferno@chromium.org", "inferno-sec"),
- Committer("Adam Langley", "agl@chromium.org", "agl"),
- Committer("Albert J. Wong", "ajwong@chromium.org"),
- Committer("Alejandro G. Castro", ["alex@igalia.com", "alex@webkit.org"]),
- Committer("Alexander Kellett", ["lypanov@mac.com", "a-lists001@lypanov.net", "lypanov@kde.org"], "lypanov"),
- Committer("Alexander Pavlov", "apavlov@chromium.org", "apavlov"),
- Committer("Andre Boule", "aboule@apple.com"),
- Committer("Andrei Popescu", "andreip@google.com", "andreip"),
- Committer("Andrew Wellington", ["andrew@webkit.org", "proton@wiretapped.net"], "proton"),
- Committer("Andrey Kosyakov", "caseq@chromium.org", "caseq"),
- Committer("Andras Becsi", ["abecsi@webkit.org", "abecsi@inf.u-szeged.hu"], "bbandix"),
- Committer("Andy Estes", "aestes@apple.com", "estes"),
- Committer("Anthony Ricaud", "rik@webkit.org", "rik"),
- Committer("Anton Muhin", "antonm@chromium.org", "antonm"),
- Committer("Balazs Kelemen", "kbalazs@webkit.org", "kbalazs"),
- Committer("Ben Murdoch", "benm@google.com", "benm"),
- Committer("Benjamin C Meyer", ["ben@meyerhome.net", "ben@webkit.org"], "icefox"),
- Committer("Benjamin Otte", ["otte@gnome.org", "otte@webkit.org"], "otte"),
- Committer("Benjamin Poulain", ["benjamin.poulain@nokia.com", "ikipou@gmail.com"]),
- Committer("Brent Fulgham", "bfulgham@webkit.org", "bfulgham"),
- Committer("Brett Wilson", "brettw@chromium.org", "brettx"),
- Committer("Brian Weinstein", "bweinstein@apple.com", "bweinstein"),
- Committer("Cameron McCormack", "cam@webkit.org", "heycam"),
- Committer("Carol Szabo", "carol.szabo@nokia.com"),
- Committer("Chang Shu", "Chang.Shu@nokia.com"),
- Committer("Chris Evans", "cevans@google.com"),
- Committer("Chris Petersen", "cpetersen@apple.com", "cpetersen"),
- Committer("Chris Rogers", "crogers@google.com", "crogers"),
- Committer("Christian Dywan", ["christian@twotoasts.de", "christian@webkit.org"]),
- Committer("Collin Jackson", "collinj@webkit.org"),
- Committer("David Smith", ["catfish.man@gmail.com", "dsmith@webkit.org"], "catfishman"),
- Committer("Dean Jackson", "dino@apple.com", "dino"),
- Committer("Diego Gonzalez", ["diegohcg@webkit.org", "diego.gonzalez@openbossa.org"], "diegohcg"),
- Committer("Dirk Pranke", "dpranke@chromium.org"),
- Committer("Drew Wilson", "atwilson@chromium.org", "atwilson"),
- Committer("Eli Fidler", "eli@staikos.net", "QBin"),
- Committer("Enrica Casucci", "enrica@apple.com"),
- Committer("Erik Arvidsson", "arv@chromium.org", "arv"),
- Committer("Eric Roman", "eroman@chromium.org", "eroman"),
- Committer("Evan Martin", "evan@chromium.org", "evmar"),
- Committer("Evan Stade", "estade@chromium.org", "estade"),
- Committer("Fady Samuel", "fsamuel@chromium.org", "fsamuel"),
- Committer("Feng Qian", "feng@chromium.org"),
- Committer("Fumitoshi Ukai", "ukai@chromium.org", "ukai"),
- Committer("Gabor Loki", "loki@webkit.org", "loki04"),
- Committer("Girish Ramakrishnan", ["girish@forwardbias.in", "ramakrishnan.girish@gmail.com"]),
- Committer("Graham Dennis", ["Graham.Dennis@gmail.com", "gdennis@webkit.org"]),
- Committer("Greg Bolsinga", "bolsinga@apple.com"),
- Committer("Gyuyoung Kim", ["gyuyoung.kim@samsung.com", "gyuyoung@gmail.com", "gyuyoung@webkit.org"], "gyuyoung"),
- Committer("Hans Wennborg", "hans@chromium.org", "hwennborg"),
- Committer("Hayato Ito", "hayato@chromium.org", "hayato"),
- Committer("Hin-Chung Lam", ["hclam@google.com", "hclam@chromium.org"]),
- Committer("Ilya Tikhonovsky", "loislo@chromium.org", "loislo"),
- 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("Jay Civelli", "jcivelli@chromium.org", "jcivelli"),
- Committer("Jens Alfke", ["snej@chromium.org", "jens@apple.com"]),
- Committer("Jer Noble", "jer.noble@apple.com", "jernoble"),
- Committer("Jeremy Moskovich", ["playmobil@google.com", "jeremy@chromium.org"], "jeremymos"),
- Committer("Jessie Berlin", ["jberlin@webkit.org", "jberlin@apple.com"]),
- Committer("Jesus Sanchez-Palencia", ["jesus@webkit.org", "jesus.palencia@openbossa.org"], "jeez_"),
- Committer("Jocelyn Turcotte", "jocelyn.turcotte@nokia.com", "jturcotte"),
- Committer("Jochen Eisinger", "jochen@chromium.org", "jochen__"),
- Committer("John Abd-El-Malek", "jam@chromium.org", "jam"),
- Committer("John Gregg", ["johnnyg@google.com", "johnnyg@chromium.org"], "johnnyg"),
- Committer("Joost de Valk", ["joost@webkit.org", "webkit-dev@joostdevalk.nl"], "Altha"),
- Committer("Julie Parent", ["jparent@google.com", "jparent@chromium.org"], "jparent"),
- Committer("Julien Chaffraix", ["jchaffraix@webkit.org", "julien.chaffraix@gmail.com"]),
- Committer("Jungshik Shin", "jshin@chromium.org"),
- Committer("Justin Schuh", "jschuh@chromium.org", "jschuh"),
- Committer("Keishi Hattori", "keishi@webkit.org", "keishi"),
- Committer("Kelly Norton", "knorton@google.com"),
- Committer("Kent Hansen", "kent.hansen@nokia.com", "khansen"),
- Committer("Kimmo Kinnunen", ["kimmo.t.kinnunen@nokia.com", "kimmok@iki.fi", "ktkinnun@webkit.org"], "kimmok"),
- Committer("Kinuko Yasuda", "kinuko@chromium.org", "kinuko"),
- Committer("Krzysztof Kowalczyk", "kkowalczyk@gmail.com"),
- Committer("Kwang Yul Seo", ["kwangyul.seo@gmail.com", "skyul@company100.net", "kseo@webkit.org"], "kwangseo"),
- Committer("Leandro Pereira", ["leandro@profusion.mobi", "leandro@webkit.org"], "acidx"),
- Committer("Levi Weintraub", "lweintraub@apple.com"),
- Committer("Lucas De Marchi", ["lucas.demarchi@profusion.mobi", "demarchi@webkit.org"], "demarchi"),
- Committer("Luiz Agostini", ["luiz@webkit.org", "luiz.agostini@openbossa.org"], "lca"),
- Committer("Mads Ager", "ager@chromium.org"),
- Committer("Marcus Voltis Bulach", "bulach@chromium.org"),
- Committer("Mario Sanchez Prada", ["msanchez@igalia.com", "mario@webkit.org"], "msanchez"),
- Committer("Matt Delaney", "mdelaney@apple.com"),
- Committer("Matt Lilek", ["webkit@mattlilek.com", "pewtermoose@webkit.org"]),
- Committer("Matt Perry", "mpcomplete@chromium.org"),
- Committer("Maxime Britto", ["maxime.britto@gmail.com", "britto@apple.com"]),
- Committer("Maxime Simon", ["simon.maxime@gmail.com", "maxime.simon@webkit.org"], "maxime.simon"),
- Committer("Michael Nordman", "michaeln@google.com", "michaeln"),
- Committer("Michael Saboff", "msaboff@apple.com"),
- Committer("Michelangelo De Simone", "michelangelo@webkit.org", "michelangelo"),
- Committer("Mihai Parparita", "mihaip@chromium.org", "mihaip"),
- Committer("Mike Belshe", ["mbelshe@chromium.org", "mike@belshe.com"]),
- Committer("Mike Fenton", ["mifenton@rim.com", "mike.fenton@torchmobile.com"], "mfenton"),
- Committer("Mike Thole", ["mthole@mikethole.com", "mthole@apple.com"]),
- Committer("Mikhail Naganov", "mnaganov@chromium.org"),
- Committer("MORITA Hajime", "morrita@google.com", "morrita"),
- Committer("Nico Weber", ["thakis@chromium.org", "thakis@google.com"], "thakis"),
- Committer("Noam Rosenthal", "noam.rosenthal@nokia.com", "noamr"),
- Committer("Pam Greene", "pam@chromium.org", "pamg"),
- Committer("Patrick Gansterer", ["paroga@paroga.com", "paroga@webkit.org"], "paroga"),
- Committer("Pavel Podivilov", "podivilov@chromium.org", "podivilov"),
- Committer("Peter Kasting", ["pkasting@google.com", "pkasting@chromium.org"], "pkasting"),
- Committer("Philippe Normand", ["pnormand@igalia.com", "philn@webkit.org"], "philn-tp"),
- Committer("Pierre d'Herbemont", ["pdherbemont@free.fr", "pdherbemont@apple.com"], "pdherbemont"),
- Committer("Pierre-Olivier Latour", "pol@apple.com", "pol"),
- Committer("Renata Hodovan", "reni@webkit.org", "reni"),
- Committer("Robert Hogan", ["robert@webkit.org", "robert@roberthogan.net", "lists@roberthogan.net"], "mwenge"),
- Committer("Roland Steiner", "rolandsteiner@chromium.org"),
- Committer("Ryosuke Niwa", "rniwa@webkit.org", "rniwa"),
- Committer("Satish Sampath", "satish@chromium.org"),
- Committer("Scott Violet", "sky@chromium.org", "sky"),
- Committer("Stephen White", "senorblanco@chromium.org", "senorblanco"),
- Committer("Tony Gentilcore", "tonyg@chromium.org", "tonyg-cr"),
- Committer("Trey Matteson", "trey@usa.net", "trey"),
- Committer("Tristan O'Tierney", ["tristan@otierney.net", "tristan@apple.com"]),
- Committer("Vangelis Kokkevis", "vangelis@chromium.org", "vangelis"),
- Committer("Victor Wang", "victorw@chromium.org", "victorw"),
- Committer("Vitaly Repeshko", "vitalyr@chromium.org"),
- Committer("William Siegrist", "wsiegrist@apple.com", "wms"),
- Committer("Xiaomei Ji", "xji@chromium.org", "xji"),
- Committer("Yael Aharon", "yael.aharon@nokia.com"),
- 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"),
- Committer("Yuta Kitamura", "yutak@chromium.org", "yutak"),
- Committer("Yuzo Fujishima", "yuzo@google.com", "yuzo"),
- Committer("Zhenyao Mo", "zmo@google.com", "zhenyao"),
- Committer("Zoltan Herczeg", "zherczeg@webkit.org", "zherczeg"),
- Committer("Zoltan Horvath", ["zoltan@webkit.org", "hzoltan@inf.u-szeged.hu", "horvath.zoltan.6@stud.u-szeged.hu"], "zoltan"),
-]
-
-
-# This is intended as a canonical, machine-readable list of all reviewers for
-# WebKit. If your name is missing here and you are a reviewer, please add it.
-# No review needed.
-
-
-reviewers_list = [
- Reviewer("Ada Chan", "adachan@apple.com", "chanada"),
- Reviewer("Adam Barth", "abarth@webkit.org", "abarth"),
- Reviewer("Adam Roben", "aroben@apple.com", "aroben"),
- Reviewer("Adam Treat", ["treat@kde.org", "treat@webkit.org", "atreat@rim.com"], "manyoso"),
- Reviewer("Adele Peterson", "adele@apple.com", "adele"),
- Reviewer("Alexey Proskuryakov", ["ap@webkit.org", "ap@apple.com"], "ap"),
- Reviewer("Alice Liu", "alice.liu@apple.com", "aliu"),
- Reviewer("Alp Toker", ["alp@nuanti.com", "alp@atoker.com", "alp@webkit.org"], "alp"),
- Reviewer("Anders Carlsson", ["andersca@apple.com", "acarlsson@apple.com"], "andersca"),
- Reviewer("Andreas Kling", ["kling@webkit.org", "andreas.kling@nokia.com"], "kling"),
- Reviewer("Antonio Gomes", ["tonikitoo@webkit.org", "agomes@rim.com"], "tonikitoo"),
- Reviewer("Antti Koivisto", ["koivisto@iki.fi", "antti@apple.com", "antti.j.koivisto@nokia.com"], "anttik"),
- Reviewer("Ariya Hidayat", ["ariya.hidayat@gmail.com", "ariya@sencha.com", "ariya@webkit.org"], "ariya"),
- Reviewer("Beth Dakin", "bdakin@apple.com", "dethbakin"),
- Reviewer("Brady Eidson", "beidson@apple.com", "bradee-oh"),
- Reviewer("Cameron Zwarich", ["zwarich@apple.com", "cwzwarich@apple.com", "cwzwarich@webkit.org"]),
- Reviewer("Chris Blumenberg", "cblu@apple.com", "cblu"),
- Reviewer("Chris Marrin", "cmarrin@apple.com", "cmarrin"),
- Reviewer("Chris Fleizach", "cfleizach@apple.com", "cfleizach"),
- Reviewer("Chris Jerdonek", "cjerdonek@webkit.org", "cjerdonek"),
- Reviewer(u"Csaba Osztrogon\u00e1c", "ossy@webkit.org", "ossy"),
- Reviewer("Dan Bernstein", ["mitz@webkit.org", "mitz@apple.com"], "mitzpettel"),
- Reviewer("Daniel Bates", "dbates@webkit.org", "dydz"),
- Reviewer("Darin Adler", "darin@apple.com", "darin"),
- Reviewer("Darin Fisher", ["fishd@chromium.org", "darin@chromium.org"], "fishd"),
- Reviewer("David Harrison", "harrison@apple.com", "harrison"),
- Reviewer("David Hyatt", "hyatt@apple.com", "hyatt"),
- Reviewer("David Kilzer", ["ddkilzer@webkit.org", "ddkilzer@apple.com"], "ddkilzer"),
- Reviewer("David Levin", "levin@chromium.org", "dave_levin"),
- Reviewer("Dimitri Glazkov", "dglazkov@chromium.org", "dglazkov"),
- Reviewer("Dirk Schulze", "krit@webkit.org", "krit"),
- Reviewer("Dmitry Titov", "dimich@chromium.org", "dimich"),
- Reviewer("Don Melton", "gramps@apple.com", "gramps"),
- Reviewer("Dumitru Daniliuc", "dumi@chromium.org", "dumi"),
- Reviewer("Eric Carlson", "eric.carlson@apple.com"),
- Reviewer("Eric Seidel", "eric@webkit.org", "eseidel"),
- Reviewer("Gavin Barraclough", "barraclough@apple.com", "gbarra"),
- Reviewer("Geoffrey Garen", "ggaren@apple.com", "ggaren"),
- Reviewer("George Staikos", ["staikos@kde.org", "staikos@webkit.org"]),
- Reviewer("Gustavo Noronha Silva", ["gns@gnome.org", "kov@webkit.org", "gustavo.noronha@collabora.co.uk"], "kov"),
- Reviewer("Holger Freyther", ["zecke@selfish.org", "zecke@webkit.org"], "zecke"),
- Reviewer("James Robinson", ["jamesr@chromium.org", "jamesr@google.com"], "jamesr"),
- Reviewer("Jan Alonzo", ["jmalonzo@gmail.com", "jmalonzo@webkit.org"], "janm"),
- Reviewer("Jeremy Orlow", "jorlow@chromium.org", "jorlow"),
- Reviewer("Jian Li", "jianli@chromium.org", "jianli"),
- Reviewer("John Sullivan", "sullivan@apple.com", "sullivan"),
- Reviewer("Jon Honeycutt", "jhoneycutt@apple.com", "jhoneycutt"),
- Reviewer("Joseph Pecoraro", ["joepeck@webkit.org", "pecoraro@apple.com"], "JoePeck"),
- Reviewer("Justin Garcia", "justin.garcia@apple.com", "justing"),
- Reviewer("Ken Kocienda", "kocienda@apple.com"),
- Reviewer("Kenneth Rohde Christiansen", ["kenneth@webkit.org", "kenneth.christiansen@openbossa.org", "kenneth.christiansen@gmail.com"], "kenne"),
- Reviewer("Kenneth Russell", "kbr@google.com", "kbr_google"),
- Reviewer("Kent Tamura", "tkent@chromium.org", "tkent"),
- Reviewer("Kevin Decker", "kdecker@apple.com", "superkevin"),
- Reviewer("Kevin McCullough", "kmccullough@apple.com", "maculloch"),
- Reviewer("Kevin Ollivier", ["kevino@theolliviers.com", "kevino@webkit.org"], "kollivier"),
- Reviewer("Lars Knoll", ["lars@trolltech.com", "lars@kde.org", "lars.knoll@nokia.com"], "lars"),
- Reviewer("Laszlo Gombos", "laszlo.1.gombos@nokia.com", "lgombos"),
- Reviewer("Maciej Stachowiak", "mjs@apple.com", "othermaciej"),
- Reviewer("Mark Rowe", "mrowe@apple.com", "bdash"),
- Reviewer("Martin Robinson", ["mrobinson@webkit.org", "mrobinson@igalia.com", "martin.james.robinson@gmail.com"], "mrobinson"),
- Reviewer("Nate Chapin", "japhet@chromium.org", "japhet"),
- Reviewer("Nikolas Zimmermann", ["zimmermann@kde.org", "zimmermann@physik.rwth-aachen.de", "zimmermann@webkit.org"], "wildfox"),
- Reviewer("Ojan Vafai", "ojan@chromium.org", "ojan"),
- Reviewer("Oliver Hunt", "oliver@apple.com", "olliej"),
- Reviewer("Pavel Feldman", "pfeldman@chromium.org", "pfeldman"),
- Reviewer("Richard Williamson", "rjw@apple.com", "rjw"),
- Reviewer("Rob Buis", ["rwlbuis@gmail.com", "rwlbuis@webkit.org"], "rwlbuis"),
- Reviewer("Sam Weinig", ["sam@webkit.org", "weinig@apple.com"], "weinig"),
- Reviewer("Shinichiro Hamaji", "hamaji@chromium.org", "hamaji"),
- Reviewer("Simon Fraser", "simon.fraser@apple.com", "smfr"),
- Reviewer("Simon Hausmann", ["hausmann@webkit.org", "hausmann@kde.org", "simon.hausmann@nokia.com"], "tronical"),
- Reviewer("Stephanie Lewis", "slewis@apple.com", "sundiamonde"),
- Reviewer("Steve Block", "steveblock@google.com", "steveblock"),
- Reviewer("Steve Falkenburg", "sfalken@apple.com", "sfalken"),
- Reviewer("Tim Omernick", "timo@apple.com"),
- Reviewer("Timothy Hatcher", ["timothy@apple.com", "timothy@hatcher.name"], "xenon"),
- Reviewer("Tony Chang", "tony@chromium.org", "tony^work"),
- Reviewer(u"Tor Arne Vestb\u00f8", ["vestbo@webkit.org", "tor.arne.vestbo@nokia.com"], "torarne"),
- Reviewer("Vicki Murley", "vicki@apple.com"),
- Reviewer("Xan Lopez", ["xan.lopez@gmail.com", "xan@gnome.org", "xan@webkit.org"], "xan"),
- Reviewer("Yury Semikhatsky", "yurys@chromium.org", "yurys"),
- Reviewer("Zack Rusin", "zack@kde.org", "zackr"),
-]
-
-
-class CommitterList:
-
- # Committers and reviewers are passed in to allow easy testing
-
- def __init__(self,
- committers=committers_unable_to_review,
- reviewers=reviewers_list):
- self._committers = committers + reviewers
- self._reviewers = reviewers
- self._committers_by_email = {}
-
- def committers(self):
- return self._committers
-
- def reviewers(self):
- return self._reviewers
-
- def _email_to_committer_map(self):
- if not len(self._committers_by_email):
- for committer in self._committers:
- for email in committer.emails:
- self._committers_by_email[email] = committer
- return self._committers_by_email
-
- def committer_by_name(self, name):
- # This could be made into a hash lookup if callers need it to be fast.
- for committer in self.committers():
- if committer.full_name == name:
- return committer
-
- def committer_by_email(self, email):
- return self._email_to_committer_map().get(email)
-
- def reviewer_by_email(self, email):
- committer = self.committer_by_email(email)
- if committer and not committer.can_review:
- return None
- return committer
diff --git a/WebKitTools/Scripts/webkitpy/common/config/committers_unittest.py b/WebKitTools/Scripts/webkitpy/common/config/committers_unittest.py
deleted file mode 100644
index 068c0ee..0000000
--- a/WebKitTools/Scripts/webkitpy/common/config/committers_unittest.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright (C) 2009 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-from webkitpy.common.config.committers import CommitterList, Committer, Reviewer
-
-class CommittersTest(unittest.TestCase):
-
- def test_committer_lookup(self):
- committer = Committer('Test One', 'one@test.com', 'one')
- reviewer = Reviewer('Test Two', ['two@test.com', 'two@rad.com', 'so_two@gmail.com'])
- committer_list = CommitterList(committers=[committer], reviewers=[reviewer])
-
- # Test valid committer and reviewer lookup
- self.assertEqual(committer_list.committer_by_email('one@test.com'), committer)
- self.assertEqual(committer_list.reviewer_by_email('two@test.com'), reviewer)
- self.assertEqual(committer_list.committer_by_email('two@test.com'), reviewer)
- self.assertEqual(committer_list.committer_by_email('two@rad.com'), reviewer)
- self.assertEqual(committer_list.reviewer_by_email('so_two@gmail.com'), reviewer)
-
- # Test valid committer and reviewer lookup
- self.assertEqual(committer_list.committer_by_name("Test One"), committer)
- self.assertEqual(committer_list.committer_by_name("Test Two"), reviewer)
- self.assertEqual(committer_list.committer_by_name("Test Three"), None)
-
- # Test that the first email is assumed to be the Bugzilla email address (for now)
- self.assertEqual(committer_list.committer_by_email('two@rad.com').bugzilla_email(), 'two@test.com')
-
- # Test that a known committer is not returned during reviewer lookup
- self.assertEqual(committer_list.reviewer_by_email('one@test.com'), None)
-
- # Test that unknown email address fail both committer and reviewer lookup
- self.assertEqual(committer_list.committer_by_email('bar@bar.com'), None)
- self.assertEqual(committer_list.reviewer_by_email('bar@bar.com'), None)
-
- # Test that emails returns a list.
- self.assertEqual(committer.emails, ['one@test.com'])
-
- self.assertEqual(committer.irc_nickname, 'one')
-
- # Test that committers returns committers and reviewers and reviewers() just reviewers.
- self.assertEqual(committer_list.committers(), [committer, reviewer])
- self.assertEqual(committer_list.reviewers(), [reviewer])
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/config/committervalidator.py b/WebKitTools/Scripts/webkitpy/common/config/committervalidator.py
deleted file mode 100644
index b7b2990..0000000
--- a/WebKitTools/Scripts/webkitpy/common/config/committervalidator.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# Copyright (c) 2009 Google Inc. All rights reserved.
-# Copyright (c) 2009 Apple Inc. All rights reserved.
-# Copyright (c) 2010 Research In Motion Limited. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import os
-
-from webkitpy.common.system.ospath import relpath
-from webkitpy.common.config import committers
-
-
-class CommitterValidator(object):
-
- def __init__(self, bugzilla):
- self._bugzilla = bugzilla
-
- # _view_source_url belongs in some sort of webkit_config.py module.
- def _view_source_url(self, local_path):
- return "http://trac.webkit.org/browser/trunk/%s" % local_path
-
- def _checkout_root(self):
- # FIXME: This is a hack, we would have this from scm.checkout_root
- # if we had any way to get to an scm object here.
- components = __file__.split(os.sep)
- tools_index = components.index("WebKitTools")
- return os.sep.join(components[:tools_index])
-
- def _committers_py_path(self):
- # extension can sometimes be .pyc, we always want .py
- (path, extension) = os.path.splitext(committers.__file__)
- # FIXME: When we're allowed to use python 2.6 we can use the real
- # os.path.relpath
- path = relpath(path, self._checkout_root())
- return ".".join([path, "py"])
-
- def _flag_permission_rejection_message(self, setter_email, flag_name):
- # Should come from some webkit_config.py
- contribution_guidlines = "http://webkit.org/coding/contributing.html"
- # This could be queried from the status_server.
- queue_administrator = "eseidel@chromium.org"
- # This could be queried from the tool.
- queue_name = "commit-queue"
- committers_list = self._committers_py_path()
- message = "%s does not have %s permissions according to %s." % (
- setter_email,
- flag_name,
- self._view_source_url(committers_list))
- message += "\n\n- If you do not have %s rights please read %s for instructions on how to use bugzilla flags." % (
- flag_name, contribution_guidlines)
- message += "\n\n- If you have %s rights please correct the error in %s by adding yourself to the file (no review needed). " % (
- flag_name, committers_list)
- message += "The %s restarts itself every 2 hours. After restart the %s will correctly respect your %s rights." % (
- queue_name, queue_name, flag_name)
- return message
-
- def _validate_setter_email(self, patch, result_key, rejection_function):
- committer = getattr(patch, result_key)()
- # If the flag is set, and we don't recognize the setter, reject the
- # flag!
- setter_email = patch._attachment_dictionary.get("%s_email" % result_key)
- if setter_email and not committer:
- rejection_function(patch.id(),
- self._flag_permission_rejection_message(setter_email,
- result_key))
- return False
- return True
-
- def _reject_patch_if_flags_are_invalid(self, patch):
- return (self._validate_setter_email(
- patch, "reviewer", self.reject_patch_from_review_queue)
- and self._validate_setter_email(
- patch, "committer", self.reject_patch_from_commit_queue))
-
- def patches_after_rejecting_invalid_commiters_and_reviewers(self, patches):
- return [patch for patch in patches if self._reject_patch_if_flags_are_invalid(patch)]
-
- def reject_patch_from_commit_queue(self,
- attachment_id,
- additional_comment_text=None):
- comment_text = "Rejecting patch %s from commit-queue." % attachment_id
- self._bugzilla.set_flag_on_attachment(attachment_id,
- "commit-queue",
- "-",
- comment_text,
- additional_comment_text)
-
- def reject_patch_from_review_queue(self,
- attachment_id,
- additional_comment_text=None):
- comment_text = "Rejecting patch %s from review queue." % attachment_id
- self._bugzilla.set_flag_on_attachment(attachment_id,
- 'review',
- '-',
- comment_text,
- additional_comment_text)
diff --git a/WebKitTools/Scripts/webkitpy/common/config/committervalidator_unittest.py b/WebKitTools/Scripts/webkitpy/common/config/committervalidator_unittest.py
deleted file mode 100644
index 61fa3bf..0000000
--- a/WebKitTools/Scripts/webkitpy/common/config/committervalidator_unittest.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from .committervalidator import CommitterValidator
-
-
-class CommitterValidatorTest(unittest.TestCase):
- def test_flag_permission_rejection_message(self):
- validator = CommitterValidator(bugzilla=None)
- self.assertEqual(validator._committers_py_path(), "WebKitTools/Scripts/webkitpy/common/config/committers.py")
- expected_messsage = """foo@foo.com does not have review permissions according to http://trac.webkit.org/browser/trunk/WebKitTools/Scripts/webkitpy/common/config/committers.py.
-
-- If you do not have review rights please read http://webkit.org/coding/contributing.html for instructions on how to use bugzilla flags.
-
-- If you have review rights please correct the error in WebKitTools/Scripts/webkitpy/common/config/committers.py by adding yourself to the file (no review needed). The commit-queue restarts itself every 2 hours. After restart the commit-queue will correctly respect your review rights."""
- self.assertEqual(validator._flag_permission_rejection_message("foo@foo.com", "review"), expected_messsage)
diff --git a/WebKitTools/Scripts/webkitpy/common/config/irc.py b/WebKitTools/Scripts/webkitpy/common/config/irc.py
deleted file mode 100644
index 950c573..0000000
--- a/WebKitTools/Scripts/webkitpy/common/config/irc.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (c) 2009 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-server="irc.freenode.net"
-port=6667
-channel="#webkit"
diff --git a/WebKitTools/Scripts/webkitpy/common/config/ports.py b/WebKitTools/Scripts/webkitpy/common/config/ports.py
deleted file mode 100644
index d268865..0000000
--- a/WebKitTools/Scripts/webkitpy/common/config/ports.py
+++ /dev/null
@@ -1,249 +0,0 @@
-# Copyright (C) 2009, 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# WebKit's Python module for understanding the various ports
-
-import os
-import platform
-
-from webkitpy.common.system.executive import Executive
-
-
-class WebKitPort(object):
-
- # We might need to pass scm into this function for scm.checkout_root
- @classmethod
- def script_path(cls, script_name):
- return os.path.join("WebKitTools", "Scripts", script_name)
-
- @staticmethod
- def port(port_name):
- ports = {
- "chromium": ChromiumPort,
- "chromium-xvfb": ChromiumXVFBPort,
- "gtk": GtkPort,
- "mac": MacPort,
- "win": WinPort,
- "qt": QtPort,
- "efl": EflPort,
- }
- default_port = {
- "Windows": WinPort,
- "Darwin": MacPort,
- }
- # Do we really need MacPort as the ultimate default?
- return ports.get(port_name, default_port.get(platform.system(), MacPort))
-
- @staticmethod
- def makeArgs():
- args = '--makeargs="-j%s"' % Executive().cpu_count()
- if os.environ.has_key('MAKEFLAGS'):
- args = '--makeargs="%s"' % os.environ['MAKEFLAGS']
- return args
-
- @classmethod
- def name(cls):
- raise NotImplementedError("subclasses must implement")
-
- @classmethod
- def flag(cls):
- raise NotImplementedError("subclasses must implement")
-
- @classmethod
- def update_webkit_command(cls):
- return [cls.script_path("update-webkit")]
-
- @classmethod
- def build_webkit_command(cls, build_style=None):
- command = [cls.script_path("build-webkit")]
- if build_style == "debug":
- command.append("--debug")
- if build_style == "release":
- command.append("--release")
- return command
-
- @classmethod
- def run_javascriptcore_tests_command(cls):
- return [cls.script_path("run-javascriptcore-tests")]
-
- @classmethod
- def run_webkit_tests_command(cls):
- return [cls.script_path("run-webkit-tests")]
-
- @classmethod
- def run_python_unittests_command(cls):
- return [cls.script_path("test-webkitpy")]
-
- @classmethod
- def run_perl_unittests_command(cls):
- return [cls.script_path("test-webkitperl")]
-
- @classmethod
- def layout_tests_results_path(cls):
- return "/tmp/layout-test-results/results.html"
-
-
-class MacPort(WebKitPort):
-
- @classmethod
- def name(cls):
- return "Mac"
-
- @classmethod
- def flag(cls):
- return "--port=mac"
-
- @classmethod
- def _system_version(cls):
- version_string = platform.mac_ver()[0] # e.g. "10.5.6"
- version_tuple = version_string.split('.')
- return map(int, version_tuple)
-
- @classmethod
- def is_leopard(cls):
- return tuple(cls._system_version()[:2]) == (10, 5)
-
-
-class WinPort(WebKitPort):
-
- @classmethod
- def name(cls):
- return "Win"
-
- @classmethod
- def flag(cls):
- # FIXME: This is lame. We should autogenerate this from a codename or something.
- return "--port=win"
-
-
-class GtkPort(WebKitPort):
-
- @classmethod
- def name(cls):
- return "Gtk"
-
- @classmethod
- def flag(cls):
- return "--port=gtk"
-
- @classmethod
- def build_webkit_command(cls, build_style=None):
- command = WebKitPort.build_webkit_command(build_style=build_style)
- command.append("--gtk")
- command.append(WebKitPort.makeArgs())
- return command
-
- @classmethod
- def run_webkit_tests_command(cls):
- command = WebKitPort.run_webkit_tests_command()
- command.append("--gtk")
- return command
-
-
-class QtPort(WebKitPort):
-
- @classmethod
- def name(cls):
- return "Qt"
-
- @classmethod
- def flag(cls):
- return "--port=qt"
-
- @classmethod
- def build_webkit_command(cls, build_style=None):
- command = WebKitPort.build_webkit_command(build_style=build_style)
- command.append("--qt")
- command.append(WebKitPort.makeArgs())
- return command
-
-
-class EflPort(WebKitPort):
-
- @classmethod
- def name(cls):
- return "Efl"
-
- @classmethod
- def flag(cls):
- return "--port=efl"
-
- @classmethod
- def build_webkit_command(cls, build_style=None):
- command = WebKitPort.build_webkit_command(build_style=build_style)
- command.append("--efl")
- command.append(WebKitPort.makeArgs())
- return command
-
-
-class ChromiumPort(WebKitPort):
-
- @classmethod
- def name(cls):
- return "Chromium"
-
- @classmethod
- def flag(cls):
- return "--port=chromium"
-
- @classmethod
- def update_webkit_command(cls):
- command = WebKitPort.update_webkit_command()
- command.append("--chromium")
- return command
-
- @classmethod
- def build_webkit_command(cls, build_style=None):
- command = WebKitPort.build_webkit_command(build_style=build_style)
- command.append("--chromium")
- return command
-
- @classmethod
- def run_webkit_tests_command(cls):
- return [
- cls.script_path("new-run-webkit-tests"),
- "--chromium",
- "--use-drt",
- "--no-pixel-tests",
- ]
-
- @classmethod
- def run_javascriptcore_tests_command(cls):
- return None
-
-
-class ChromiumXVFBPort(ChromiumPort):
-
- @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.
- return ["xvfb-run"] + ChromiumPort.run_webkit_tests_command()
diff --git a/WebKitTools/Scripts/webkitpy/common/config/ports_unittest.py b/WebKitTools/Scripts/webkitpy/common/config/ports_unittest.py
deleted file mode 100644
index 3bdf0e6..0000000
--- a/WebKitTools/Scripts/webkitpy/common/config/ports_unittest.py
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2009, 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from webkitpy.common.config.ports import *
-
-
-class WebKitPortTest(unittest.TestCase):
- def test_mac_port(self):
- self.assertEquals(MacPort.name(), "Mac")
- self.assertEquals(MacPort.flag(), "--port=mac")
- self.assertEquals(MacPort.run_webkit_tests_command(), [WebKitPort.script_path("run-webkit-tests")])
- self.assertEquals(MacPort.build_webkit_command(), [WebKitPort.script_path("build-webkit")])
- self.assertEquals(MacPort.build_webkit_command(build_style="debug"), [WebKitPort.script_path("build-webkit"), "--debug"])
- self.assertEquals(MacPort.build_webkit_command(build_style="release"), [WebKitPort.script_path("build-webkit"), "--release"])
-
- class TestIsLeopard(MacPort):
- @classmethod
- def _system_version(cls):
- return [10, 5]
- self.assertTrue(TestIsLeopard.is_leopard())
-
- def test_gtk_port(self):
- self.assertEquals(GtkPort.name(), "Gtk")
- self.assertEquals(GtkPort.flag(), "--port=gtk")
- self.assertEquals(GtkPort.run_webkit_tests_command(), [WebKitPort.script_path("run-webkit-tests"), "--gtk"])
- self.assertEquals(GtkPort.build_webkit_command(), [WebKitPort.script_path("build-webkit"), "--gtk", WebKitPort.makeArgs()])
- self.assertEquals(GtkPort.build_webkit_command(build_style="debug"), [WebKitPort.script_path("build-webkit"), "--debug", "--gtk", WebKitPort.makeArgs()])
-
- def test_qt_port(self):
- self.assertEquals(QtPort.name(), "Qt")
- self.assertEquals(QtPort.flag(), "--port=qt")
- self.assertEquals(QtPort.run_webkit_tests_command(), [WebKitPort.script_path("run-webkit-tests")])
- self.assertEquals(QtPort.build_webkit_command(), [WebKitPort.script_path("build-webkit"), "--qt", WebKitPort.makeArgs()])
- self.assertEquals(QtPort.build_webkit_command(build_style="debug"), [WebKitPort.script_path("build-webkit"), "--debug", "--qt", WebKitPort.makeArgs()])
-
- def test_chromium_port(self):
- self.assertEquals(ChromiumPort.name(), "Chromium")
- self.assertEquals(ChromiumPort.flag(), "--port=chromium")
- self.assertEquals(ChromiumPort.run_webkit_tests_command(), [WebKitPort.script_path("new-run-webkit-tests"), "--chromium", "--use-drt", "--no-pixel-tests"])
- self.assertEquals(ChromiumPort.build_webkit_command(), [WebKitPort.script_path("build-webkit"), "--chromium"])
- self.assertEquals(ChromiumPort.build_webkit_command(build_style="debug"), [WebKitPort.script_path("build-webkit"), "--debug", "--chromium"])
- self.assertEquals(ChromiumPort.update_webkit_command(), [WebKitPort.script_path("update-webkit"), "--chromium"])
-
- def test_chromium_xvfb_port(self):
- self.assertEquals(ChromiumXVFBPort.run_webkit_tests_command(), ["xvfb-run", "WebKitTools/Scripts/new-run-webkit-tests", "--chromium", "--use-drt", "--no-pixel-tests"])
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/memoized.py b/WebKitTools/Scripts/webkitpy/common/memoized.py
deleted file mode 100644
index dc844a5..0000000
--- a/WebKitTools/Scripts/webkitpy/common/memoized.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# Python does not (yet) seem to provide automatic memoization. So we've
-# written a small decorator to do so.
-
-import functools
-
-
-class memoized(object):
- def __init__(self, function):
- self._function = function
- self._results_cache = {}
-
- def __call__(self, *args):
- try:
- return self._results_cache[args]
- except KeyError:
- # If we didn't find the args in our cache, call and save the results.
- result = self._function(*args)
- self._results_cache[args] = result
- return result
- # FIXME: We may need to handle TypeError here in the case
- # that "args" is not a valid dictionary key.
-
- # Use python "descriptor" protocol __get__ to appear
- # invisible during property access.
- def __get__(self, instance, owner):
- # Return a function partial with obj already bound as self.
- return functools.partial(self.__call__, instance)
diff --git a/WebKitTools/Scripts/webkitpy/common/memoized_unittest.py b/WebKitTools/Scripts/webkitpy/common/memoized_unittest.py
deleted file mode 100644
index dd7c793..0000000
--- a/WebKitTools/Scripts/webkitpy/common/memoized_unittest.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from webkitpy.common.memoized import memoized
-
-
-class _TestObject(object):
- def __init__(self):
- self.callCount = 0
-
- @memoized
- def memoized_add(self, argument):
- """testing docstring"""
- self.callCount += 1
- if argument is None:
- return None # Avoid the TypeError from None + 1
- return argument + 1
-
-
-class MemoizedTest(unittest.TestCase):
- def test_caching(self):
- test = _TestObject()
- test.callCount = 0
- self.assertEqual(test.memoized_add(1), 2)
- self.assertEqual(test.callCount, 1)
- self.assertEqual(test.memoized_add(1), 2)
- self.assertEqual(test.callCount, 1)
-
- # Validate that callCount is working as expected.
- self.assertEqual(test.memoized_add(2), 3)
- self.assertEqual(test.callCount, 2)
-
- def test_tearoff(self):
- test = _TestObject()
- # Make sure that get()/tear-offs work:
- tearoff = test.memoized_add
- self.assertEqual(tearoff(4), 5)
- self.assertEqual(test.callCount, 1)
diff --git a/WebKitTools/Scripts/webkitpy/common/net/__init__.py b/WebKitTools/Scripts/webkitpy/common/net/__init__.py
deleted file mode 100644
index ef65bee..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Required for Python to search this directory for module files
diff --git a/WebKitTools/Scripts/webkitpy/common/net/bugzilla/__init__.py b/WebKitTools/Scripts/webkitpy/common/net/bugzilla/__init__.py
deleted file mode 100644
index cfaf3b1..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/bugzilla/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# Required for Python to search this directory for module files
-
-# We only export public API here.
-# FIXME: parse_bug_id should not be a free function.
-from .bugzilla import Bugzilla, parse_bug_id
-# Unclear if Bug and Attachment need to be public classes.
-from .bug import Bug
-from .attachment import Attachment
diff --git a/WebKitTools/Scripts/webkitpy/common/net/bugzilla/attachment.py b/WebKitTools/Scripts/webkitpy/common/net/bugzilla/attachment.py
deleted file mode 100644
index 85761fe..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/bugzilla/attachment.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# Copyright (c) 2009 Google Inc. All rights reserved.
-# Copyright (c) 2009 Apple Inc. All rights reserved.
-# Copyright (c) 2010 Research In Motion Limited. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-from webkitpy.common.system.deprecated_logging import log
-
-
-class Attachment(object):
-
- rollout_preamble = "ROLLOUT of r"
-
- def __init__(self, attachment_dictionary, bug):
- self._attachment_dictionary = attachment_dictionary
- self._bug = bug
- self._reviewer = None
- self._committer = None
-
- def _bugzilla(self):
- return self._bug._bugzilla
-
- def id(self):
- return int(self._attachment_dictionary.get("id"))
-
- def attacher_is_committer(self):
- return self._bugzilla.committers.committer_by_email(
- patch.attacher_email())
-
- def attacher_email(self):
- return self._attachment_dictionary.get("attacher_email")
-
- def bug(self):
- return self._bug
-
- def bug_id(self):
- return int(self._attachment_dictionary.get("bug_id"))
-
- def is_patch(self):
- return not not self._attachment_dictionary.get("is_patch")
-
- def is_obsolete(self):
- return not not self._attachment_dictionary.get("is_obsolete")
-
- def is_rollout(self):
- return self.name().startswith(self.rollout_preamble)
-
- def name(self):
- return self._attachment_dictionary.get("name")
-
- def attach_date(self):
- return self._attachment_dictionary.get("attach_date")
-
- def review(self):
- return self._attachment_dictionary.get("review")
-
- def commit_queue(self):
- return self._attachment_dictionary.get("commit-queue")
-
- def url(self):
- # FIXME: This should just return
- # self._bugzilla().attachment_url_for_id(self.id()). scm_unittest.py
- # depends on the current behavior.
- return self._attachment_dictionary.get("url")
-
- def contents(self):
- # FIXME: We shouldn't be grabbing at _bugzilla.
- return self._bug._bugzilla.fetch_attachment_contents(self.id())
-
- def _validate_flag_value(self, flag):
- email = self._attachment_dictionary.get("%s_email" % flag)
- if not email:
- return None
- committer = getattr(self._bugzilla().committers,
- "%s_by_email" % flag)(email)
- if committer:
- return committer
- log("Warning, attachment %s on bug %s has invalid %s (%s)" % (
- self._attachment_dictionary['id'],
- self._attachment_dictionary['bug_id'], flag, email))
-
- def reviewer(self):
- if not self._reviewer:
- self._reviewer = self._validate_flag_value("reviewer")
- return self._reviewer
-
- def committer(self):
- if not self._committer:
- self._committer = self._validate_flag_value("committer")
- return self._committer
diff --git a/WebKitTools/Scripts/webkitpy/common/net/bugzilla/bug.py b/WebKitTools/Scripts/webkitpy/common/net/bugzilla/bug.py
deleted file mode 100644
index 2cb4bc8..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/bugzilla/bug.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# Copyright (c) 2009 Google Inc. All rights reserved.
-# Copyright (c) 2009 Apple Inc. All rights reserved.
-# Copyright (c) 2010 Research In Motion Limited. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-from .attachment import Attachment
-
-
-class Bug(object):
- # FIXME: This class is kinda a hack for now. It exists so we have one
- # place to hold bug logic, even if much of the code deals with
- # dictionaries still.
-
- def __init__(self, bug_dictionary, bugzilla):
- self.bug_dictionary = bug_dictionary
- self._bugzilla = bugzilla
-
- def id(self):
- return self.bug_dictionary["id"]
-
- def title(self):
- return self.bug_dictionary["title"]
-
- def assigned_to_email(self):
- return self.bug_dictionary["assigned_to_email"]
-
- # FIXME: This information should be stored in some sort of webkit_config.py instead of here.
- unassigned_emails = frozenset([
- "webkit-unassigned@lists.webkit.org",
- "webkit-qt-unassigned@trolltech.com",
- ])
-
- def is_unassigned(self):
- return self.assigned_to_email() in self.unassigned_emails
-
- def status(self):
- return self.bug_dictionary["bug_status"]
-
- # Bugzilla has many status states we don't really use in WebKit:
- # https://bugs.webkit.org/page.cgi?id=fields.html#status
- _open_states = ["UNCONFIRMED", "NEW", "ASSIGNED", "REOPENED"]
- _closed_states = ["RESOLVED", "VERIFIED", "CLOSED"]
-
- def is_open(self):
- return self.status() in self._open_states
-
- def is_closed(self):
- return not self.is_open()
-
- # Rarely do we actually want obsolete attachments
- def attachments(self, include_obsolete=False):
- attachments = self.bug_dictionary["attachments"]
- if not include_obsolete:
- attachments = filter(lambda attachment:
- not attachment["is_obsolete"], attachments)
- return [Attachment(attachment, self) for attachment in attachments]
-
- def patches(self, include_obsolete=False):
- return [patch for patch in self.attachments(include_obsolete)
- if patch.is_patch()]
-
- def unreviewed_patches(self):
- return [patch for patch in self.patches() if patch.review() == "?"]
-
- def reviewed_patches(self, include_invalid=False):
- patches = [patch for patch in self.patches() if patch.review() == "+"]
- if include_invalid:
- return patches
- # Checking reviewer() ensures that it was both reviewed and has a valid
- # reviewer.
- return filter(lambda patch: patch.reviewer(), patches)
-
- def commit_queued_patches(self, include_invalid=False):
- patches = [patch for patch in self.patches()
- if patch.commit_queue() == "+"]
- if include_invalid:
- return patches
- # Checking committer() ensures that it was both commit-queue+'d and has
- # a valid committer.
- return filter(lambda patch: patch.committer(), patches)
diff --git a/WebKitTools/Scripts/webkitpy/common/net/bugzilla/bug_unittest.py b/WebKitTools/Scripts/webkitpy/common/net/bugzilla/bug_unittest.py
deleted file mode 100644
index d43d64f..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/bugzilla/bug_unittest.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2009 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from .bug import Bug
-
-
-class BugTest(unittest.TestCase):
- def test_is_unassigned(self):
- for email in Bug.unassigned_emails:
- bug = Bug({"assigned_to_email": email}, bugzilla=None)
- self.assertTrue(bug.is_unassigned())
- bug = Bug({"assigned_to_email": "test@test.com"}, bugzilla=None)
- self.assertFalse(bug.is_unassigned())
diff --git a/WebKitTools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py b/WebKitTools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py
deleted file mode 100644
index 9fa7fe5..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py
+++ /dev/null
@@ -1,674 +0,0 @@
-# Copyright (c) 2009 Google Inc. All rights reserved.
-# Copyright (c) 2009 Apple Inc. All rights reserved.
-# Copyright (c) 2010 Research In Motion Limited. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# WebKit's Python module for interacting with Bugzilla
-
-import os.path
-import re
-import StringIO
-
-from datetime import datetime # used in timestamp()
-
-from .attachment import Attachment
-from .bug import Bug
-
-from webkitpy.common.system.deprecated_logging import log
-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
-
-
-# FIXME: parse_bug_id should not be a free function.
-def parse_bug_id(message):
- if not message:
- return None
- match = re.search("http\://webkit\.org/b/(?P<bug_id>\d+)", message)
- if match:
- return int(match.group('bug_id'))
- match = re.search(
- Bugzilla.bug_server_regex + "show_bug\.cgi\?id=(?P<bug_id>\d+)",
- message)
- if match:
- return int(match.group('bug_id'))
- return None
-
-
-def timestamp():
- return datetime.now().strftime("%Y%m%d%H%M%S")
-
-
-# A container for all of the logic for making and parsing buzilla queries.
-class BugzillaQueries(object):
-
- def __init__(self, bugzilla):
- self._bugzilla = bugzilla
-
- # Note: _load_query and _fetch_bug are the only two methods which access
- # self._bugzilla.
-
- def _load_query(self, query):
- self._bugzilla.authenticate()
-
- full_url = "%s%s" % (self._bugzilla.bug_server_url, query)
- return self._bugzilla.browser.open(full_url)
-
- def _fetch_bug(self, bug_id):
- return self._bugzilla.fetch_bug(bug_id)
-
- def _fetch_bug_ids_advanced_query(self, query):
- soup = BeautifulSoup(self._load_query(query))
- # The contents of the <a> inside the cells in the first column happen
- # to be the bug id.
- return [int(bug_link_cell.find("a").string)
- for bug_link_cell in soup('td', "first-child")]
-
- def _parse_attachment_ids_request_query(self, page):
- digits = re.compile("\d+")
- attachment_href = re.compile("attachment.cgi\?id=\d+&action=review")
- attachment_links = SoupStrainer("a", href=attachment_href)
- return [int(digits.search(tag["href"]).group(0))
- for tag in BeautifulSoup(page, parseOnlyThese=attachment_links)]
-
- def _fetch_attachment_ids_request_query(self, query):
- return self._parse_attachment_ids_request_query(self._load_query(query))
-
- def _parse_quips(self, page):
- soup = BeautifulSoup(page, convertEntities=BeautifulSoup.HTML_ENTITIES)
- quips = soup.find(text=re.compile(r"Existing quips:")).findNext("ul").findAll("li")
- return [unicode(quip_entry.string) for quip_entry in quips]
-
- def fetch_quips(self):
- return self._parse_quips(self._load_query("/quips.cgi?action=show"))
-
- # List of all r+'d bugs.
- def fetch_bug_ids_from_pending_commit_list(self):
- needs_commit_query_url = "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=review%2B"
- return self._fetch_bug_ids_advanced_query(needs_commit_query_url)
-
- def fetch_patches_from_pending_commit_list(self):
- return sum([self._fetch_bug(bug_id).reviewed_patches()
- for bug_id in self.fetch_bug_ids_from_pending_commit_list()], [])
-
- def fetch_bug_ids_from_commit_queue(self):
- commit_queue_url = "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=commit-queue%2B&order=Last+Changed"
- return self._fetch_bug_ids_advanced_query(commit_queue_url)
-
- def fetch_patches_from_commit_queue(self):
- # This function will only return patches which have valid committers
- # set. It won't reject patches with invalid committers/reviewers.
- return sum([self._fetch_bug(bug_id).commit_queued_patches()
- for bug_id in self.fetch_bug_ids_from_commit_queue()], [])
-
- def fetch_bug_ids_from_review_queue(self):
- review_queue_url = "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=review?"
- return self._fetch_bug_ids_advanced_query(review_queue_url)
-
- # This method will make several requests to bugzilla.
- def fetch_patches_from_review_queue(self, limit=None):
- # [:None] returns the whole array.
- return sum([self._fetch_bug(bug_id).unreviewed_patches()
- for bug_id in self.fetch_bug_ids_from_review_queue()[:limit]], [])
-
- # NOTE: This is the only client of _fetch_attachment_ids_request_query
- # This method only makes one request to bugzilla.
- def fetch_attachment_ids_from_review_queue(self):
- review_queue_url = "request.cgi?action=queue&type=review&group=type"
- return self._fetch_attachment_ids_request_query(review_queue_url)
-
-
-class Bugzilla(object):
-
- def __init__(self, dryrun=False, committers=committers.CommitterList()):
- self.dryrun = dryrun
- self.authenticated = False
- self.queries = BugzillaQueries(self)
- self.committers = committers
- self.cached_quips = []
-
- # FIXME: We should use some sort of Browser mock object when in dryrun
- # mode (to prevent any mistakes).
- self.browser = Browser()
- # Ignore bugs.webkit.org/robots.txt until we fix it to allow this
- # script.
- self.browser.set_handle_robots(False)
-
- # FIXME: Much of this should go into some sort of config module:
- bug_server_host = "bugs.webkit.org"
- bug_server_regex = "https?://%s/" % re.sub('\.', '\\.', bug_server_host)
- bug_server_url = "https://%s/" % bug_server_host
-
- 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:
- self.cached_quips = self.queries.fetch_quips()
- return self.cached_quips
-
- def bug_url_for_bug_id(self, bug_id, xml=False):
- if not bug_id:
- return None
- content_type = "&ctype=xml" if xml else ""
- return "%sshow_bug.cgi?id=%s%s" % (self.bug_server_url,
- bug_id,
- content_type)
-
- def short_bug_url_for_bug_id(self, bug_id):
- if not bug_id:
- return None
- return "http://webkit.org/b/%s" % bug_id
-
- def attachment_url_for_id(self, attachment_id, action="view"):
- if not attachment_id:
- return None
- action_param = ""
- if action and action != "view":
- action_param = "&action=%s" % action
- return "%sattachment.cgi?id=%s%s" % (self.bug_server_url,
- attachment_id,
- action_param)
-
- def _parse_attachment_flag(self,
- element,
- flag_name,
- attachment,
- result_key):
- flag = element.find('flag', attrs={'name': flag_name})
- if flag:
- attachment[flag_name] = flag['status']
- if flag['status'] == '+':
- attachment[result_key] = flag['setter']
- # Sadly show_bug.cgi?ctype=xml does not expose the flag modification date.
-
- def _string_contents(self, soup):
- # WebKit's bugzilla instance uses UTF-8.
- # BeautifulSoup 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().
- return unicode(soup.string)
-
- # Example: 2010-01-20 14:31 PST
- # FIXME: Some bugzilla dates seem to have seconds in them?
- # Python does not support timezones out of the box.
- # Assume that bugzilla always uses PST (which is true for bugs.webkit.org)
- _bugzilla_date_format = "%Y-%m-%d %H:%M"
-
- @classmethod
- def _parse_date(cls, date_string):
- (date, time, time_zone) = date_string.split(" ")
- # Ignore the timezone because python doesn't understand timezones out of the box.
- date_string = "%s %s" % (date, time)
- return datetime.strptime(date_string, cls._bugzilla_date_format)
-
- def _date_contents(self, soup):
- return self._parse_date(self._string_contents(soup))
-
- def _parse_attachment_element(self, element, bug_id):
- attachment = {}
- attachment['bug_id'] = bug_id
- attachment['is_obsolete'] = (element.has_key('isobsolete') and element['isobsolete'] == "1")
- attachment['is_patch'] = (element.has_key('ispatch') and element['ispatch'] == "1")
- attachment['id'] = int(element.find('attachid').string)
- # FIXME: No need to parse out the url here.
- attachment['url'] = self.attachment_url_for_id(attachment['id'])
- attachment["attach_date"] = self._date_contents(element.find("date"))
- attachment['name'] = self._string_contents(element.find('desc'))
- attachment['attacher_email'] = self._string_contents(element.find('attacher'))
- attachment['type'] = self._string_contents(element.find('type'))
- self._parse_attachment_flag(
- element, 'review', attachment, 'reviewer_email')
- self._parse_attachment_flag(
- element, 'commit-queue', attachment, 'committer_email')
- return attachment
-
- def _parse_bug_page(self, page):
- soup = BeautifulSoup(page)
- bug = {}
- bug["id"] = int(soup.find("bug_id").string)
- bug["title"] = self._string_contents(soup.find("short_desc"))
- bug["bug_status"] = self._string_contents(soup.find("bug_status"))
- bug["reporter_email"] = self._string_contents(soup.find("reporter"))
- bug["assigned_to_email"] = self._string_contents(soup.find("assigned_to"))
- bug["cc_emails"] = [self._string_contents(element)
- for element in soup.findAll('cc')]
- bug["attachments"] = [self._parse_attachment_element(element, bug["id"]) for element in soup.findAll('attachment')]
- return bug
-
- # Makes testing fetch_*_from_bug() possible until we have a better
- # BugzillaNetwork abstration.
-
- def _fetch_bug_page(self, bug_id):
- bug_url = self.bug_url_for_bug_id(bug_id, xml=True)
- log("Fetching: %s" % bug_url)
- return self.browser.open(bug_url)
-
- def fetch_bug_dictionary(self, bug_id):
- try:
- return self._parse_bug_page(self._fetch_bug_page(bug_id))
- except KeyboardInterrupt:
- raise
- except:
- self.authenticate()
- return self._parse_bug_page(self._fetch_bug_page(bug_id))
-
- # FIXME: A BugzillaCache object should provide all these fetch_ methods.
-
- def fetch_bug(self, bug_id):
- return Bug(self.fetch_bug_dictionary(bug_id), self)
-
- def fetch_attachment_contents(self, attachment_id):
- attachment_url = self.attachment_url_for_id(attachment_id)
- # We need to authenticate to download patches from security bugs.
- self.authenticate()
- return self.browser.open(attachment_url).read()
-
- def _parse_bug_id_from_attachment_page(self, page):
- # The "Up" relation happens to point to the bug.
- up_link = BeautifulSoup(page).find('link', rel='Up')
- if not up_link:
- # This attachment does not exist (or you don't have permissions to
- # view it).
- return None
- match = re.search("show_bug.cgi\?id=(?P<bug_id>\d+)", up_link['href'])
- return int(match.group('bug_id'))
-
- def bug_id_for_attachment_id(self, attachment_id):
- self.authenticate()
-
- attachment_url = self.attachment_url_for_id(attachment_id, 'edit')
- log("Fetching: %s" % attachment_url)
- page = self.browser.open(attachment_url)
- return self._parse_bug_id_from_attachment_page(page)
-
- # FIXME: This should just return Attachment(id), which should be able to
- # lazily fetch needed data.
-
- def fetch_attachment(self, attachment_id):
- # We could grab all the attachment details off of the attachment edit
- # page but we already have working code to do so off of the bugs page,
- # so re-use that.
- bug_id = self.bug_id_for_attachment_id(attachment_id)
- if not bug_id:
- return None
- attachments = self.fetch_bug(bug_id).attachments(include_obsolete=True)
- for attachment in attachments:
- if attachment.id() == int(attachment_id):
- return attachment
- return None # This should never be hit.
-
- def authenticate(self):
- if self.authenticated:
- return
-
- if self.dryrun:
- log("Skipping log in for dry run...")
- self.authenticated = True
- return
-
- credentials = Credentials(self.bug_server_host, git_prefix="bugzilla")
-
- attempts = 0
- while not self.authenticated:
- attempts += 1
- username, password = credentials.read_credentials()
-
- log("Logging in as %s..." % username)
- self.browser.open(self.bug_server_url +
- "index.cgi?GoAheadAndLogIn=1")
- self.browser.select_form(name="login")
- self.browser['Bugzilla_login'] = username
- self.browser['Bugzilla_password'] = password
- response = self.browser.submit()
-
- match = re.search("<title>(.+?)</title>", response.read())
- # If the resulting page has a title, and it contains the word
- # "invalid" assume it's the login failure page.
- if match and re.search("Invalid", match.group(1), re.IGNORECASE):
- errorMessage = "Bugzilla login failed: %s" % match.group(1)
- # raise an exception only if this was the last attempt
- if attempts < 5:
- log(errorMessage)
- else:
- raise Exception(errorMessage)
- else:
- self.authenticated = True
- self.username = username
-
- def _fill_attachment_form(self,
- description,
- patch_file_object,
- comment_text=None,
- mark_for_review=False,
- mark_for_commit_queue=False,
- mark_for_landing=False,
- bug_id=None):
- self.browser['description'] = description
- self.browser['ispatch'] = ("1",)
- self.browser['flag_type-1'] = ('?',) if mark_for_review else ('X',)
-
- if mark_for_landing:
- self.browser['flag_type-3'] = ('+',)
- elif mark_for_commit_queue:
- self.browser['flag_type-3'] = ('?',)
- else:
- self.browser['flag_type-3'] = ('X',)
-
- if bug_id:
- patch_name = "bug-%s-%s.patch" % (bug_id, timestamp())
- else:
- patch_name ="%s.patch" % timestamp()
-
- self.browser.add_file(patch_file_object,
- "text/plain",
- patch_name,
- 'data')
-
- def add_patch_to_bug(self,
- bug_id,
- diff,
- description,
- comment_text=None,
- mark_for_review=False,
- mark_for_commit_queue=False,
- mark_for_landing=False):
- self.authenticate()
-
- log('Adding patch "%s" to %sshow_bug.cgi?id=%s' % (description,
- self.bug_server_url,
- bug_id))
-
- if self.dryrun:
- log(comment_text)
- return
-
- self.browser.open("%sattachment.cgi?action=enter&bugid=%s" % (
- self.bug_server_url, bug_id))
- self.browser.select_form(name="entryform")
-
- # _fill_attachment_form expects a file-like object
- # Patch files are already binary, so no encoding needed.
- assert(isinstance(diff, str))
- patch_file_object = StringIO.StringIO(diff)
- self._fill_attachment_form(description,
- patch_file_object,
- mark_for_review=mark_for_review,
- mark_for_commit_queue=mark_for_commit_queue,
- mark_for_landing=mark_for_landing,
- bug_id=bug_id)
- if comment_text:
- log(comment_text)
- self.browser['comment'] = comment_text
- self.browser.submit()
-
- def _check_create_bug_response(self, response_html):
- match = re.search("<title>Bug (?P<bug_id>\d+) Submitted</title>",
- response_html)
- if match:
- return match.group('bug_id')
-
- match = re.search(
- '<div id="bugzilla-body">(?P<error_message>.+)<div id="footer">',
- response_html,
- re.DOTALL)
- error_message = "FAIL"
- if match:
- text_lines = BeautifulSoup(
- match.group('error_message')).findAll(text=True)
- error_message = "\n" + '\n'.join(
- [" " + line.strip()
- for line in text_lines if line.strip()])
- raise Exception("Bug not created: %s" % error_message)
-
- def create_bug(self,
- bug_title,
- bug_description,
- component=None,
- diff=None,
- patch_description=None,
- cc=None,
- blocked=None,
- assignee=None,
- mark_for_review=False,
- mark_for_commit_queue=False):
- self.authenticate()
-
- log('Creating bug with title "%s"' % bug_title)
- if self.dryrun:
- log(bug_description)
- return
-
- self.browser.open(self.bug_server_url + "enter_bug.cgi?product=WebKit")
- self.browser.select_form(name="Create")
- component_items = self.browser.find_control('component').items
- component_names = map(lambda item: item.name, component_items)
- if not component:
- component = "New Bugs"
- if component not in component_names:
- component = User.prompt_with_list("Please pick a component:", component_names)
- self.browser["component"] = [component]
- if cc:
- self.browser["cc"] = cc
- if blocked:
- self.browser["blocked"] = unicode(blocked)
- if assignee == None:
- assignee = self.username
- if assignee and not self.browser.find_control("assigned_to").disabled:
- self.browser["assigned_to"] = assignee
- self.browser["short_desc"] = bug_title
- self.browser["comment"] = bug_description
-
- if diff:
- # _fill_attachment_form expects a file-like object
- # Patch files are already binary, so no encoding needed.
- assert(isinstance(diff, str))
- patch_file_object = StringIO.StringIO(diff)
- self._fill_attachment_form(
- patch_description,
- patch_file_object,
- mark_for_review=mark_for_review,
- mark_for_commit_queue=mark_for_commit_queue)
-
- response = self.browser.submit()
-
- bug_id = self._check_create_bug_response(response.read())
- log("Bug %s created." % bug_id)
- log("%sshow_bug.cgi?id=%s" % (self.bug_server_url, bug_id))
- return bug_id
-
- def _find_select_element_for_flag(self, flag_name):
- # FIXME: This will break if we ever re-order attachment flags
- if flag_name == "review":
- return self.browser.find_control(type='select', nr=0)
- elif flag_name == "commit-queue":
- return self.browser.find_control(type='select', nr=1)
- raise Exception("Don't know how to find flag named \"%s\"" % flag_name)
-
- def clear_attachment_flags(self,
- attachment_id,
- additional_comment_text=None):
- self.authenticate()
-
- comment_text = "Clearing flags on attachment: %s" % attachment_id
- if additional_comment_text:
- 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)
- self._find_select_element_for_flag('review').value = ("X",)
- self._find_select_element_for_flag('commit-queue').value = ("X",)
- self.browser.submit()
-
- def set_flag_on_attachment(self,
- attachment_id,
- flag_name,
- flag_value,
- comment_text=None,
- additional_comment_text=None):
- # FIXME: We need a way to test this function on a live bugzilla
- # instance.
-
- self.authenticate()
-
- if additional_comment_text:
- 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)
-
- if comment_text:
- self.browser.set_value(comment_text, name='comment', nr=0)
-
- self._find_select_element_for_flag(flag_name).value = (flag_value,)
- self.browser.submit()
-
- # FIXME: All of these bug editing methods have a ridiculous amount of
- # copy/paste code.
-
- def obsolete_attachment(self, attachment_id, comment_text=None):
- 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
- # Also clear any review flag (to remove it from review/commit queues)
- self._find_select_element_for_flag('review').value = ("X",)
- self._find_select_element_for_flag('commit-queue').value = ("X",)
- if comment_text:
- log(comment_text)
- # Bugzilla has two textareas named 'comment', one is somehow
- # hidden. We want the first.
- self.browser.set_value(comment_text, name='comment', nr=0)
- self.browser.submit()
-
- def add_cc_to_bug(self, bug_id, email_address_list):
- 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)
- self.browser.submit()
-
- def post_comment_to_bug(self, bug_id, comment_text, cc=None):
- 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
- if cc:
- self.browser["newcc"] = ", ".join(cc)
- self.browser.submit()
-
- def close_bug_as_fixed(self, bug_id, comment_text=None):
- 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:
- self.browser['comment'] = comment_text
- self.browser['bug_status'] = ['RESOLVED']
- self.browser['resolution'] = ['FIXED']
- self.browser.submit()
-
- def reassign_bug(self, bug_id, assignee, comment_text=None):
- self.authenticate()
-
- 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")
- if comment_text:
- log(comment_text)
- self.browser["comment"] = comment_text
- self.browser["assigned_to"] = assignee
- self.browser.submit()
-
- def reopen_bug(self, bug_id, comment_text):
- self.authenticate()
-
- log("Re-opening bug %s" % bug_id)
- # 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")
- # This is a hack around the fact that ClientForm.ListControl seems to
- # have no simpler way to ask if a control has an item named "REOPENED"
- # without using exceptions for control flow.
- possible_bug_statuses = map(lambda item: item.name, bug_status.items)
- if "REOPENED" in possible_bug_statuses:
- bug_status.value = ["REOPENED"]
- # If the bug was never confirmed it will not have a "REOPENED"
- # state, but only an "UNCONFIRMED" state.
- elif "UNCONFIRMED" in possible_bug_statuses:
- bug_status.value = ["UNCONFIRMED"]
- else:
- # FIXME: This logic is slightly backwards. We won't print this
- # message if the bug is already open with state "UNCONFIRMED".
- log("Did not reopen bug %s, it appears to already be open with status %s." % (bug_id, bug_status.value))
- self.browser['comment'] = comment_text
- self.browser.submit()
diff --git a/WebKitTools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py b/WebKitTools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py
deleted file mode 100644
index c476c81..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py
+++ /dev/null
@@ -1,342 +0,0 @@
-# Copyright (C) 2009 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-import datetime
-
-from .bugzilla import Bugzilla, BugzillaQueries, parse_bug_id
-
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.tool.mocktool import MockBrowser
-from webkitpy.thirdparty.mock import Mock
-from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup
-
-
-class BugzillaTest(unittest.TestCase):
- _example_attachment = '''
- <attachment
- isobsolete="1"
- ispatch="1"
- isprivate="0"
- >
- <attachid>33721</attachid>
- <date>2009-07-29 10:23 PDT</date>
- <desc>Fixed whitespace issue</desc>
- <filename>patch</filename>
- <type>text/plain</type>
- <size>9719</size>
- <attacher>christian.plesner.hansen@gmail.com</attacher>
- <flag name="review"
- id="17931"
- status="+"
- setter="one@test.com"
- />
- <flag name="commit-queue"
- id="17932"
- status="+"
- setter="two@test.com"
- />
- </attachment>
-'''
- _expected_example_attachment_parsing = {
- 'attach_date': datetime.datetime(2009, 07, 29, 10, 23),
- 'bug_id' : 100,
- 'is_obsolete' : True,
- 'is_patch' : True,
- 'id' : 33721,
- 'url' : "https://bugs.webkit.org/attachment.cgi?id=33721",
- 'name' : "Fixed whitespace issue",
- 'type' : "text/plain",
- 'review' : '+',
- 'reviewer_email' : 'one@test.com',
- 'commit-queue' : '+',
- 'committer_email' : 'two@test.com',
- 'attacher_email' : 'christian.plesner.hansen@gmail.com',
- }
-
- def test_url_creation(self):
- # FIXME: These would be all better as doctests
- bugs = Bugzilla()
- self.assertEquals(None, bugs.bug_url_for_bug_id(None))
- self.assertEquals(None, bugs.short_bug_url_for_bug_id(None))
- self.assertEquals(None, bugs.attachment_url_for_id(None))
-
- def test_parse_bug_id(self):
- # FIXME: These would be all better as doctests
- bugs = Bugzilla()
- self.assertEquals(12345, parse_bug_id("http://webkit.org/b/12345"))
- self.assertEquals(12345, parse_bug_id("http://bugs.webkit.org/show_bug.cgi?id=12345"))
- self.assertEquals(12345, parse_bug_id(bugs.short_bug_url_for_bug_id(12345)))
- self.assertEquals(12345, parse_bug_id(bugs.bug_url_for_bug_id(12345)))
- self.assertEquals(12345, parse_bug_id(bugs.bug_url_for_bug_id(12345, xml=True)))
-
- # Our bug parser is super-fragile, but at least we're testing it.
- self.assertEquals(None, parse_bug_id("http://www.webkit.org/b/12345"))
- self.assertEquals(None, parse_bug_id("http://bugs.webkit.org/show_bug.cgi?ctype=xml&id=12345"))
-
- _example_bug = """
-<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
-<!DOCTYPE bugzilla SYSTEM "https://bugs.webkit.org/bugzilla.dtd">
-<bugzilla version="3.2.3"
- urlbase="https://bugs.webkit.org/"
- maintainer="admin@webkit.org"
- exporter="eric@webkit.org"
->
- <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>
- <delta_ts>2009-12-27 21:04:50 PST</delta_ts>
- <reporter_accessible>1</reporter_accessible>
- <cclist_accessible>1</cclist_accessible>
- <classification_id>1</classification_id>
- <classification>Unclassified</classification>
- <product>WebKit</product>
- <component>Tools / Tests</component>
- <version>528+ (Nightly build)</version>
- <rep_platform>PC</rep_platform>
- <op_sys>Mac OS X 10.5</op_sys>
- <bug_status>NEW</bug_status>
- <priority>P2</priority>
- <bug_severity>Normal</bug_severity>
- <target_milestone>---</target_milestone>
- <everconfirmed>1</everconfirmed>
- <reporter name="Eric Seidel">eric@webkit.org</reporter>
- <assigned_to name="Nobody">webkit-unassigned@lists.webkit.org</assigned_to>
- <cc>foo@bar.com</cc>
- <cc>example@example.com</cc>
- <long_desc isprivate="0">
- <who name="Eric Seidel">eric@webkit.org</who>
- <bug_when>2009-12-15 15:17:28 PST</bug_when>
- <thetext>bug to test webkit-patch and commit-queue failures
-
-Ignore this bug. Just for testing failure modes of webkit-patch and the commit-queue.</thetext>
- </long_desc>
- <attachment
- isobsolete="0"
- ispatch="1"
- isprivate="0"
- >
- <attachid>45548</attachid>
- <date>2009-12-27 23:51 PST</date>
- <desc>Patch</desc>
- <filename>bug-32585-20091228005112.patch</filename>
- <type>text/plain</type>
- <size>10882</size>
- <attacher>mjs@apple.com</attacher>
-
- <token>1261988248-dc51409e9c421a4358f365fa8bec8357</token>
- <data encoding="base64">SW5kZXg6IFdlYktpdC9tYWMvQ2hhbmdlTG9nCj09PT09PT09PT09PT09PT09PT09PT09PT09PT09
-removed-because-it-was-really-long
-ZEZpbmlzaExvYWRXaXRoUmVhc29uOnJlYXNvbl07Cit9CisKIEBlbmQKIAogI2VuZGlmCg==
-</data>
-
- <flag name="review"
- id="27602"
- status="?"
- setter="mjs@apple.com"
- />
- </attachment>
- </bug>
-</bugzilla>
-"""
- _expected_example_bug_parsing = {
- "id" : 32585,
- "title" : u"bug to test webkit-patch and commit-queue failures",
- "cc_emails" : ["foo@bar.com", "example@example.com"],
- "reporter_email" : "eric@webkit.org",
- "assigned_to_email" : "webkit-unassigned@lists.webkit.org",
- "bug_status": "NEW",
- "attachments" : [{
- "attach_date": datetime.datetime(2009, 12, 27, 23, 51),
- 'name': u'Patch',
- 'url' : "https://bugs.webkit.org/attachment.cgi?id=45548",
- 'is_obsolete': False,
- 'review': '?',
- 'is_patch': True,
- 'attacher_email': 'mjs@apple.com',
- 'bug_id': 32585,
- 'type': 'text/plain',
- 'id': 45548
- }],
- }
-
- # FIXME: This should move to a central location and be shared by more unit tests.
- def _assert_dictionaries_equal(self, actual, expected):
- # Make sure we aren't parsing more or less than we expect
- self.assertEquals(sorted(actual.keys()), sorted(expected.keys()))
-
- for key, expected_value in expected.items():
- self.assertEquals(actual[key], expected_value, ("Failure for key: %s: Actual='%s' Expected='%s'" % (key, actual[key], expected_value)))
-
- def test_bug_parsing(self):
- bug = Bugzilla()._parse_bug_page(self._example_bug)
- self._assert_dictionaries_equal(bug, self._expected_example_bug_parsing)
-
- # This could be combined into test_bug_parsing later if desired.
- def test_attachment_parsing(self):
- bugzilla = Bugzilla()
- soup = BeautifulSoup(self._example_attachment)
- attachment_element = soup.find("attachment")
- attachment = bugzilla._parse_attachment_element(attachment_element, self._expected_example_attachment_parsing['bug_id'])
- self.assertTrue(attachment)
- self._assert_dictionaries_equal(attachment, self._expected_example_attachment_parsing)
-
- _sample_attachment_detail_page = """
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
-<html>
- <head>
- <title>
- Attachment 41073 Details for Bug 27314</title>
-<link rel="Top" href="https://bugs.webkit.org/">
- <link rel="Up" href="show_bug.cgi?id=27314">
-"""
-
- def test_attachment_detail_bug_parsing(self):
- bugzilla = Bugzilla()
- self.assertEquals(27314, bugzilla._parse_bug_id_from_attachment_page(self._sample_attachment_detail_page))
-
- def test_add_cc_to_bug(self):
- bugzilla = Bugzilla()
- bugzilla.browser = MockBrowser()
- bugzilla.authenticate = lambda: None
- expected_stderr = "Adding ['adam@example.com'] to the CC list for bug 42\n"
- OutputCapture().assert_outputs(self, bugzilla.add_cc_to_bug, [42, ["adam@example.com"]], expected_stderr=expected_stderr)
-
- def _mock_control_item(self, name):
- mock_item = Mock()
- mock_item.name = name
- return mock_item
-
- def _mock_find_control(self, item_names=[], selected_index=0):
- mock_control = Mock()
- mock_control.items = [self._mock_control_item(name) for name in item_names]
- mock_control.value = [item_names[selected_index]] if item_names else None
- return lambda name, type: mock_control
-
- def _assert_reopen(self, item_names=None, selected_index=None, extra_stderr=None):
- bugzilla = Bugzilla()
- bugzilla.browser = MockBrowser()
- bugzilla.authenticate = lambda: None
-
- mock_find_control = self._mock_find_control(item_names, selected_index)
- bugzilla.browser.find_control = mock_find_control
- expected_stderr = "Re-opening bug 42\n['comment']\n"
- if extra_stderr:
- expected_stderr += extra_stderr
- OutputCapture().assert_outputs(self, bugzilla.reopen_bug, [42, ["comment"]], expected_stderr=expected_stderr)
-
- def test_reopen_bug(self):
- self._assert_reopen(item_names=["REOPENED", "RESOLVED", "CLOSED"], selected_index=1)
- self._assert_reopen(item_names=["UNCONFIRMED", "RESOLVED", "CLOSED"], selected_index=1)
- extra_stderr = "Did not reopen bug 42, it appears to already be open with status ['NEW'].\n"
- self._assert_reopen(item_names=["NEW", "RESOLVED"], selected_index=0, extra_stderr=extra_stderr)
-
-
-class BugzillaQueriesTest(unittest.TestCase):
- _sample_request_page = """
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
-<html>
- <head>
- <title>Request Queue</title>
- </head>
-<body>
-
-<h3>Flag: review</h3>
- <table class="requests" cellspacing="0" cellpadding="4" border="1">
- <tr>
- <th>Requester</th>
- <th>Requestee</th>
- <th>Bug</th>
- <th>Attachment</th>
- <th>Created</th>
- </tr>
- <tr>
- <td>Shinichiro Hamaji &lt;hamaji&#64;chromium.org&gt;</td>
- <td></td>
- <td><a href="show_bug.cgi?id=30015">30015: text-transform:capitalize is failing in CSS2.1 test suite</a></td>
- <td><a href="attachment.cgi?id=40511&amp;action=review">
-40511: Patch v0</a></td>
- <td>2009-10-02 04:58 PST</td>
- </tr>
- <tr>
- <td>Zan Dobersek &lt;zandobersek&#64;gmail.com&gt;</td>
- <td></td>
- <td><a href="show_bug.cgi?id=26304">26304: [GTK] Add controls for playing html5 video.</a></td>
- <td><a href="attachment.cgi?id=40722&amp;action=review">
-40722: Media controls, the simple approach</a></td>
- <td>2009-10-06 09:13 PST</td>
- </tr>
- <tr>
- <td>Zan Dobersek &lt;zandobersek&#64;gmail.com&gt;</td>
- <td></td>
- <td><a href="show_bug.cgi?id=26304">26304: [GTK] Add controls for playing html5 video.</a></td>
- <td><a href="attachment.cgi?id=40723&amp;action=review">
-40723: Adjust the media slider thumb size</a></td>
- <td>2009-10-06 09:15 PST</td>
- </tr>
- </table>
-</body>
-</html>
-"""
- _sample_quip_page = u"""
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
-<html>
- <head>
- <title>Bugzilla Quip System</title>
- </head>
- <body>
- <h2>
-
- Existing quips:
- </h2>
- <ul>
- <li>Everything should be made as simple as possible, but not simpler. - Albert Einstein</li>
- <li>Good artists copy. Great artists steal. - Pablo Picasso</li>
- <li>\u00e7gua mole em pedra dura, tanto bate at\u008e que fura.</li>
-
- </ul>
- </body>
-</html>
-"""
-
- def test_request_page_parsing(self):
- queries = BugzillaQueries(None)
- self.assertEquals([40511, 40722, 40723], queries._parse_attachment_ids_request_query(self._sample_request_page))
-
- def test_quip_page_parsing(self):
- queries = BugzillaQueries(None)
- expected_quips = ["Everything should be made as simple as possible, but not simpler. - Albert Einstein", "Good artists copy. Great artists steal. - Pablo Picasso", u"\u00e7gua mole em pedra dura, tanto bate at\u008e que fura."]
- self.assertEquals(expected_quips, queries._parse_quips(self._sample_quip_page))
-
- def test_load_query(self):
- queries = BugzillaQueries(Mock())
- queries._load_query("request.cgi?action=queue&type=review&group=type")
diff --git a/WebKitTools/Scripts/webkitpy/common/net/buildbot.py b/WebKitTools/Scripts/webkitpy/common/net/buildbot.py
deleted file mode 100644
index 88cdd4e..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/buildbot.py
+++ /dev/null
@@ -1,452 +0,0 @@
-# Copyright (c) 2009, 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# WebKit's Python module for interacting with WebKit's buildbot
-
-import operator
-import re
-import urllib
-import urllib2
-import xmlrpclib
-
-from webkitpy.common.net.failuremap import FailureMap
-from webkitpy.common.net.layouttestresults import LayoutTestResults
-from webkitpy.common.net.regressionwindow import RegressionWindow
-from webkitpy.common.system.logutils import get_logger
-from webkitpy.thirdparty.autoinstalled.mechanize import Browser
-from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup
-
-_log = get_logger(__file__)
-
-
-class Builder(object):
- def __init__(self, name, buildbot):
- self._name = name
- self._buildbot = buildbot
- self._builds_cache = {}
- self._revision_to_build_number = None
- self._browser = Browser()
- self._browser.set_handle_robots(False) # The builder pages are excluded by robots.txt
-
- def name(self):
- return self._name
-
- def results_url(self):
- return "http://%s/results/%s" % (self._buildbot.buildbot_host, self.url_encoded_name())
-
- def url_encoded_name(self):
- return urllib.quote(self._name)
-
- def url(self):
- return "http://%s/builders/%s" % (self._buildbot.buildbot_host, self.url_encoded_name())
-
- # This provides a single place to mock
- def _fetch_build(self, build_number):
- build_dictionary = self._buildbot._fetch_xmlrpc_build_dictionary(self, build_number)
- if not build_dictionary:
- return None
- return Build(self,
- build_number=int(build_dictionary['number']),
- revision=int(build_dictionary['revision']),
- is_green=(build_dictionary['results'] == 0) # Undocumented, buildbot XMLRPC, 0 seems to mean "pass"
- )
-
- def build(self, build_number):
- if not build_number:
- return None
- cached_build = self._builds_cache.get(build_number)
- if cached_build:
- return cached_build
-
- build = self._fetch_build(build_number)
- self._builds_cache[build_number] = build
- return build
-
- def force_build(self, username="webkit-patch", comments=None):
- def predicate(form):
- try:
- return form.find_control("username")
- except Exception, e:
- return False
- self._browser.open(self.url())
- self._browser.select_form(predicate=predicate)
- self._browser["username"] = username
- if comments:
- self._browser["comments"] = comments
- return self._browser.submit()
-
- file_name_regexp = re.compile(r"r(?P<revision>\d+) \((?P<build_number>\d+)\)")
- def _revision_and_build_for_filename(self, filename):
- # Example: "r47483 (1)/" or "r47483 (1).zip"
- match = self.file_name_regexp.match(filename)
- return (int(match.group("revision")), int(match.group("build_number")))
-
- def _fetch_revision_to_build_map(self):
- # All _fetch requests go through _buildbot for easier mocking
- # FIXME: This should use NetworkTransaction's 404 handling instead.
- try:
- # FIXME: This method is horribly slow due to the huge network load.
- # FIXME: This is a poor way to do revision -> build mapping.
- # Better would be to ask buildbot through some sort of API.
- print "Loading revision/build list from %s." % self.results_url()
- print "This may take a while..."
- result_files = self._buildbot._fetch_twisted_directory_listing(self.results_url())
- except urllib2.HTTPError, error:
- if error.code != 404:
- raise
- result_files = []
-
- # This assumes there was only one build per revision, which is false but we don't care for now.
- return dict([self._revision_and_build_for_filename(file_info["filename"]) for file_info in result_files])
-
- def _revision_to_build_map(self):
- if not self._revision_to_build_number:
- self._revision_to_build_number = self._fetch_revision_to_build_map()
- return self._revision_to_build_number
-
- def revision_build_pairs_with_results(self):
- return self._revision_to_build_map().items()
-
- # This assumes there can be only one build per revision, which is false, but we don't care for now.
- def build_for_revision(self, revision, allow_failed_lookups=False):
- # NOTE: This lookup will fail if that exact revision was never built.
- build_number = self._revision_to_build_map().get(int(revision))
- if not build_number:
- return None
- build = self.build(build_number)
- if not build and allow_failed_lookups:
- # Builds for old revisions with fail to lookup via buildbot's xmlrpc api.
- build = Build(self,
- build_number=build_number,
- revision=revision,
- is_green=False,
- )
- return build
-
- def find_regression_window(self, red_build, look_back_limit=30):
- if not red_build or red_build.is_green():
- return RegressionWindow(None, None)
- common_failures = None
- current_build = red_build
- build_after_current_build = None
- look_back_count = 0
- while current_build:
- if current_build.is_green():
- # current_build can't possibly have any failures in common
- # with red_build because it's green.
- break
- results = current_build.layout_test_results()
- # We treat a lack of results as if all the test failed.
- # This occurs, for example, when we can't compile at all.
- if results:
- failures = set(results.failing_tests())
- if common_failures == None:
- common_failures = failures
- else:
- common_failures = common_failures.intersection(failures)
- if not common_failures:
- # current_build doesn't have any failures in common with
- # the red build we're worried about. We assume that any
- # failures in current_build were due to flakiness.
- break
- look_back_count += 1
- if look_back_count > look_back_limit:
- return RegressionWindow(None, current_build, failing_tests=common_failures)
- build_after_current_build = current_build
- current_build = current_build.previous_build()
- # We must iterate at least once because red_build is red.
- assert(build_after_current_build)
- # Current build must either be green or have no failures in common
- # with red build, so we've found our failure transition.
- return RegressionWindow(current_build, build_after_current_build, failing_tests=common_failures)
-
- def find_blameworthy_regression_window(self, red_build_number, look_back_limit=30, avoid_flakey_tests=True):
- red_build = self.build(red_build_number)
- regression_window = self.find_regression_window(red_build, look_back_limit)
- if not regression_window.build_before_failure():
- return None # We ran off the limit of our search
- # If avoid_flakey_tests, require at least 2 bad builds before we
- # suspect a real failure transition.
- if avoid_flakey_tests and regression_window.failing_build() == red_build:
- return None
- return regression_window
-
-
-class Build(object):
- def __init__(self, builder, build_number, revision, is_green):
- self._builder = builder
- self._number = build_number
- self._revision = revision
- self._is_green = is_green
- self._layout_test_results = None
-
- @staticmethod
- def build_url(builder, build_number):
- return "%s/builds/%s" % (builder.url(), build_number)
-
- def url(self):
- return self.build_url(self.builder(), self._number)
-
- def results_url(self):
- results_directory = "r%s (%s)" % (self.revision(), self._number)
- return "%s/%s" % (self._builder.results_url(), urllib.quote(results_directory))
-
- def _fetch_results_html(self):
- results_html = "%s/results.html" % (self.results_url())
- # FIXME: This should use NetworkTransaction's 404 handling instead.
- try:
- # It seems this can return None if the url redirects and then returns 404.
- return urllib2.urlopen(results_html)
- except urllib2.HTTPError, error:
- if error.code != 404:
- raise
-
- def layout_test_results(self):
- if not self._layout_test_results:
- # FIXME: This should cache that the result was a 404 and stop hitting the network.
- self._layout_test_results = LayoutTestResults.results_from_string(self._fetch_results_html())
- return self._layout_test_results
-
- def builder(self):
- return self._builder
-
- def revision(self):
- return self._revision
-
- def is_green(self):
- return self._is_green
-
- def previous_build(self):
- # previous_build() allows callers to avoid assuming build numbers are sequential.
- # They may not be sequential across all master changes, or when non-trunk builds are made.
- return self._builder.build(self._number - 1)
-
-
-class BuildBot(object):
- # FIXME: This should move into some sort of webkit_config.py
- default_host = "build.webkit.org"
-
- def __init__(self, host=default_host):
- self.buildbot_host = host
- self._builder_by_name = {}
-
- # If any core builder is red we should not be landing patches. Other
- # builders should be added to this list once they are known to be
- # reliable.
- # See https://bugs.webkit.org/show_bug.cgi?id=33296 and related bugs.
- self.core_builder_names_regexps = [
- "SnowLeopard.*Build",
- "SnowLeopard.*\(Test", # Exclude WebKit2 for now.
- "Leopard",
- "Tiger",
- "Windows.*Build",
- "GTK.*32",
- "GTK.*64.*Debug", # Disallow the 64-bit Release bot which is broken.
- "Qt",
- "Chromium.*Release$",
- ]
-
- def _parse_last_build_cell(self, builder, cell):
- status_link = cell.find('a')
- if status_link:
- # Will be either a revision number or a build number
- revision_string = status_link.string
- # If revision_string has non-digits assume it's not a revision number.
- builder['built_revision'] = int(revision_string) \
- if not re.match('\D', revision_string) \
- else None
-
- # FIXME: We treat slave lost as green even though it is not to
- # work around the Qts bot being on a broken internet connection.
- # The real fix is https://bugs.webkit.org/show_bug.cgi?id=37099
- builder['is_green'] = not re.search('fail', cell.renderContents()) or \
- not not re.search('lost', cell.renderContents())
-
- status_link_regexp = r"builders/(?P<builder_name>.*)/builds/(?P<build_number>\d+)"
- link_match = re.match(status_link_regexp, status_link['href'])
- builder['build_number'] = int(link_match.group("build_number"))
- else:
- # We failed to find a link in the first cell, just give up. This
- # can happen if a builder is just-added, the first cell will just
- # be "no build"
- # Other parts of the code depend on is_green being present.
- builder['is_green'] = False
- builder['built_revision'] = None
- builder['build_number'] = None
-
- def _parse_current_build_cell(self, builder, cell):
- activity_lines = cell.renderContents().split("<br />")
- builder["activity"] = activity_lines[0] # normally "building" or "idle"
- # The middle lines document how long left for any current builds.
- match = re.match("(?P<pending_builds>\d) pending", activity_lines[-1])
- builder["pending_builds"] = int(match.group("pending_builds")) if match else 0
-
- def _parse_builder_status_from_row(self, status_row):
- status_cells = status_row.findAll('td')
- builder = {}
-
- # First cell is the name
- name_link = status_cells[0].find('a')
- builder["name"] = unicode(name_link.string)
-
- self._parse_last_build_cell(builder, status_cells[1])
- self._parse_current_build_cell(builder, status_cells[2])
- return builder
-
- def _matches_regexps(self, builder_name, name_regexps):
- for name_regexp in name_regexps:
- if re.match(name_regexp, builder_name):
- return True
- return False
-
- # FIXME: Should move onto Builder
- def _is_core_builder(self, builder_name):
- return self._matches_regexps(builder_name, self.core_builder_names_regexps)
-
- # FIXME: This method needs to die, but is used by a unit test at the moment.
- def _builder_statuses_with_names_matching_regexps(self, builder_statuses, name_regexps):
- return [builder for builder in builder_statuses if self._matches_regexps(builder["name"], name_regexps)]
-
- def red_core_builders(self):
- return [builder for builder in self.core_builder_statuses() if not builder["is_green"]]
-
- def red_core_builders_names(self):
- return [builder["name"] for builder in self.red_core_builders()]
-
- def idle_red_core_builders(self):
- return [builder for builder in self.red_core_builders() if builder["activity"] == "idle"]
-
- def core_builders_are_green(self):
- return not self.red_core_builders()
-
- # FIXME: These _fetch methods should move to a networking class.
- def _fetch_xmlrpc_build_dictionary(self, builder, build_number):
- # The buildbot XMLRPC API is super-limited.
- # For one, you cannot fetch info on builds which are incomplete.
- proxy = xmlrpclib.ServerProxy("http://%s/xmlrpc" % self.buildbot_host, allow_none=True)
- try:
- return proxy.getBuild(builder.name(), int(build_number))
- except xmlrpclib.Fault, err:
- build_url = Build.build_url(builder, build_number)
- _log.error("Error fetching data for %s build %s (%s): %s" % (builder.name(), build_number, build_url, err))
- return None
-
- def _fetch_one_box_per_builder(self):
- build_status_url = "http://%s/one_box_per_builder" % self.buildbot_host
- return urllib2.urlopen(build_status_url)
-
- def _file_cell_text(self, file_cell):
- """Traverses down through firstChild elements until one containing a string is found, then returns that string"""
- element = file_cell
- while element.string is None and element.contents:
- element = element.contents[0]
- return element.string
-
- def _parse_twisted_file_row(self, file_row):
- string_or_empty = lambda string: unicode(string) if string else u""
- file_cells = file_row.findAll('td')
- return {
- "filename": string_or_empty(self._file_cell_text(file_cells[0])),
- "size": string_or_empty(self._file_cell_text(file_cells[1])),
- "type": string_or_empty(self._file_cell_text(file_cells[2])),
- "encoding": string_or_empty(self._file_cell_text(file_cells[3])),
- }
-
- def _parse_twisted_directory_listing(self, page):
- soup = BeautifulSoup(page)
- # HACK: Match only table rows with a class to ignore twisted header/footer rows.
- file_rows = soup.find('table').findAll('tr', {'class': re.compile(r'\b(?:directory|file)\b')})
- return [self._parse_twisted_file_row(file_row) for file_row in file_rows]
-
- # FIXME: There should be a better way to get this information directly from twisted.
- def _fetch_twisted_directory_listing(self, url):
- return self._parse_twisted_directory_listing(urllib2.urlopen(url))
-
- def builders(self):
- return [self.builder_with_name(status["name"]) for status in self.builder_statuses()]
-
- # This method pulls from /one_box_per_builder as an efficient way to get information about
- def builder_statuses(self):
- soup = BeautifulSoup(self._fetch_one_box_per_builder())
- return [self._parse_builder_status_from_row(status_row) for status_row in soup.find('table').findAll('tr')]
-
- def core_builder_statuses(self):
- return [builder for builder in self.builder_statuses() if self._is_core_builder(builder["name"])]
-
- def builder_with_name(self, name):
- builder = self._builder_by_name.get(name)
- if not builder:
- builder = Builder(name, self)
- self._builder_by_name[name] = builder
- return builder
-
- def failure_map(self, only_core_builders=True):
- builder_statuses = self.core_builder_statuses() if only_core_builders else self.builder_statuses()
- failure_map = FailureMap()
- revision_to_failing_bots = {}
- for builder_status in builder_statuses:
- if builder_status["is_green"]:
- continue
- builder = self.builder_with_name(builder_status["name"])
- regression_window = builder.find_blameworthy_regression_window(builder_status["build_number"])
- if regression_window:
- failure_map.add_regression_window(builder, regression_window)
- return failure_map
-
- # This makes fewer requests than calling Builder.latest_build would. It grabs all builder
- # statuses in one request using self.builder_statuses (fetching /one_box_per_builder instead of builder pages).
- def _latest_builds_from_builders(self, only_core_builders=True):
- builder_statuses = self.core_builder_statuses() if only_core_builders else self.builder_statuses()
- return [self.builder_with_name(status["name"]).build(status["build_number"]) for status in builder_statuses]
-
- def _build_at_or_before_revision(self, build, revision):
- while build:
- if build.revision() <= revision:
- return build
- build = build.previous_build()
-
- def last_green_revision(self, only_core_builders=True):
- builds = self._latest_builds_from_builders(only_core_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
- continue
- return min_revision
diff --git a/WebKitTools/Scripts/webkitpy/common/net/buildbot_unittest.py b/WebKitTools/Scripts/webkitpy/common/net/buildbot_unittest.py
deleted file mode 100644
index 4fdf24c..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/buildbot_unittest.py
+++ /dev/null
@@ -1,410 +0,0 @@
-# Copyright (C) 2009 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from webkitpy.common.net.buildbot import BuildBot, Builder, Build, LayoutTestResults
-from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup
-
-
-class BuilderTest(unittest.TestCase):
- def _install_fetch_build(self, failure):
- def _mock_fetch_build(build_number):
- build = Build(
- builder=self.builder,
- build_number=build_number,
- revision=build_number + 1000,
- is_green=build_number < 4
- )
- parsed_results = {LayoutTestResults.fail_key: failure(build_number)}
- build._layout_test_results = LayoutTestResults(parsed_results)
- return build
- self.builder._fetch_build = _mock_fetch_build
-
- def setUp(self):
- self.buildbot = BuildBot()
- self.builder = Builder(u"Test Builder \u2661", self.buildbot)
- self._install_fetch_build(lambda build_number: ["test1", "test2"])
-
- def test_find_regression_window(self):
- regression_window = self.builder.find_regression_window(self.builder.build(10))
- self.assertEqual(regression_window.build_before_failure().revision(), 1003)
- self.assertEqual(regression_window.failing_build().revision(), 1004)
-
- regression_window = self.builder.find_regression_window(self.builder.build(10), look_back_limit=2)
- self.assertEqual(regression_window.build_before_failure(), None)
- self.assertEqual(regression_window.failing_build().revision(), 1008)
-
- def test_none_build(self):
- self.builder._fetch_build = lambda build_number: None
- regression_window = self.builder.find_regression_window(self.builder.build(10))
- self.assertEqual(regression_window.build_before_failure(), None)
- self.assertEqual(regression_window.failing_build(), None)
-
- def test_flaky_tests(self):
- self._install_fetch_build(lambda build_number: ["test1"] if build_number % 2 else ["test2"])
- regression_window = self.builder.find_regression_window(self.builder.build(10))
- self.assertEqual(regression_window.build_before_failure().revision(), 1009)
- self.assertEqual(regression_window.failing_build().revision(), 1010)
-
- def test_failure_and_flaky(self):
- self._install_fetch_build(lambda build_number: ["test1", "test2"] if build_number % 2 else ["test2"])
- regression_window = self.builder.find_regression_window(self.builder.build(10))
- self.assertEqual(regression_window.build_before_failure().revision(), 1003)
- self.assertEqual(regression_window.failing_build().revision(), 1004)
-
- def test_no_results(self):
- self._install_fetch_build(lambda build_number: ["test1", "test2"] if build_number % 2 else ["test2"])
- regression_window = self.builder.find_regression_window(self.builder.build(10))
- self.assertEqual(regression_window.build_before_failure().revision(), 1003)
- self.assertEqual(regression_window.failing_build().revision(), 1004)
-
- def test_failure_after_flaky(self):
- self._install_fetch_build(lambda build_number: ["test1", "test2"] if build_number > 6 else ["test3"])
- regression_window = self.builder.find_regression_window(self.builder.build(10))
- self.assertEqual(regression_window.build_before_failure().revision(), 1006)
- self.assertEqual(regression_window.failing_build().revision(), 1007)
-
- def test_find_blameworthy_regression_window(self):
- self.assertEqual(self.builder.find_blameworthy_regression_window(10).revisions(), [1004])
- self.assertEqual(self.builder.find_blameworthy_regression_window(10, look_back_limit=2), None)
- # Flakey test avoidance requires at least 2 red builds:
- self.assertEqual(self.builder.find_blameworthy_regression_window(4), None)
- self.assertEqual(self.builder.find_blameworthy_regression_window(4, avoid_flakey_tests=False).revisions(), [1004])
- # Green builder:
- self.assertEqual(self.builder.find_blameworthy_regression_window(3), None)
-
- def test_build_caching(self):
- self.assertEqual(self.builder.build(10), self.builder.build(10))
-
- def test_build_and_revision_for_filename(self):
- expectations = {
- "r47483 (1)/" : (47483, 1),
- "r47483 (1).zip" : (47483, 1),
- }
- for filename, revision_and_build in expectations.items():
- self.assertEqual(self.builder._revision_and_build_for_filename(filename), revision_and_build)
-
-
-class BuildTest(unittest.TestCase):
- def test_layout_test_results(self):
- build = Build(None, None, None, None)
- build._fetch_results_html = lambda: None
- # Test that layout_test_results() returns None if the fetch fails.
- self.assertEqual(build.layout_test_results(), None)
-
-
-class BuildBotTest(unittest.TestCase):
-
- _example_one_box_status = '''
- <table>
- <tr>
- <td class="box"><a href="builders/Windows%20Debug%20%28Tests%29">Windows Debug (Tests)</a></td>
- <td align="center" class="LastBuild box success"><a href="builders/Windows%20Debug%20%28Tests%29/builds/3693">47380</a><br />build<br />successful</td>
- <td align="center" class="Activity building">building<br />ETA in<br />~ 14 mins<br />at 13:40</td>
- <tr>
- <td class="box"><a href="builders/SnowLeopard%20Intel%20Release">SnowLeopard Intel Release</a></td>
- <td class="LastBuild box" >no build</td>
- <td align="center" class="Activity building">building<br />< 1 min</td>
- <tr>
- <td class="box"><a href="builders/Qt%20Linux%20Release">Qt Linux Release</a></td>
- <td align="center" class="LastBuild box failure"><a href="builders/Qt%20Linux%20Release/builds/654">47383</a><br />failed<br />compile-webkit</td>
- <td align="center" class="Activity idle">idle<br />3 pending</td>
- <tr>
- <td class="box"><a href="builders/Qt%20Windows%2032-bit%20Debug">Qt Windows 32-bit Debug</a></td>
- <td align="center" class="LastBuild box failure"><a href="builders/Qt%20Windows%2032-bit%20Debug/builds/2090">60563</a><br />failed<br />failed<br />slave<br />lost</td>
- <td align="center" class="Activity building">building<br />ETA in<br />~ 5 mins<br />at 08:25</td>
- </table>
-'''
- _expected_example_one_box_parsings = [
- {
- 'is_green': True,
- 'build_number' : 3693,
- 'name': u'Windows Debug (Tests)',
- 'built_revision': 47380,
- 'activity': 'building',
- 'pending_builds': 0,
- },
- {
- 'is_green': False,
- 'build_number' : None,
- 'name': u'SnowLeopard Intel Release',
- 'built_revision': None,
- 'activity': 'building',
- 'pending_builds': 0,
- },
- {
- 'is_green': False,
- 'build_number' : 654,
- 'name': u'Qt Linux Release',
- 'built_revision': 47383,
- 'activity': 'idle',
- 'pending_builds': 3,
- },
- {
- 'is_green': True,
- 'build_number' : 2090,
- 'name': u'Qt Windows 32-bit Debug',
- 'built_revision': 60563,
- 'activity': 'building',
- 'pending_builds': 0,
- },
- ]
-
- def test_status_parsing(self):
- buildbot = BuildBot()
-
- soup = BeautifulSoup(self._example_one_box_status)
- status_table = soup.find("table")
- input_rows = status_table.findAll('tr')
-
- for x in range(len(input_rows)):
- status_row = input_rows[x]
- expected_parsing = self._expected_example_one_box_parsings[x]
-
- builder = buildbot._parse_builder_status_from_row(status_row)
-
- # Make sure we aren't parsing more or less than we expect
- self.assertEquals(builder.keys(), expected_parsing.keys())
-
- for key, expected_value in expected_parsing.items():
- self.assertEquals(builder[key], expected_value, ("Builder %d parse failure for key: %s: Actual='%s' Expected='%s'" % (x, key, builder[key], expected_value)))
-
- def test_core_builder_methods(self):
- buildbot = BuildBot()
-
- # Override builder_statuses function to not touch the network.
- def example_builder_statuses(): # We could use instancemethod() to bind 'self' but we don't need to.
- return BuildBotTest._expected_example_one_box_parsings
- buildbot.builder_statuses = example_builder_statuses
-
- buildbot.core_builder_names_regexps = [ 'Leopard', "Windows.*Build" ]
- self.assertEquals(buildbot.red_core_builders_names(), [])
- self.assertTrue(buildbot.core_builders_are_green())
-
- buildbot.core_builder_names_regexps = [ 'SnowLeopard', 'Qt' ]
- self.assertEquals(buildbot.red_core_builders_names(), [ u'SnowLeopard Intel Release', u'Qt Linux Release' ])
- self.assertFalse(buildbot.core_builders_are_green())
-
- def test_builder_name_regexps(self):
- buildbot = BuildBot()
-
- # For complete testing, this list should match the list of builders at build.webkit.org:
- example_builders = [
- {'name': u'Tiger Intel Release', },
- {'name': u'Leopard Intel Release (Build)', },
- {'name': u'Leopard Intel Release (Tests)', },
- {'name': u'Leopard Intel Debug (Build)', },
- {'name': u'Leopard Intel Debug (Tests)', },
- {'name': u'SnowLeopard Intel Release (Build)', },
- {'name': u'SnowLeopard Intel Release (Tests)', },
- {'name': u'SnowLeopard Intel Release (WebKit2 Tests)', },
- {'name': u'SnowLeopard Intel Leaks', },
- {'name': u'Windows Release (Build)', },
- {'name': u'Windows Release (Tests)', },
- {'name': u'Windows Debug (Build)', },
- {'name': u'Windows Debug (Tests)', },
- {'name': u'GTK Linux 32-bit Release', },
- {'name': u'GTK Linux 32-bit Debug', },
- {'name': u'GTK Linux 64-bit Debug', },
- {'name': u'GTK Linux 64-bit Release', },
- {'name': u'Qt Linux Release', },
- {'name': u'Qt Linux Release minimal', },
- {'name': u'Qt Linux ARMv5 Release', },
- {'name': u'Qt Linux ARMv7 Release', },
- {'name': u'Qt Windows 32-bit Release', },
- {'name': u'Qt Windows 32-bit Debug', },
- {'name': u'Chromium Linux Release', },
- {'name': u'Chromium Mac Release', },
- {'name': u'Chromium Win Release', },
- {'name': u'Chromium Linux Release (Tests)', },
- {'name': u'Chromium Mac Release (Tests)', },
- {'name': u'Chromium Win Release (Tests)', },
- {'name': u'New run-webkit-tests', },
- ]
- name_regexps = [
- "SnowLeopard.*Build",
- "SnowLeopard.*\(Test",
- "Leopard",
- "Tiger",
- "Windows.*Build",
- "GTK.*32",
- "GTK.*64.*Debug", # Disallow the 64-bit Release bot which is broken.
- "Qt",
- "Chromium.*Release$",
- ]
- expected_builders = [
- {'name': u'Tiger Intel Release', },
- {'name': u'Leopard Intel Release (Build)', },
- {'name': u'Leopard Intel Release (Tests)', },
- {'name': u'Leopard Intel Debug (Build)', },
- {'name': u'Leopard Intel Debug (Tests)', },
- {'name': u'SnowLeopard Intel Release (Build)', },
- {'name': u'SnowLeopard Intel Release (Tests)', },
- {'name': u'Windows Release (Build)', },
- {'name': u'Windows Debug (Build)', },
- {'name': u'GTK Linux 32-bit Release', },
- {'name': u'GTK Linux 32-bit Debug', },
- {'name': u'GTK Linux 64-bit Debug', },
- {'name': u'Qt Linux Release', },
- {'name': u'Qt Linux Release minimal', },
- {'name': u'Qt Linux ARMv5 Release', },
- {'name': u'Qt Linux ARMv7 Release', },
- {'name': u'Qt Windows 32-bit Release', },
- {'name': u'Qt Windows 32-bit Debug', },
- {'name': u'Chromium Linux Release', },
- {'name': u'Chromium Mac Release', },
- {'name': u'Chromium Win Release', },
- ]
-
- # This test should probably be updated if the default regexp list changes
- self.assertEquals(buildbot.core_builder_names_regexps, name_regexps)
-
- builders = buildbot._builder_statuses_with_names_matching_regexps(example_builders, name_regexps)
- self.assertEquals(builders, expected_builders)
-
- def test_builder_with_name(self):
- buildbot = BuildBot()
-
- builder = buildbot.builder_with_name("Test Builder")
- self.assertEqual(builder.name(), "Test Builder")
- self.assertEqual(builder.url(), "http://build.webkit.org/builders/Test%20Builder")
- self.assertEqual(builder.url_encoded_name(), "Test%20Builder")
- self.assertEqual(builder.results_url(), "http://build.webkit.org/results/Test%20Builder")
-
- # Override _fetch_xmlrpc_build_dictionary function to not touch the network.
- def mock_fetch_xmlrpc_build_dictionary(self, build_number):
- build_dictionary = {
- "revision" : 2 * build_number,
- "number" : int(build_number),
- "results" : build_number % 2, # 0 means pass
- }
- return build_dictionary
- buildbot._fetch_xmlrpc_build_dictionary = mock_fetch_xmlrpc_build_dictionary
-
- build = builder.build(10)
- self.assertEqual(build.builder(), builder)
- self.assertEqual(build.url(), "http://build.webkit.org/builders/Test%20Builder/builds/10")
- self.assertEqual(build.results_url(), "http://build.webkit.org/results/Test%20Builder/r20%20%2810%29")
- self.assertEqual(build.revision(), 20)
- self.assertEqual(build.is_green(), True)
-
- build = build.previous_build()
- self.assertEqual(build.builder(), builder)
- self.assertEqual(build.url(), "http://build.webkit.org/builders/Test%20Builder/builds/9")
- self.assertEqual(build.results_url(), "http://build.webkit.org/results/Test%20Builder/r18%20%289%29")
- self.assertEqual(build.revision(), 18)
- self.assertEqual(build.is_green(), False)
-
- self.assertEqual(builder.build(None), None)
-
- _example_directory_listing = '''
-<h1>Directory listing for /results/SnowLeopard Intel Leaks/</h1>
-
-<table>
- <tr class="alt">
- <th>Filename</th>
- <th>Size</th>
- <th>Content type</th>
- <th>Content encoding</th>
- </tr>
-<tr class="directory ">
- <td><a href="r47483%20%281%29/"><b>r47483 (1)/</b></a></td>
- <td><b></b></td>
- <td><b>[Directory]</b></td>
- <td><b></b></td>
-</tr>
-<tr class="file alt">
- <td><a href="r47484%20%282%29.zip">r47484 (2).zip</a></td>
- <td>89K</td>
- <td>[application/zip]</td>
- <td></td>
-</tr>
-'''
- _expected_files = [
- {
- "filename" : "r47483 (1)/",
- "size" : "",
- "type" : "[Directory]",
- "encoding" : "",
- },
- {
- "filename" : "r47484 (2).zip",
- "size" : "89K",
- "type" : "[application/zip]",
- "encoding" : "",
- },
- ]
-
- def test_parse_build_to_revision_map(self):
- buildbot = BuildBot()
- 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]
-
- def test_last_green_revision(self):
- buildbot = BuildBot()
- def mock_builds_from_builders(only_core_builders):
- return self._fake_builds_at_index(0)
- buildbot._latest_builds_from_builders = mock_builds_from_builders
- self.assertEqual(buildbot.last_green_revision(), 1)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/net/credentials.py b/WebKitTools/Scripts/webkitpy/common/net/credentials.py
deleted file mode 100644
index 30480b3..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/credentials.py
+++ /dev/null
@@ -1,155 +0,0 @@
-# Copyright (c) 2009 Google Inc. All rights reserved.
-# Copyright (c) 2009 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Python module for reading stored web credentials from the OS.
-
-import getpass
-import os
-import platform
-import re
-
-from webkitpy.common.checkout.scm import Git
-from webkitpy.common.system.executive import Executive, ScriptError
-from webkitpy.common.system.user import User
-from webkitpy.common.system.deprecated_logging import log
-
-try:
- # Use keyring, a cross platform keyring interface, as a fallback:
- # http://pypi.python.org/pypi/keyring
- import keyring
-except ImportError:
- keyring = None
-
-
-class Credentials(object):
- _environ_prefix = "webkit_bugzilla_"
-
- def __init__(self, host, git_prefix=None, executive=None, cwd=os.getcwd(),
- keyring=keyring):
- self.host = host
- self.git_prefix = "%s." % git_prefix if git_prefix else ""
- self.executive = executive or Executive()
- self.cwd = cwd
- self._keyring = keyring
-
- def _credentials_from_git(self):
- try:
- if not Git.in_working_directory(self.cwd):
- return (None, None)
- return (Git.read_git_config(self.git_prefix + "username"),
- Git.read_git_config(self.git_prefix + "password"))
- except OSError, e:
- # Catch and ignore OSError exceptions such as "no such file
- # or directory" (OSError errno 2), which imply that the Git
- # command cannot be found/is not installed.
- pass
- return (None, None)
-
- def _keychain_value_with_label(self, label, source_text):
- match = re.search("%s\"(?P<value>.+)\"" % label,
- source_text,
- re.MULTILINE)
- if match:
- return match.group('value')
-
- def _is_mac_os_x(self):
- return platform.mac_ver()[0]
-
- def _parse_security_tool_output(self, security_output):
- username = self._keychain_value_with_label("^\s*\"acct\"<blob>=",
- security_output)
- password = self._keychain_value_with_label("^password: ",
- security_output)
- return [username, password]
-
- def _run_security_tool(self, username=None):
- security_command = [
- "/usr/bin/security",
- "find-internet-password",
- "-g",
- "-s",
- self.host,
- ]
- if username:
- security_command += ["-a", username]
-
- log("Reading Keychain for %s account and password. "
- "Click \"Allow\" to continue..." % self.host)
- try:
- return self.executive.run_command(security_command)
- except ScriptError:
- # Failed to either find a keychain entry or somekind of OS-related
- # error occured (for instance, couldn't find the /usr/sbin/security
- # command).
- log("Could not find a keychain entry for %s." % self.host)
- return None
-
- def _credentials_from_keychain(self, username=None):
- if not self._is_mac_os_x():
- return [username, None]
-
- security_output = self._run_security_tool(username)
- if security_output:
- return self._parse_security_tool_output(security_output)
- else:
- return [None, None]
-
- def _read_environ(self, key):
- environ_key = self._environ_prefix + key
- return os.environ.get(environ_key.upper())
-
- def _credentials_from_environment(self):
- return (self._read_environ("username"), self._read_environ("password"))
-
- def _offer_to_store_credentials_in_keyring(self, username, password):
- if not self._keyring:
- return
- if not User().confirm("Store password in system keyring?", User.DEFAULT_NO):
- return
- self._keyring.set_password(self.host, username, password)
-
- def read_credentials(self):
- username, password = self._credentials_from_environment()
- # FIXME: We don't currently support pulling the username from one
- # source and the password from a separate source.
- if not username or not password:
- username, password = self._credentials_from_git()
- if not username or not password:
- username, password = self._credentials_from_keychain(username)
-
- if username and not password and self._keyring:
- password = self._keyring.get_password(self.host, username)
-
- if not username:
- username = User.prompt("%s login: " % self.host)
- if not password:
- password = getpass.getpass("%s password for %s: " % (self.host, username))
- self._offer_to_store_credentials_in_keyring(username, password)
-
- return (username, password)
diff --git a/WebKitTools/Scripts/webkitpy/common/net/credentials_unittest.py b/WebKitTools/Scripts/webkitpy/common/net/credentials_unittest.py
deleted file mode 100644
index 6f2d909..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/credentials_unittest.py
+++ /dev/null
@@ -1,176 +0,0 @@
-# Copyright (C) 2009 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-from __future__ import with_statement
-
-import os
-import tempfile
-import unittest
-from webkitpy.common.net.credentials import Credentials
-from webkitpy.common.system.executive import Executive
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.thirdparty.mock import Mock
-
-
-# FIXME: Other unit tests probably want this class.
-class _TemporaryDirectory(object):
- def __init__(self, **kwargs):
- self._kwargs = kwargs
- self._directory_path = None
-
- def __enter__(self):
- self._directory_path = tempfile.mkdtemp(**self._kwargs)
- return self._directory_path
-
- def __exit__(self, type, value, traceback):
- os.rmdir(self._directory_path)
-
-
-class CredentialsTest(unittest.TestCase):
- example_security_output = """keychain: "/Users/test/Library/Keychains/login.keychain"
-class: "inet"
-attributes:
- 0x00000007 <blob>="bugs.webkit.org (test@webkit.org)"
- 0x00000008 <blob>=<NULL>
- "acct"<blob>="test@webkit.org"
- "atyp"<blob>="form"
- "cdat"<timedate>=0x32303039303832353233353231365A00 "20090825235216Z\000"
- "crtr"<uint32>=<NULL>
- "cusi"<sint32>=<NULL>
- "desc"<blob>="Web form password"
- "icmt"<blob>="default"
- "invi"<sint32>=<NULL>
- "mdat"<timedate>=0x32303039303930393137323635315A00 "20090909172651Z\000"
- "nega"<sint32>=<NULL>
- "path"<blob>=<NULL>
- "port"<uint32>=0x00000000
- "prot"<blob>=<NULL>
- "ptcl"<uint32>="htps"
- "scrp"<sint32>=<NULL>
- "sdmn"<blob>=<NULL>
- "srvr"<blob>="bugs.webkit.org"
- "type"<uint32>=<NULL>
-password: "SECRETSAUCE"
-"""
-
- def test_keychain_lookup_on_non_mac(self):
- class FakeCredentials(Credentials):
- def _is_mac_os_x(self):
- return False
- credentials = FakeCredentials("bugs.webkit.org")
- self.assertEqual(credentials._is_mac_os_x(), False)
- self.assertEqual(credentials._credentials_from_keychain("foo"), ["foo", None])
-
- def test_security_output_parse(self):
- credentials = Credentials("bugs.webkit.org")
- self.assertEqual(credentials._parse_security_tool_output(self.example_security_output), ["test@webkit.org", "SECRETSAUCE"])
-
- def test_security_output_parse_entry_not_found(self):
- credentials = Credentials("foo.example.com")
- if not credentials._is_mac_os_x():
- return # This test does not run on a non-Mac.
-
- # Note, we ignore the captured output because it is already covered
- # by the test case CredentialsTest._assert_security_call (below).
- outputCapture = OutputCapture()
- outputCapture.capture_output()
- self.assertEqual(credentials._run_security_tool(), None)
- outputCapture.restore_output()
-
- def _assert_security_call(self, username=None):
- executive_mock = Mock()
- credentials = Credentials("example.com", executive=executive_mock)
-
- expected_stderr = "Reading Keychain for example.com account and password. Click \"Allow\" to continue...\n"
- OutputCapture().assert_outputs(self, credentials._run_security_tool, [username], expected_stderr=expected_stderr)
-
- security_args = ["/usr/bin/security", "find-internet-password", "-g", "-s", "example.com"]
- if username:
- security_args += ["-a", username]
- executive_mock.run_command.assert_called_with(security_args)
-
- def test_security_calls(self):
- self._assert_security_call()
- self._assert_security_call(username="foo")
-
- def test_credentials_from_environment(self):
- executive_mock = Mock()
- credentials = Credentials("example.com", executive=executive_mock)
-
- saved_environ = os.environ.copy()
- os.environ['WEBKIT_BUGZILLA_USERNAME'] = "foo"
- os.environ['WEBKIT_BUGZILLA_PASSWORD'] = "bar"
- username, password = credentials._credentials_from_environment()
- self.assertEquals(username, "foo")
- self.assertEquals(password, "bar")
- os.environ = saved_environ
-
- def test_read_credentials_without_git_repo(self):
- # FIXME: This should share more code with test_keyring_without_git_repo
- class FakeCredentials(Credentials):
- def _is_mac_os_x(self):
- return True
-
- def _credentials_from_keychain(self, username):
- return ("test@webkit.org", "SECRETSAUCE")
-
- def _credentials_from_environment(self):
- return (None, None)
-
- with _TemporaryDirectory(suffix="not_a_git_repo") as temp_dir_path:
- credentials = FakeCredentials("bugs.webkit.org", cwd=temp_dir_path)
- # FIXME: Using read_credentials here seems too broad as higher-priority
- # credential source could be affected by the user's environment.
- self.assertEqual(credentials.read_credentials(), ("test@webkit.org", "SECRETSAUCE"))
-
-
- def test_keyring_without_git_repo(self):
- # FIXME: This should share more code with test_read_credentials_without_git_repo
- class MockKeyring(object):
- def get_password(self, host, username):
- return "NOMNOMNOM"
-
- class FakeCredentials(Credentials):
- def _is_mac_os_x(self):
- return True
-
- def _credentials_from_keychain(self, username):
- return ("test@webkit.org", None)
-
- def _credentials_from_environment(self):
- return (None, None)
-
- with _TemporaryDirectory(suffix="not_a_git_repo") as temp_dir_path:
- credentials = FakeCredentials("fake.hostname", cwd=temp_dir_path, keyring=MockKeyring())
- # FIXME: Using read_credentials here seems too broad as higher-priority
- # credential source could be affected by the user's environment.
- self.assertEqual(credentials.read_credentials(), ("test@webkit.org", "NOMNOMNOM"))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/net/failuremap.py b/WebKitTools/Scripts/webkitpy/common/net/failuremap.py
deleted file mode 100644
index e2d53ae..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/failuremap.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-class FailureMap(object):
- def __init__(self):
- self._failures = []
-
- def add_regression_window(self, builder, regression_window):
- self._failures.append({
- 'builder': builder,
- 'regression_window': regression_window,
- })
-
- def is_empty(self):
- return not self._failures
-
- def failing_revisions(self):
- failing_revisions = [failure_info['regression_window'].revisions()
- for failure_info in self._failures]
- return sorted(set(sum(failing_revisions, [])))
-
- def builders_failing_for(self, revision):
- return self._builders_failing_because_of([revision])
-
- def tests_failing_for(self, revision):
- tests = [failure_info['regression_window'].failing_tests()
- for failure_info in self._failures
- if revision in failure_info['regression_window'].revisions()
- and failure_info['regression_window'].failing_tests()]
- result = set()
- for test in tests:
- result = result.union(test)
- return sorted(result)
-
- def _old_failures(self, is_old_failure):
- return filter(lambda revision: is_old_failure(revision),
- self.failing_revisions())
-
- def _builders_failing_because_of(self, revisions):
- revision_set = set(revisions)
- return [failure_info['builder'] for failure_info in self._failures
- if revision_set.intersection(
- failure_info['regression_window'].revisions())]
-
- # FIXME: We should re-process old failures after some time delay.
- # https://bugs.webkit.org/show_bug.cgi?id=36581
- def filter_out_old_failures(self, is_old_failure):
- old_failures = self._old_failures(is_old_failure)
- old_failing_builder_names = set([builder.name()
- for builder in self._builders_failing_because_of(old_failures)])
-
- # We filter out all the failing builders that could have been caused
- # by old_failures. We could miss some new failures this way, but
- # emperically, this reduces the amount of spam we generate.
- failures = self._failures
- self._failures = [failure_info for failure_info in failures
- if failure_info['builder'].name() not in old_failing_builder_names]
- self._cache = {}
diff --git a/WebKitTools/Scripts/webkitpy/common/net/failuremap_unittest.py b/WebKitTools/Scripts/webkitpy/common/net/failuremap_unittest.py
deleted file mode 100644
index 2f0b49d..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/failuremap_unittest.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from webkitpy.common.net.buildbot import Build
-from webkitpy.common.net.failuremap import *
-from webkitpy.common.net.regressionwindow import RegressionWindow
-from webkitpy.tool.mocktool import MockBuilder
-
-
-class FailureMapTest(unittest.TestCase):
- builder1 = MockBuilder("Builder1")
- builder2 = MockBuilder("Builder2")
-
- build1a = Build(builder1, build_number=22, revision=1233, is_green=True)
- build1b = Build(builder1, build_number=23, revision=1234, is_green=False)
- build2a = Build(builder2, build_number=89, revision=1233, is_green=True)
- build2b = Build(builder2, build_number=90, revision=1235, is_green=False)
-
- regression_window1 = RegressionWindow(build1a, build1b, failing_tests=[u'test1', u'test1'])
- regression_window2 = RegressionWindow(build2a, build2b, failing_tests=[u'test1'])
-
- def _make_failure_map(self):
- failure_map = FailureMap()
- failure_map.add_regression_window(self.builder1, self.regression_window1)
- failure_map.add_regression_window(self.builder2, self.regression_window2)
- return failure_map
-
- def test_failing_revisions(self):
- failure_map = self._make_failure_map()
- self.assertEquals(failure_map.failing_revisions(), [1234, 1235])
-
- def test_new_failures(self):
- failure_map = self._make_failure_map()
- failure_map.filter_out_old_failures(lambda revision: False)
- self.assertEquals(failure_map.failing_revisions(), [1234, 1235])
-
- def test_new_failures_with_old_revisions(self):
- failure_map = self._make_failure_map()
- failure_map.filter_out_old_failures(lambda revision: revision == 1234)
- self.assertEquals(failure_map.failing_revisions(), [])
-
- def test_new_failures_with_more_old_revisions(self):
- failure_map = self._make_failure_map()
- failure_map.filter_out_old_failures(lambda revision: revision == 1235)
- self.assertEquals(failure_map.failing_revisions(), [1234])
-
- def test_tests_failing_for(self):
- failure_map = self._make_failure_map()
- self.assertEquals(failure_map.tests_failing_for(1234), [u'test1'])
diff --git a/WebKitTools/Scripts/webkitpy/common/net/irc/__init__.py b/WebKitTools/Scripts/webkitpy/common/net/irc/__init__.py
deleted file mode 100644
index ef65bee..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/irc/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Required for Python to search this directory for module files
diff --git a/WebKitTools/Scripts/webkitpy/common/net/irc/ircbot.py b/WebKitTools/Scripts/webkitpy/common/net/irc/ircbot.py
deleted file mode 100644
index f742867..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/irc/ircbot.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import webkitpy.common.config.irc as config_irc
-
-from webkitpy.common.thread.messagepump import MessagePump, MessagePumpDelegate
-from webkitpy.thirdparty.autoinstalled.irc import ircbot
-from webkitpy.thirdparty.autoinstalled.irc import irclib
-
-
-class IRCBotDelegate(object):
- def irc_message_received(self, nick, message):
- raise NotImplementedError, "subclasses must implement"
-
- def irc_nickname(self):
- raise NotImplementedError, "subclasses must implement"
-
- def irc_password(self):
- raise NotImplementedError, "subclasses must implement"
-
-
-class IRCBot(ircbot.SingleServerIRCBot, MessagePumpDelegate):
- # FIXME: We should get this information from a config file.
- def __init__(self,
- message_queue,
- delegate):
- self._message_queue = message_queue
- self._delegate = delegate
- ircbot.SingleServerIRCBot.__init__(
- self,
- [(
- config_irc.server,
- config_irc.port,
- self._delegate.irc_password()
- )],
- self._delegate.irc_nickname(),
- self._delegate.irc_nickname())
- self._channel = config_irc.channel
-
- # ircbot.SingleServerIRCBot methods
-
- def on_nicknameinuse(self, connection, event):
- connection.nick(connection.get_nickname() + "_")
-
- def on_welcome(self, connection, event):
- connection.join(self._channel)
- self._message_pump = MessagePump(self, self._message_queue)
-
- def on_pubmsg(self, connection, event):
- nick = irclib.nm_to_n(event.source())
- request = event.arguments()[0].split(":", 1)
- if len(request) > 1 and irclib.irc_lower(request[0]) == irclib.irc_lower(self.connection.get_nickname()):
- response = self._delegate.irc_message_received(nick, request[1])
- if response:
- connection.privmsg(self._channel, response)
-
- # MessagePumpDelegate methods
-
- def schedule(self, interval, callback):
- self.connection.execute_delayed(interval, callback)
-
- def message_available(self, message):
- self.connection.privmsg(self._channel, message)
-
- def final_message_delivered(self):
- self.die()
diff --git a/WebKitTools/Scripts/webkitpy/common/net/irc/ircproxy.py b/WebKitTools/Scripts/webkitpy/common/net/irc/ircproxy.py
deleted file mode 100644
index 13348b4..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/irc/ircproxy.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import threading
-
-from webkitpy.common.net.irc.ircbot import IRCBot
-from webkitpy.common.thread.threadedmessagequeue import ThreadedMessageQueue
-from webkitpy.common.system.deprecated_logging import log
-
-
-class _IRCThread(threading.Thread):
- def __init__(self, message_queue, irc_delegate, irc_bot):
- threading.Thread.__init__(self)
- self.setDaemon(True)
- self._message_queue = message_queue
- self._irc_delegate = irc_delegate
- self._irc_bot = irc_bot
-
- def run(self):
- bot = self._irc_bot(self._message_queue, self._irc_delegate)
- bot.start()
-
-
-class IRCProxy(object):
- def __init__(self, irc_delegate, irc_bot=IRCBot):
- log("Connecting to IRC")
- self._message_queue = ThreadedMessageQueue()
- self._child_thread = _IRCThread(self._message_queue, irc_delegate, irc_bot)
- self._child_thread.start()
-
- def post(self, message):
- self._message_queue.post(message)
-
- def disconnect(self):
- log("Disconnecting from IRC...")
- self._message_queue.stop()
- self._child_thread.join()
diff --git a/WebKitTools/Scripts/webkitpy/common/net/irc/ircproxy_unittest.py b/WebKitTools/Scripts/webkitpy/common/net/irc/ircproxy_unittest.py
deleted file mode 100644
index b44ce40..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/irc/ircproxy_unittest.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from webkitpy.common.net.irc.ircproxy import IRCProxy
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.thirdparty.mock import Mock
-
-class IRCProxyTest(unittest.TestCase):
- def test_trivial(self):
- def fun():
- proxy = IRCProxy(Mock(), Mock())
- proxy.post("hello")
- proxy.disconnect()
-
- expected_stderr = "Connecting to IRC\nDisconnecting from IRC...\n"
- OutputCapture().assert_outputs(self, fun, expected_stderr=expected_stderr)
diff --git a/WebKitTools/Scripts/webkitpy/common/net/layouttestresults.py b/WebKitTools/Scripts/webkitpy/common/net/layouttestresults.py
deleted file mode 100644
index a7b3b0a..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/layouttestresults.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# A module for parsing results.html files generated by old-run-webkit-tests
-
-from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup, SoupStrainer
-
-
-# FIXME: This should be unified with all the layout test results code in the layout_tests package
-# This doesn't belong in common.net, but we don't have a better place for it yet.
-def path_for_layout_test(test_name):
- return "LayoutTests/%s" % test_name
-
-
-# FIXME: This should be unified with all the layout test results code in the layout_tests package
-# This doesn't belong in common.net, but we don't have a better place for it yet.
-class LayoutTestResults(object):
- """This class knows how to parse old-run-webkit-tests results.html files."""
-
- stderr_key = u'Tests that had stderr output:'
- fail_key = u'Tests where results did not match expected results:'
- timeout_key = u'Tests that timed out:'
- crash_key = u'Tests that caused the DumpRenderTree tool to crash:'
- missing_key = u'Tests that had no expected results (probably new):'
-
- expected_keys = [
- stderr_key,
- fail_key,
- crash_key,
- timeout_key,
- missing_key,
- ]
-
- @classmethod
- def _parse_results_html(cls, page):
- if not page:
- return None
- parsed_results = {}
- tables = BeautifulSoup(page).findAll("table")
- for table in tables:
- table_title = unicode(table.findPreviousSibling("p").string)
- if table_title not in cls.expected_keys:
- # This Exception should only ever be hit if run-webkit-tests changes its results.html format.
- raise Exception("Unhandled title: %s" % table_title)
- # We might want to translate table titles into identifiers before storing.
- parsed_results[table_title] = [unicode(row.find("a").string) for row in table.findAll("tr")]
-
- return parsed_results
-
- @classmethod
- def results_from_string(cls, string):
- parsed_results = cls._parse_results_html(string)
- if not parsed_results:
- return None
- return cls(parsed_results)
-
- def __init__(self, parsed_results):
- self._parsed_results = parsed_results
-
- def parsed_results(self):
- return self._parsed_results
-
- def failing_tests(self):
- failing_keys = [self.fail_key, self.crash_key, self.timeout_key]
- return sorted(sum([tests for key, tests in self._parsed_results.items() if key in failing_keys], []))
diff --git a/WebKitTools/Scripts/webkitpy/common/net/layouttestresults_unittest.py b/WebKitTools/Scripts/webkitpy/common/net/layouttestresults_unittest.py
deleted file mode 100644
index 8490eae..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/layouttestresults_unittest.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from webkitpy.common.net.layouttestresults import LayoutTestResults
-
-
-class LayoutTestResultsTest(unittest.TestCase):
- _example_results_html = """
-<html>
-<head>
-<title>Layout Test Results</title>
-</head>
-<body>
-<p>Tests that had stderr output:</p>
-<table>
-<tr>
-<td><a href="/var/lib/buildbot/build/gtk-linux-64-release/build/LayoutTests/accessibility/aria-activedescendant-crash.html">accessibility/aria-activedescendant-crash.html</a></td>
-<td><a href="accessibility/aria-activedescendant-crash-stderr.txt">stderr</a></td>
-</tr>
-<td><a href="/var/lib/buildbot/build/gtk-linux-64-release/build/LayoutTests/http/tests/security/canvas-remote-read-svg-image.html">http/tests/security/canvas-remote-read-svg-image.html</a></td>
-<td><a href="http/tests/security/canvas-remote-read-svg-image-stderr.txt">stderr</a></td>
-</tr>
-</table><p>Tests that had no expected results (probably new):</p>
-<table>
-<tr>
-<td><a href="/var/lib/buildbot/build/gtk-linux-64-release/build/LayoutTests/fast/repaint/no-caret-repaint-in-non-content-editable-element.html">fast/repaint/no-caret-repaint-in-non-content-editable-element.html</a></td>
-<td><a href="fast/repaint/no-caret-repaint-in-non-content-editable-element-actual.txt">result</a></td>
-</tr>
-</table></body>
-</html>
-"""
-
- _expected_layout_test_results = {
- 'Tests that had stderr output:': [
- 'accessibility/aria-activedescendant-crash.html',
- ],
- 'Tests that had no expected results (probably new):': [
- 'fast/repaint/no-caret-repaint-in-non-content-editable-element.html',
- ],
- }
-
- def test_parse_layout_test_results(self):
- results = LayoutTestResults._parse_results_html(self._example_results_html)
- self.assertEqual(self._expected_layout_test_results, results)
-
- def test_results_from_string(self):
- self.assertEqual(LayoutTestResults.results_from_string(None), None)
- self.assertEqual(LayoutTestResults.results_from_string(""), None)
- results = LayoutTestResults.results_from_string(self._example_results_html)
- self.assertEqual(len(results.failing_tests()), 0)
diff --git a/WebKitTools/Scripts/webkitpy/common/net/networktransaction.py b/WebKitTools/Scripts/webkitpy/common/net/networktransaction.py
deleted file mode 100644
index de19e94..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/networktransaction.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import logging
-import time
-
-from webkitpy.thirdparty.autoinstalled import mechanize
-from webkitpy.common.system.deprecated_logging import log
-
-
-_log = logging.getLogger(__name__)
-
-
-class NetworkTimeout(Exception):
- pass
-
-
-class NetworkTransaction(object):
- def __init__(self, initial_backoff_seconds=10, grown_factor=1.5, timeout_seconds=(10 * 60), convert_404_to_None=False):
- self._initial_backoff_seconds = initial_backoff_seconds
- self._grown_factor = grown_factor
- self._timeout_seconds = timeout_seconds
- self._convert_404_to_None = convert_404_to_None
-
- def run(self, request):
- self._total_sleep = 0
- self._backoff_seconds = self._initial_backoff_seconds
- while True:
- try:
- return request()
- # FIXME: We should catch urllib2.HTTPError here too.
- except mechanize.HTTPError, e:
- if self._convert_404_to_None and e.code == 404:
- return None
- self._check_for_timeout()
- _log.warn("Received HTTP status %s from server. Retrying in "
- "%s seconds..." % (e.code, self._backoff_seconds))
- self._sleep()
-
- def _check_for_timeout(self):
- if self._total_sleep + self._backoff_seconds > self._timeout_seconds:
- raise NetworkTimeout()
-
- def _sleep(self):
- time.sleep(self._backoff_seconds)
- self._total_sleep += self._backoff_seconds
- self._backoff_seconds *= self._grown_factor
diff --git a/WebKitTools/Scripts/webkitpy/common/net/networktransaction_unittest.py b/WebKitTools/Scripts/webkitpy/common/net/networktransaction_unittest.py
deleted file mode 100644
index 49aaeed..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/networktransaction_unittest.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from webkitpy.common.net.networktransaction import NetworkTransaction, NetworkTimeout
-from webkitpy.common.system.logtesting import LoggingTestCase
-from webkitpy.thirdparty.autoinstalled.mechanize import HTTPError
-
-
-class NetworkTransactionTest(LoggingTestCase):
- exception = Exception("Test exception")
-
- def test_success(self):
- transaction = NetworkTransaction()
- self.assertEqual(transaction.run(lambda: 42), 42)
-
- def _raise_exception(self):
- raise self.exception
-
- def test_exception(self):
- transaction = NetworkTransaction()
- did_process_exception = False
- did_throw_exception = True
- try:
- transaction.run(lambda: self._raise_exception())
- did_throw_exception = False
- except Exception, e:
- did_process_exception = True
- self.assertEqual(e, self.exception)
- self.assertTrue(did_throw_exception)
- self.assertTrue(did_process_exception)
-
- def _raise_500_error(self):
- self._run_count += 1
- if self._run_count < 3:
- raise HTTPError("http://example.com/", 500, "internal server error", None, None)
- return 42
-
- def _raise_404_error(self):
- raise HTTPError("http://foo.com/", 404, "not found", None, None)
-
- def test_retry(self):
- self._run_count = 0
- transaction = NetworkTransaction(initial_backoff_seconds=0)
- self.assertEqual(transaction.run(lambda: self._raise_500_error()), 42)
- self.assertEqual(self._run_count, 3)
- self.assertLog(['WARNING: Received HTTP status 500 from server. '
- 'Retrying in 0 seconds...\n',
- 'WARNING: Received HTTP status 500 from server. '
- 'Retrying in 0.0 seconds...\n'])
-
- def test_convert_404_to_None(self):
- transaction = NetworkTransaction(convert_404_to_None=True)
- self.assertEqual(transaction.run(lambda: self._raise_404_error()), None)
-
- def test_timeout(self):
- self._run_count = 0
- transaction = NetworkTransaction(initial_backoff_seconds=60*60, timeout_seconds=60)
- did_process_exception = False
- did_throw_exception = True
- try:
- transaction.run(lambda: self._raise_500_error())
- did_throw_exception = False
- except NetworkTimeout, e:
- did_process_exception = True
- self.assertTrue(did_throw_exception)
- self.assertTrue(did_process_exception)
diff --git a/WebKitTools/Scripts/webkitpy/common/net/regressionwindow.py b/WebKitTools/Scripts/webkitpy/common/net/regressionwindow.py
deleted file mode 100644
index ad89815..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/regressionwindow.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-class RegressionWindow(object):
- def __init__(self, build_before_failure, failing_build, failing_tests=None):
- self._build_before_failure = build_before_failure
- self._failing_build = failing_build
- self._failing_tests = failing_tests
- self._revisions = None
-
- def build_before_failure(self):
- return self._build_before_failure
-
- def failing_build(self):
- return self._failing_build
-
- def failing_tests(self):
- return self._failing_tests
-
- def revisions(self):
- # Cache revisions to avoid excessive allocations.
- if not self._revisions:
- self._revisions = range(self._failing_build.revision(), self._build_before_failure.revision(), -1)
- self._revisions.reverse()
- return self._revisions
diff --git a/WebKitTools/Scripts/webkitpy/common/net/statusserver.py b/WebKitTools/Scripts/webkitpy/common/net/statusserver.py
deleted file mode 100644
index 64dd77b..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/statusserver.py
+++ /dev/null
@@ -1,160 +0,0 @@
-# Copyright (C) 2009 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-from webkitpy.common.net.networktransaction import NetworkTransaction
-from webkitpy.common.system.deprecated_logging import log
-from webkitpy.thirdparty.autoinstalled.mechanize import Browser
-from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup
-
-import logging
-import urllib2
-
-
-_log = logging.getLogger("webkitpy.common.net.statusserver")
-
-
-class StatusServer:
- default_host = "queues.webkit.org"
-
- def __init__(self, host=default_host, browser=None, bot_id=None):
- self.set_host(host)
- self._browser = browser or Browser()
- self.set_bot_id(bot_id)
-
- def set_host(self, host):
- self.host = host
- self.url = "http://%s" % self.host
-
- def set_bot_id(self, bot_id):
- self.bot_id = bot_id
-
- def results_url_for_status(self, status_id):
- return "%s/results/%s" % (self.url, status_id)
-
- def _add_patch(self, patch):
- if not patch:
- return
- if patch.bug_id():
- self._browser["bug_id"] = unicode(patch.bug_id())
- if patch.id():
- self._browser["patch_id"] = unicode(patch.id())
-
- def _add_results_file(self, results_file):
- if not results_file:
- return
- self._browser.add_file(results_file, "text/plain", "results.txt", 'results_file')
-
- def _post_status_to_server(self, queue_name, status, patch, results_file):
- if results_file:
- # We might need to re-wind the file if we've already tried to post it.
- results_file.seek(0)
-
- update_status_url = "%s/update-status" % self.url
- self._browser.open(update_status_url)
- self._browser.select_form(name="update_status")
- self._browser["queue_name"] = queue_name
- if self.bot_id:
- self._browser["bot_id"] = self.bot_id
- self._add_patch(patch)
- self._browser["status"] = status
- self._add_results_file(results_file)
- return self._browser.submit().read() # This is the id of the newly created status object.
-
- def _post_svn_revision_to_server(self, svn_revision_number, broken_bot):
- update_svn_revision_url = "%s/update-svn-revision" % self.url
- self._browser.open(update_svn_revision_url)
- self._browser.select_form(name="update_svn_revision")
- self._browser["number"] = unicode(svn_revision_number)
- self._browser["broken_bot"] = broken_bot
- return self._browser.submit().read()
-
- def _post_work_items_to_server(self, queue_name, work_items):
- update_work_items_url = "%s/update-work-items" % self.url
- self._browser.open(update_work_items_url)
- self._browser.select_form(name="update_work_items")
- self._browser["queue_name"] = queue_name
- work_items = map(unicode, work_items) # .join expects strings
- self._browser["work_items"] = " ".join(work_items)
- return self._browser.submit().read()
-
- def _post_work_item_to_ews(self, attachment_id):
- submit_to_ews_url = "%s/submit-to-ews" % self.url
- self._browser.open(submit_to_ews_url)
- self._browser.select_form(name="submit_to_ews")
- self._browser["attachment_id"] = unicode(attachment_id)
- self._browser.submit()
-
- def submit_to_ews(self, attachment_id):
- _log.info("Submitting attachment %s to EWS queues" % attachment_id)
- return NetworkTransaction().run(lambda: self._post_work_item_to_ews(attachment_id))
-
- def next_work_item(self, queue_name):
- _log.debug("Fetching next work item for %s" % queue_name)
- patch_status_url = "%s/next-patch/%s" % (self.url, queue_name)
- return self._fetch_url(patch_status_url)
-
- def _post_release_work_item(self, queue_name, patch):
- release_patch_url = "%s/release-patch" % (self.url)
- self._browser.open(release_patch_url)
- self._browser.select_form(name="release_patch")
- self._browser["queue_name"] = queue_name
- self._browser["attachment_id"] = unicode(patch.id())
- self._browser.submit()
-
- def release_work_item(self, queue_name, patch):
- _log.info("Releasing work item %s from %s" % (patch.id(), queue_name))
- return NetworkTransaction(convert_404_to_None=True).run(lambda: self._post_release_work_item(queue_name, patch))
-
- def update_work_items(self, queue_name, work_items):
- _log.debug("Recording work items: %s for %s" % (work_items, queue_name))
- return NetworkTransaction().run(lambda: self._post_work_items_to_server(queue_name, work_items))
-
- def update_status(self, queue_name, status, patch=None, results_file=None):
- log(status)
- return NetworkTransaction().run(lambda: self._post_status_to_server(queue_name, status, patch, results_file))
-
- def update_svn_revision(self, svn_revision_number, broken_bot):
- log("SVN revision: %s broke %s" % (svn_revision_number, broken_bot))
- return NetworkTransaction().run(lambda: self._post_svn_revision_to_server(svn_revision_number, broken_bot))
-
- def _fetch_url(self, url):
- # FIXME: This should use NetworkTransaction's 404 handling instead.
- try:
- return urllib2.urlopen(url).read()
- except urllib2.HTTPError, e:
- if e.code == 404:
- return None
- raise e
-
- def patch_status(self, queue_name, patch_id):
- patch_status_url = "%s/patch-status/%s/%s" % (self.url, queue_name, patch_id)
- return self._fetch_url(patch_status_url)
-
- def svn_revision(self, svn_revision_number):
- svn_revision_url = "%s/svn-revision/%s" % (self.url, svn_revision_number)
- return self._fetch_url(svn_revision_url)
diff --git a/WebKitTools/Scripts/webkitpy/common/net/statusserver_unittest.py b/WebKitTools/Scripts/webkitpy/common/net/statusserver_unittest.py
deleted file mode 100644
index 1169ba0..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/statusserver_unittest.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from webkitpy.common.net.statusserver import StatusServer
-from webkitpy.common.system.outputcapture import OutputCaptureTestCaseBase
-from webkitpy.tool.mocktool import MockBrowser
-
-
-class StatusServerTest(OutputCaptureTestCaseBase):
- def test_url_for_issue(self):
- mock_browser = MockBrowser()
- status_server = StatusServer(browser=mock_browser, bot_id='123')
- status_server.update_status('queue name', 'the status')
- self.assertEqual('queue name', mock_browser.params['queue_name'])
- self.assertEqual('the status', mock_browser.params['status'])
- self.assertEqual('123', mock_browser.params['bot_id'])
diff --git a/WebKitTools/Scripts/webkitpy/common/newstringio.py b/WebKitTools/Scripts/webkitpy/common/newstringio.py
deleted file mode 100644
index f6d08ec..0000000
--- a/WebKitTools/Scripts/webkitpy/common/newstringio.py
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/env python
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""'with'-compliant StringIO implementation."""
-
-import StringIO
-
-
-class StringIO(StringIO.StringIO):
- def __enter__(self):
- return self
-
- def __exit__(self, type, value, traceback):
- pass
diff --git a/WebKitTools/Scripts/webkitpy/common/newstringio_unittest.py b/WebKitTools/Scripts/webkitpy/common/newstringio_unittest.py
deleted file mode 100644
index 5755c98..0000000
--- a/WebKitTools/Scripts/webkitpy/common/newstringio_unittest.py
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Unit tests for newstringio module."""
-
-from __future__ import with_statement
-
-import unittest
-
-import newstringio
-
-
-class NewStringIOTest(unittest.TestCase):
- def test_with(self):
- with newstringio.StringIO("foo") as f:
- contents = f.read()
- self.assertEqual(contents, "foo")
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/prettypatch.py b/WebKitTools/Scripts/webkitpy/common/prettypatch.py
deleted file mode 100644
index 4e92a53..0000000
--- a/WebKitTools/Scripts/webkitpy/common/prettypatch.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import os
-import tempfile
-
-
-class PrettyPatch(object):
- # FIXME: PrettyPatch should not require checkout_root.
- def __init__(self, executive, checkout_root):
- self._executive = executive
- self._checkout_root = checkout_root
-
- def pretty_diff_file(self, diff):
- # Diffs can contain multiple text files of different encodings
- # so we always deal with them as byte arrays, not unicode strings.
- assert(isinstance(diff, str))
- pretty_diff = self.pretty_diff(diff)
- diff_file = tempfile.NamedTemporaryFile(suffix=".html")
- diff_file.write(pretty_diff)
- diff_file.flush()
- return diff_file
-
- def pretty_diff(self, diff):
- # pretify.rb will hang forever if given no input.
- # Avoid the hang by returning an empty string.
- if not diff:
- return ""
-
- pretty_patch_path = os.path.join(self._checkout_root,
- "BugsSite", "PrettyPatch")
- prettify_path = os.path.join(pretty_patch_path, "prettify.rb")
- args = [
- "ruby",
- "-I",
- pretty_patch_path,
- prettify_path,
- ]
- # PrettyPatch does not modify the encoding of the diff output
- # so we can't expect it to be utf-8.
- return self._executive.run_command(args, input=diff, decode_output=False)
diff --git a/WebKitTools/Scripts/webkitpy/common/prettypatch_unittest.py b/WebKitTools/Scripts/webkitpy/common/prettypatch_unittest.py
deleted file mode 100644
index 1307856..0000000
--- a/WebKitTools/Scripts/webkitpy/common/prettypatch_unittest.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import os.path
-import unittest
-
-from webkitpy.common.system.executive import Executive
-from webkitpy.common.prettypatch import PrettyPatch
-
-
-class PrettyPatchTest(unittest.TestCase):
-
- _diff_with_multiple_encodings = """
-Index: utf8_test
-===================================================================
---- utf8_test\t(revision 0)
-+++ utf8_test\t(revision 0)
-@@ -0,0 +1 @@
-+utf-8 test: \xc2\xa0
-Index: latin1_test
-===================================================================
---- latin1_test\t(revision 0)
-+++ latin1_test\t(revision 0)
-@@ -0,0 +1 @@
-+latin1 test: \xa0
-"""
-
- def _webkit_root(self):
- webkitpy_common = os.path.dirname(__file__)
- webkitpy = os.path.dirname(webkitpy_common)
- scripts = os.path.dirname(webkitpy)
- webkit_tools = os.path.dirname(scripts)
- webkit_root = os.path.dirname(webkit_tools)
- return webkit_root
-
- def test_pretty_diff_encodings(self):
- pretty_patch = PrettyPatch(Executive(), self._webkit_root())
- pretty = pretty_patch.pretty_diff(self._diff_with_multiple_encodings)
- self.assertTrue(pretty) # We got some output
- self.assertTrue(isinstance(pretty, str)) # It's a byte array, not unicode
-
- def test_pretty_print_empty_string(self):
- # Make sure that an empty diff does not hang the process.
- pretty_patch = PrettyPatch(Executive(), self._webkit_root())
- self.assertEqual(pretty_patch.pretty_diff(""), "")
diff --git a/WebKitTools/Scripts/webkitpy/common/system/__init__.py b/WebKitTools/Scripts/webkitpy/common/system/__init__.py
deleted file mode 100644
index ef65bee..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Required for Python to search this directory for module files
diff --git a/WebKitTools/Scripts/webkitpy/common/system/autoinstall.py b/WebKitTools/Scripts/webkitpy/common/system/autoinstall.py
deleted file mode 100755
index 9adab29..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/autoinstall.py
+++ /dev/null
@@ -1,517 +0,0 @@
-# Copyright (c) 2009, Daniel Krech All rights reserved.
-# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# * Neither the name of the Daniel Krech nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Support for automatically downloading Python packages from an URL."""
-
-
-from __future__ import with_statement
-
-import codecs
-import logging
-import new
-import os
-import shutil
-import sys
-import tarfile
-import tempfile
-import urllib
-import urlparse
-import zipfile
-import zipimport
-
-_log = logging.getLogger(__name__)
-
-
-class AutoInstaller(object):
-
- """Supports automatically installing Python packages from an URL.
-
- Supports uncompressed files, .tar.gz, and .zip formats.
-
- Basic usage:
-
- installer = AutoInstaller()
-
- installer.install(url="http://pypi.python.org/packages/source/p/pep8/pep8-0.5.0.tar.gz#md5=512a818af9979290cd619cce8e9c2e2b",
- url_subpath="pep8-0.5.0/pep8.py")
- installer.install(url="http://pypi.python.org/packages/source/m/mechanize/mechanize-0.1.11.zip",
- url_subpath="mechanize")
-
- """
-
- def __init__(self, append_to_search_path=False, make_package=True,
- target_dir=None, temp_dir=None):
- """Create an AutoInstaller instance, and set up the target directory.
-
- Args:
- append_to_search_path: A boolean value of whether to append the
- target directory to the sys.path search path.
- make_package: A boolean value of whether to make the target
- directory a package. This adds an __init__.py file
- to the target directory -- allowing packages and
- modules within the target directory to be imported
- explicitly using dotted module names.
- target_dir: The directory path to which packages should be installed.
- Defaults to a subdirectory of the folder containing
- this module called "autoinstalled".
- temp_dir: The directory path to use for any temporary files
- generated while downloading, unzipping, and extracting
- packages to install. Defaults to a standard temporary
- location generated by the tempfile module. This
- parameter should normally be used only for development
- testing.
-
- """
- if target_dir is None:
- this_dir = os.path.dirname(__file__)
- target_dir = os.path.join(this_dir, "autoinstalled")
-
- # Ensure that the target directory exists.
- self._set_up_target_dir(target_dir, append_to_search_path, make_package)
-
- self._target_dir = target_dir
- self._temp_dir = temp_dir
-
- def _log_transfer(self, message, source, target, log_method=None):
- """Log a debug message that involves a source and target."""
- if log_method is None:
- log_method = _log.debug
-
- log_method("%s" % message)
- log_method(' From: "%s"' % source)
- log_method(' To: "%s"' % target)
-
- def _create_directory(self, path, name=None):
- """Create a directory."""
- log = _log.debug
-
- name = name + " " if name is not None else ""
- log('Creating %sdirectory...' % name)
- log(' "%s"' % path)
-
- os.makedirs(path)
-
- def _write_file(self, path, text, encoding):
- """Create a file at the given path with given text.
-
- This method overwrites any existing file.
-
- """
- _log.debug("Creating file...")
- _log.debug(' "%s"' % path)
- with codecs.open(path, "w", encoding) as file:
- file.write(text)
-
- def _set_up_target_dir(self, target_dir, append_to_search_path,
- make_package):
- """Set up a target directory.
-
- Args:
- target_dir: The path to the target directory to set up.
- append_to_search_path: A boolean value of whether to append the
- target directory to the sys.path search path.
- make_package: A boolean value of whether to make the target
- directory a package. This adds an __init__.py file
- to the target directory -- allowing packages and
- modules within the target directory to be imported
- explicitly using dotted module names.
-
- """
- if not os.path.exists(target_dir):
- self._create_directory(target_dir, "autoinstall target")
-
- if append_to_search_path:
- sys.path.append(target_dir)
-
- if make_package:
- init_path = os.path.join(target_dir, "__init__.py")
- if not os.path.exists(init_path):
- text = ("# This file is required for Python to search this "
- "directory for modules.\n")
- self._write_file(init_path, text, "ascii")
-
- def _create_scratch_directory_inner(self, prefix):
- """Create a scratch directory without exception handling.
-
- Creates a scratch directory inside the AutoInstaller temp
- directory self._temp_dir, or inside a platform-dependent temp
- directory if self._temp_dir is None. Returns the path to the
- created scratch directory.
-
- Raises:
- OSError: [Errno 2] if the containing temp directory self._temp_dir
- is not None and does not exist.
-
- """
- # The tempfile.mkdtemp() method function requires that the
- # directory corresponding to the "dir" parameter already exist
- # if it is not None.
- scratch_dir = tempfile.mkdtemp(prefix=prefix, dir=self._temp_dir)
- return scratch_dir
-
- def _create_scratch_directory(self, target_name):
- """Create a temporary scratch directory, and return its path.
-
- The scratch directory is generated inside the temp directory
- of this AutoInstaller instance. This method also creates the
- temp directory if it does not already exist.
-
- """
- prefix = target_name + "_"
- try:
- scratch_dir = self._create_scratch_directory_inner(prefix)
- except OSError:
- # Handle case of containing temp directory not existing--
- # OSError: [Errno 2] No such file or directory:...
- temp_dir = self._temp_dir
- if temp_dir is None or os.path.exists(temp_dir):
- raise
- # Else try again after creating the temp directory.
- self._create_directory(temp_dir, "autoinstall temp")
- scratch_dir = self._create_scratch_directory_inner(prefix)
-
- return scratch_dir
-
- def _url_downloaded_path(self, target_name):
- """Return the path to the file containing the URL downloaded."""
- filename = ".%s.url" % target_name
- path = os.path.join(self._target_dir, filename)
- return path
-
- def _is_downloaded(self, target_name, url):
- """Return whether a package version has been downloaded."""
- version_path = self._url_downloaded_path(target_name)
-
- _log.debug('Checking %s URL downloaded...' % target_name)
- _log.debug(' "%s"' % version_path)
-
- if not os.path.exists(version_path):
- # Then no package version has been downloaded.
- _log.debug("No URL file found.")
- return False
-
- with codecs.open(version_path, "r", "utf-8") as file:
- version = file.read()
-
- return version.strip() == url.strip()
-
- def _record_url_downloaded(self, target_name, url):
- """Record the URL downloaded to a file."""
- version_path = self._url_downloaded_path(target_name)
- _log.debug("Recording URL downloaded...")
- _log.debug(' URL: "%s"' % url)
- _log.debug(' To: "%s"' % version_path)
-
- self._write_file(version_path, url, "utf-8")
-
- def _extract_targz(self, path, scratch_dir):
- # tarfile.extractall() extracts to a path without the
- # trailing ".tar.gz".
- target_basename = os.path.basename(path[:-len(".tar.gz")])
- target_path = os.path.join(scratch_dir, target_basename)
-
- self._log_transfer("Starting gunzip/extract...", path, target_path)
-
- try:
- tar_file = tarfile.open(path)
- except tarfile.ReadError, err:
- # Append existing Error message to new Error.
- message = ("Could not open tar file: %s\n"
- " The file probably does not have the correct format.\n"
- " --> Inner message: %s"
- % (path, err))
- raise Exception(message)
-
- try:
- # This is helpful for debugging purposes.
- _log.debug("Listing tar file contents...")
- for name in tar_file.getnames():
- _log.debug(' * "%s"' % name)
- _log.debug("Extracting gzipped tar file...")
- tar_file.extractall(target_path)
- finally:
- tar_file.close()
-
- return target_path
-
- # This is a replacement for ZipFile.extractall(), which is
- # available in Python 2.6 but not in earlier versions.
- def _extract_all(self, zip_file, target_dir):
- self._log_transfer("Extracting zip file...", zip_file, target_dir)
-
- # This is helpful for debugging purposes.
- _log.debug("Listing zip file contents...")
- for name in zip_file.namelist():
- _log.debug(' * "%s"' % name)
-
- for name in zip_file.namelist():
- path = os.path.join(target_dir, name)
- self._log_transfer("Extracting...", name, path)
-
- if not os.path.basename(path):
- # Then the path ends in a slash, so it is a directory.
- self._create_directory(path)
- continue
- # Otherwise, it is a file.
-
- try:
- # We open this file w/o encoding, as we're reading/writing
- # the raw byte-stream from the zip file.
- outfile = open(path, 'wb')
- except IOError, err:
- # Not all zip files seem to list the directories explicitly,
- # so try again after creating the containing directory.
- _log.debug("Got IOError: retrying after creating directory...")
- dir = os.path.dirname(path)
- self._create_directory(dir)
- outfile = open(path, 'wb')
-
- try:
- outfile.write(zip_file.read(name))
- finally:
- outfile.close()
-
- def _unzip(self, path, scratch_dir):
- # zipfile.extractall() extracts to a path without the
- # trailing ".zip".
- target_basename = os.path.basename(path[:-len(".zip")])
- target_path = os.path.join(scratch_dir, target_basename)
-
- self._log_transfer("Starting unzip...", path, target_path)
-
- try:
- zip_file = zipfile.ZipFile(path, "r")
- except zipfile.BadZipfile, err:
- message = ("Could not open zip file: %s\n"
- " --> Inner message: %s"
- % (path, err))
- raise Exception(message)
-
- try:
- self._extract_all(zip_file, scratch_dir)
- finally:
- zip_file.close()
-
- return target_path
-
- def _prepare_package(self, path, scratch_dir):
- """Prepare a package for use, if necessary, and return the new path.
-
- For example, this method unzips zipped files and extracts
- tar files.
-
- Args:
- path: The path to the downloaded URL contents.
- scratch_dir: The scratch directory. Note that the scratch
- directory contains the file designated by the
- path parameter.
-
- """
- # FIXME: Add other natural extensions.
- if path.endswith(".zip"):
- new_path = self._unzip(path, scratch_dir)
- elif path.endswith(".tar.gz"):
- new_path = self._extract_targz(path, scratch_dir)
- else:
- # No preparation is needed.
- new_path = path
-
- return new_path
-
- def _download_to_stream(self, url, stream):
- """Download an URL to a stream, and return the number of bytes."""
- try:
- netstream = urllib.urlopen(url)
- except IOError, err:
- # Append existing Error message to new Error.
- message = ('Could not download Python modules from URL "%s".\n'
- " Make sure you are connected to the internet.\n"
- " You must be connected to the internet when "
- "downloading needed modules for the first time.\n"
- " --> Inner message: %s"
- % (url, err))
- raise IOError(message)
- code = 200
- if hasattr(netstream, "getcode"):
- code = netstream.getcode()
- if not 200 <= code < 300:
- raise ValueError("HTTP Error code %s" % code)
-
- BUFSIZE = 2**13 # 8KB
- bytes = 0
- while True:
- data = netstream.read(BUFSIZE)
- if not data:
- break
- stream.write(data)
- bytes += len(data)
- netstream.close()
- return bytes
-
- def _download(self, url, scratch_dir):
- """Download URL contents, and return the download path."""
- url_path = urlparse.urlsplit(url)[2]
- url_path = os.path.normpath(url_path) # Removes trailing slash.
- target_filename = os.path.basename(url_path)
- target_path = os.path.join(scratch_dir, target_filename)
-
- self._log_transfer("Starting download...", url, target_path)
-
- with open(target_path, "wb") as stream:
- bytes = self._download_to_stream(url, stream)
-
- _log.debug("Downloaded %s bytes." % bytes)
-
- return target_path
-
- def _install(self, scratch_dir, package_name, target_path, url,
- url_subpath):
- """Install a python package from an URL.
-
- This internal method overwrites the target path if the target
- path already exists.
-
- """
- path = self._download(url=url, scratch_dir=scratch_dir)
- path = self._prepare_package(path, scratch_dir)
-
- if url_subpath is None:
- source_path = path
- else:
- source_path = os.path.join(path, url_subpath)
-
- if os.path.exists(target_path):
- _log.debug('Refreshing install: deleting "%s".' % target_path)
- if os.path.isdir(target_path):
- shutil.rmtree(target_path)
- else:
- os.remove(target_path)
-
- self._log_transfer("Moving files into place...", source_path, target_path)
-
- # The shutil.move() command creates intermediate directories if they
- # do not exist, but we do not rely on this behavior since we
- # need to create the __init__.py file anyway.
- shutil.move(source_path, target_path)
-
- self._record_url_downloaded(package_name, url)
-
- def install(self, url, should_refresh=False, target_name=None,
- url_subpath=None):
- """Install a python package from an URL.
-
- Args:
- url: The URL from which to download the package.
-
- Optional Args:
- should_refresh: A boolean value of whether the package should be
- downloaded again if the package is already present.
- target_name: The name of the folder or file in the autoinstaller
- target directory at which the package should be
- installed. Defaults to the base name of the
- URL sub-path. This parameter must be provided if
- the URL sub-path is not specified.
- url_subpath: The relative path of the URL directory that should
- be installed. Defaults to the full directory, or
- the entire URL contents.
-
- """
- if target_name is None:
- if not url_subpath:
- raise ValueError('The "target_name" parameter must be '
- 'provided if the "url_subpath" parameter '
- "is not provided.")
- # Remove any trailing slashes.
- url_subpath = os.path.normpath(url_subpath)
- target_name = os.path.basename(url_subpath)
-
- target_path = os.path.join(self._target_dir, target_name)
- if not should_refresh and self._is_downloaded(target_name, url):
- _log.debug('URL for %s already downloaded. Skipping...'
- % target_name)
- _log.debug(' "%s"' % url)
- return
-
- self._log_transfer("Auto-installing package: %s" % target_name,
- url, target_path, log_method=_log.info)
-
- # The scratch directory is where we will download and prepare
- # files specific to this install until they are ready to move
- # into place.
- scratch_dir = self._create_scratch_directory(target_name)
-
- try:
- self._install(package_name=target_name,
- target_path=target_path,
- scratch_dir=scratch_dir,
- url=url,
- url_subpath=url_subpath)
- except Exception, err:
- # Append existing Error message to new Error.
- message = ("Error auto-installing the %s package to:\n"
- ' "%s"\n'
- " --> Inner message: %s"
- % (target_name, target_path, err))
- raise Exception(message)
- finally:
- _log.debug('Cleaning up: deleting "%s".' % scratch_dir)
- shutil.rmtree(scratch_dir)
- _log.debug('Auto-installed %s to:' % target_name)
- _log.debug(' "%s"' % target_path)
-
-
-if __name__=="__main__":
-
- # Configure the autoinstall logger to log DEBUG messages for
- # development testing purposes.
- console = logging.StreamHandler()
-
- formatter = logging.Formatter('%(name)s: %(levelname)-8s %(message)s')
- console.setFormatter(formatter)
- _log.addHandler(console)
- _log.setLevel(logging.DEBUG)
-
- # Use a more visible temp directory for debug purposes.
- this_dir = os.path.dirname(__file__)
- target_dir = os.path.join(this_dir, "autoinstalled")
- temp_dir = os.path.join(target_dir, "Temp")
-
- installer = AutoInstaller(target_dir=target_dir,
- temp_dir=temp_dir)
-
- installer.install(should_refresh=False,
- target_name="pep8.py",
- url="http://pypi.python.org/packages/source/p/pep8/pep8-0.5.0.tar.gz#md5=512a818af9979290cd619cce8e9c2e2b",
- url_subpath="pep8-0.5.0/pep8.py")
- installer.install(should_refresh=False,
- target_name="mechanize",
- url="http://pypi.python.org/packages/source/m/mechanize/mechanize-0.1.11.zip",
- url_subpath="mechanize")
-
diff --git a/WebKitTools/Scripts/webkitpy/common/system/deprecated_logging.py b/WebKitTools/Scripts/webkitpy/common/system/deprecated_logging.py
deleted file mode 100644
index 9e6b529..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/deprecated_logging.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# Copyright (c) 2009, Google Inc. All rights reserved.
-# Copyright (c) 2009 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# WebKit's Python module for logging
-# This module is now deprecated in favor of python's built-in logging.py.
-
-import codecs
-import os
-import sys
-
-
-def log(string):
- print >> sys.stderr, string
-
-
-def error(string):
- log("ERROR: %s" % string)
- exit(1)
-
-
-# Simple class to split output between multiple destinations
-class tee:
- def __init__(self, *files):
- self.files = files
-
- # Callers should pass an already encoded string for writing.
- def write(self, bytes):
- for file in self.files:
- file.write(bytes)
-
-
-class OutputTee:
- def __init__(self):
- self._original_stdout = None
- self._original_stderr = None
- self._files_for_output = []
-
- def add_log(self, path):
- log_file = self._open_log_file(path)
- self._files_for_output.append(log_file)
- self._tee_outputs_to_files(self._files_for_output)
- return log_file
-
- def remove_log(self, log_file):
- self._files_for_output.remove(log_file)
- self._tee_outputs_to_files(self._files_for_output)
- log_file.close()
-
- @staticmethod
- def _open_log_file(log_path):
- (log_directory, log_name) = os.path.split(log_path)
- if log_directory and not os.path.exists(log_directory):
- os.makedirs(log_directory)
- return codecs.open(log_path, "a+", "utf-8")
-
- def _tee_outputs_to_files(self, files):
- if not self._original_stdout:
- self._original_stdout = sys.stdout
- self._original_stderr = sys.stderr
- if files and len(files):
- sys.stdout = tee(self._original_stdout, *files)
- sys.stderr = tee(self._original_stderr, *files)
- else:
- sys.stdout = self._original_stdout
- sys.stderr = self._original_stderr
diff --git a/WebKitTools/Scripts/webkitpy/common/system/deprecated_logging_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/deprecated_logging_unittest.py
deleted file mode 100644
index 3778162..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/deprecated_logging_unittest.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright (C) 2009 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import os
-import StringIO
-import tempfile
-import unittest
-
-from webkitpy.common.system.executive import ScriptError
-from webkitpy.common.system.deprecated_logging import *
-
-class LoggingTest(unittest.TestCase):
-
- def assert_log_equals(self, log_input, expected_output):
- original_stderr = sys.stderr
- test_stderr = StringIO.StringIO()
- sys.stderr = test_stderr
-
- try:
- log(log_input)
- actual_output = test_stderr.getvalue()
- finally:
- sys.stderr = original_stderr
-
- self.assertEquals(actual_output, expected_output, "log(\"%s\") expected: %s actual: %s" % (log_input, expected_output, actual_output))
-
- def test_log(self):
- self.assert_log_equals("test", "test\n")
-
- # Test that log() does not throw an exception when passed an object instead of a string.
- self.assert_log_equals(ScriptError(message="ScriptError"), "ScriptError\n")
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/system/executive.py b/WebKitTools/Scripts/webkitpy/common/system/executive.py
deleted file mode 100644
index 85a683a..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/executive.py
+++ /dev/null
@@ -1,399 +0,0 @@
-# Copyright (c) 2009, Google Inc. All rights reserved.
-# Copyright (c) 2009 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-try:
- # This API exists only in Python 2.6 and higher. :(
- import multiprocessing
-except ImportError:
- multiprocessing = None
-
-import ctypes
-import errno
-import logging
-import os
-import platform
-import StringIO
-import signal
-import subprocess
-import sys
-import time
-
-from webkitpy.common.system.deprecated_logging import tee
-from webkitpy.python24 import versioning
-
-
-_log = logging.getLogger("webkitpy.common.system")
-
-
-class ScriptError(Exception):
-
- def __init__(self,
- message=None,
- script_args=None,
- exit_code=None,
- output=None,
- cwd=None):
- if not message:
- message = 'Failed to run "%s"' % script_args
- if exit_code:
- message += " exit_code: %d" % exit_code
- if cwd:
- message += " cwd: %s" % cwd
-
- Exception.__init__(self, message)
- self.script_args = script_args # 'args' is already used by Exception
- self.exit_code = exit_code
- self.output = output
- self.cwd = cwd
-
- def message_with_output(self, output_limit=500):
- if self.output:
- if output_limit and len(self.output) > output_limit:
- return u"%s\nLast %s characters of output:\n%s" % \
- (self, output_limit, self.output[-output_limit:])
- return u"%s\n%s" % (self, self.output)
- return unicode(self)
-
- def command_name(self):
- command_path = self.script_args
- if type(command_path) is list:
- command_path = command_path[0]
- return os.path.basename(command_path)
-
-
-def run_command(*args, **kwargs):
- # FIXME: This should not be a global static.
- # New code should use Executive.run_command directly instead
- return Executive().run_command(*args, **kwargs)
-
-
-class Executive(object):
-
- def _should_close_fds(self):
- # We need to pass close_fds=True to work around Python bug #2320
- # (otherwise we can hang when we kill DumpRenderTree when we are running
- # multiple threads). See http://bugs.python.org/issue2320 .
- # Note that close_fds isn't supported on Windows, but this bug only
- # shows up on Mac and Linux.
- return sys.platform not in ('win32', 'cygwin')
-
- def _run_command_with_teed_output(self, args, teed_output):
- args = map(unicode, args) # Popen will throw an exception if args are non-strings (like int())
- args = map(self._encode_argument_if_needed, args)
-
- child_process = subprocess.Popen(args,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- close_fds=self._should_close_fds())
-
- # Use our own custom wait loop because Popen ignores a tee'd
- # stderr/stdout.
- # FIXME: This could be improved not to flatten output to stdout.
- while True:
- output_line = child_process.stdout.readline()
- if output_line == "" and child_process.poll() != None:
- # poll() is not threadsafe and can throw OSError due to:
- # http://bugs.python.org/issue1731717
- return child_process.poll()
- # We assume that the child process wrote to us in utf-8,
- # so no re-encoding is necessary before writing here.
- teed_output.write(output_line)
-
- # FIXME: Remove this deprecated method and move callers to run_command.
- # FIXME: This method is a hack to allow running command which both
- # capture their output and print out to stdin. Useful for things
- # like "build-webkit" where we want to display to the user that we're building
- # but still have the output to stuff into a log file.
- def run_and_throw_if_fail(self, args, quiet=False, decode_output=True):
- # Cache the child's output locally so it can be used for error reports.
- child_out_file = StringIO.StringIO()
- tee_stdout = sys.stdout
- if quiet:
- dev_null = open(os.devnull, "w") # FIXME: Does this need an encoding?
- tee_stdout = dev_null
- child_stdout = tee(child_out_file, tee_stdout)
- exit_code = self._run_command_with_teed_output(args, child_stdout)
- if quiet:
- dev_null.close()
-
- child_output = child_out_file.getvalue()
- child_out_file.close()
-
- if decode_output:
- child_output = child_output.decode(self._child_process_encoding())
-
- if exit_code:
- raise ScriptError(script_args=args,
- exit_code=exit_code,
- output=child_output)
- 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
-
- def kill_process(self, pid):
- """Attempts to kill the given pid.
- Will fail silently if pid does not exist or insufficient permisssions."""
- if sys.platform == "win32":
- # We only use taskkill.exe on windows (not cygwin) because subprocess.pid
- # is a CYGWIN pid and taskkill.exe expects a windows pid.
- # Thankfully os.kill on CYGWIN handles either pid type.
- command = ["taskkill.exe", "/f", "/pid", pid]
- # taskkill will exit 128 if the process is not found. We should log.
- self.run_command(command, error_handler=self.ignore_error)
- return
-
- # According to http://docs.python.org/library/os.html
- # os.kill isn't available on Windows. python 2.5.5 os.kill appears
- # to work in cygwin, however it occasionally raises EAGAIN.
- retries_left = 10 if sys.platform == "cygwin" else 1
- while retries_left > 0:
- try:
- retries_left -= 1
- os.kill(pid, signal.SIGKILL)
- except OSError, e:
- if e.errno == errno.EAGAIN:
- if retries_left <= 0:
- _log.warn("Failed to kill pid %s. Too many EAGAIN errors." % pid)
- continue
- if e.errno == errno.ESRCH: # The process does not exist.
- _log.warn("Called kill_process with a non-existant pid %s" % pid)
- return
- raise
-
- def _win32_check_running_pid(self, pid):
-
- class PROCESSENTRY32(ctypes.Structure):
- _fields_ = [("dwSize", ctypes.c_ulong),
- ("cntUsage", ctypes.c_ulong),
- ("th32ProcessID", ctypes.c_ulong),
- ("th32DefaultHeapID", ctypes.c_ulong),
- ("th32ModuleID", ctypes.c_ulong),
- ("cntThreads", ctypes.c_ulong),
- ("th32ParentProcessID", ctypes.c_ulong),
- ("pcPriClassBase", ctypes.c_ulong),
- ("dwFlags", ctypes.c_ulong),
- ("szExeFile", ctypes.c_char * 260)]
-
- CreateToolhelp32Snapshot = ctypes.windll.kernel32.CreateToolhelp32Snapshot
- Process32First = ctypes.windll.kernel32.Process32First
- Process32Next = ctypes.windll.kernel32.Process32Next
- CloseHandle = ctypes.windll.kernel32.CloseHandle
- TH32CS_SNAPPROCESS = 0x00000002 # win32 magic number
- hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
- pe32 = PROCESSENTRY32()
- pe32.dwSize = ctypes.sizeof(PROCESSENTRY32)
- result = False
- if not Process32First(hProcessSnap, ctypes.byref(pe32)):
- _log.debug("Failed getting first process.")
- CloseHandle(hProcessSnap)
- return result
- while True:
- if pe32.th32ProcessID == pid:
- result = True
- break
- if not Process32Next(hProcessSnap, ctypes.byref(pe32)):
- break
- CloseHandle(hProcessSnap)
- return result
-
- def check_running_pid(self, pid):
- """Return True if pid is alive, otherwise return False."""
- if sys.platform in ('darwin', 'linux2', 'cygwin'):
- try:
- os.kill(pid, 0)
- return True
- except OSError:
- return False
- elif sys.platform == 'win32':
- return self._win32_check_running_pid(pid)
-
- assert(False)
-
- def _windows_image_name(self, process_name):
- name, extension = os.path.splitext(process_name)
- if not extension:
- # taskkill expects processes to end in .exe
- # If necessary we could add a flag to disable appending .exe.
- process_name = "%s.exe" % name
- return process_name
-
- def kill_all(self, process_name):
- """Attempts to kill processes matching process_name.
- Will fail silently if no process are found."""
- if sys.platform in ("win32", "cygwin"):
- image_name = self._windows_image_name(process_name)
- command = ["taskkill.exe", "/f", "/im", image_name]
- # taskkill will exit 128 if the process is not found. We should log.
- self.run_command(command, error_handler=self.ignore_error)
- return
-
- # FIXME: This is inconsistent that kill_all uses TERM and kill_process
- # uses KILL. Windows is always using /f (which seems like -KILL).
- # We should pick one mode, or add support for switching between them.
- # Note: Mac OS X 10.6 requires -SIGNALNAME before -u USER
- command = ["killall", "-TERM", "-u", os.getenv("USER"), process_name]
- # killall returns 1 if no process can be found and 2 on command error.
- # FIXME: We should pass a custom error_handler to allow only exit_code 1.
- # We should log in exit_code == 1
- self.run_command(command, error_handler=self.ignore_error)
-
- # Error handlers do not need to be static methods once all callers are
- # updated to use an Executive object.
-
- @staticmethod
- def default_error_handler(error):
- raise error
-
- @staticmethod
- def ignore_error(error):
- pass
-
- def _compute_stdin(self, input):
- """Returns (stdin, string_to_communicate)"""
- # FIXME: We should be returning /dev/null for stdin
- # or closing stdin after process creation to prevent
- # child processes from getting input from the user.
- if not input:
- return (None, None)
- if hasattr(input, "read"): # Check if the input is a file.
- return (input, None) # Assume the file is in the right encoding.
-
- # Popen in Python 2.5 and before does not automatically encode unicode objects.
- # http://bugs.python.org/issue5290
- # See https://bugs.webkit.org/show_bug.cgi?id=37528
- # for an example of a regresion caused by passing a unicode string directly.
- # FIXME: We may need to encode differently on different platforms.
- if isinstance(input, unicode):
- input = input.encode(self._child_process_encoding())
- return (subprocess.PIPE, input)
-
- def _command_for_printing(self, args):
- """Returns a print-ready string representing command args.
- The string should be copy/paste ready for execution in a shell."""
- escaped_args = []
- for arg in args:
- if isinstance(arg, unicode):
- # Escape any non-ascii characters for easy copy/paste
- arg = arg.encode("unicode_escape")
- # FIXME: Do we need to fix quotes here?
- escaped_args.append(arg)
- return " ".join(escaped_args)
-
- # FIXME: run_and_throw_if_fail should be merged into this method.
- def run_command(self,
- args,
- cwd=None,
- input=None,
- error_handler=None,
- return_exit_code=False,
- return_stderr=True,
- decode_output=True):
- """Popen wrapper for convenience and to work around python bugs."""
- assert(isinstance(args, list) or isinstance(args, tuple))
- start_time = time.time()
- args = map(unicode, args) # Popen will throw an exception if args are non-strings (like int())
- args = map(self._encode_argument_if_needed, args)
-
- stdin, string_to_communicate = self._compute_stdin(input)
- stderr = subprocess.STDOUT if return_stderr else None
-
- process = subprocess.Popen(args,
- stdin=stdin,
- stdout=subprocess.PIPE,
- stderr=stderr,
- cwd=cwd,
- close_fds=self._should_close_fds())
- output = process.communicate(string_to_communicate)[0]
-
- # run_command automatically decodes to unicode() unless explicitly told not to.
- if decode_output:
- output = output.decode(self._child_process_encoding())
-
- # wait() is not threadsafe and can throw OSError due to:
- # http://bugs.python.org/issue1731717
- exit_code = process.wait()
-
- _log.debug('"%s" took %.2fs' % (self._command_for_printing(args), time.time() - start_time))
-
- if return_exit_code:
- return exit_code
-
- if exit_code:
- script_error = ScriptError(script_args=args,
- exit_code=exit_code,
- output=output,
- cwd=cwd)
- (error_handler or self.default_error_handler)(script_error)
- return output
-
- def _child_process_encoding(self):
- # Win32 Python 2.x uses CreateProcessA rather than CreateProcessW
- # to launch subprocesses, so we have to encode arguments using the
- # current code page.
- if sys.platform == 'win32' and versioning.compare_version(sys, '3.0')[0] < 0:
- return 'mbcs'
- # All other platforms use UTF-8.
- # FIXME: Using UTF-8 on Cygwin will confuse Windows-native commands
- # which will expect arguments to be encoded using the current code
- # page.
- return 'utf-8'
-
- def _should_encode_child_process_arguments(self):
- # Cygwin's Python's os.execv doesn't support unicode command
- # arguments, and neither does Cygwin's execv itself.
- if sys.platform == 'cygwin':
- return True
-
- # Win32 Python 2.x uses CreateProcessA rather than CreateProcessW
- # to launch subprocesses, so we have to encode arguments using the
- # current code page.
- if sys.platform == 'win32' and versioning.compare_version(sys, '3.0')[0] < 0:
- return True
-
- return False
-
- def _encode_argument_if_needed(self, argument):
- if not self._should_encode_child_process_arguments():
- return argument
- return argument.encode(self._child_process_encoding())
diff --git a/WebKitTools/Scripts/webkitpy/common/system/executive_mock.py b/WebKitTools/Scripts/webkitpy/common/system/executive_mock.py
deleted file mode 100644
index c1cf999..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/executive_mock.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright (C) 2009 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# FIXME: Implement the rest of the interface as needed for testing :).
-
-# FIXME: Unify with tool/mocktool.MockExecutive.
-
-
-class MockExecutive2(object):
- def __init__(self, output='', exit_code=0, exception=None,
- run_command_fn=None):
- self._output = output
- self._exit_code = exit_code
- self._exception = exception
- self._run_command_fn = run_command_fn
-
- def cpu_count(self):
- return 2
-
- def kill_all(self, process_name):
- pass
-
- def kill_process(self, pid):
- pass
-
- def run_command(self, arg_list, return_exit_code=False,
- decode_output=False):
- if self._exception:
- raise self._exception
- if return_exit_code:
- return self._exit_code
- if self._run_command_fn:
- return self._run_command_fn(arg_list)
- return self._output
diff --git a/WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py
deleted file mode 100644
index b8fd82e..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py
+++ /dev/null
@@ -1,151 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-# Copyright (C) 2009 Daniel Bates (dbates@intudata.com). All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import os
-import signal
-import subprocess
-import sys
-import unittest
-
-from webkitpy.common.system.executive import Executive, run_command, ScriptError
-from webkitpy.test import cat, echo
-
-
-def never_ending_command():
- """Arguments for a command that will never end (useful for testing process
- killing). It should be a process that is unlikely to already be running
- because all instances will be killed."""
- if sys.platform == 'win32':
- return ['wmic']
- return ['yes']
-
-
-class ExecutiveTest(unittest.TestCase):
-
- 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)
- self.failUnlessRaises(OSError, run_bad_command)
-
- def test_run_command_args_type(self):
- 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')))
-
- def test_run_command_with_unicode(self):
- """Validate that it is safe to pass unicode() objects
- to Executive.run* methods, and they will return unicode()
- objects by default unless decode_output=False"""
- unicode_tor_input = u"WebKit \u2661 Tor Arne Vestb\u00F8!"
- if sys.platform == 'win32':
- encoding = 'mbcs'
- else:
- encoding = 'utf-8'
- encoded_tor = unicode_tor_input.encode(encoding)
- # On Windows, we expect the unicode->mbcs->unicode roundtrip to be
- # lossy. On other platforms, we expect a lossless roundtrip.
- if sys.platform == 'win32':
- unicode_tor_output = encoded_tor.decode(encoding)
- else:
- unicode_tor_output = unicode_tor_input
-
- executive = Executive()
-
- output = executive.run_command(cat.command_arguments(), input=unicode_tor_input)
- self.assertEquals(output, unicode_tor_output)
-
- output = executive.run_command(echo.command_arguments("-n", unicode_tor_input))
- self.assertEquals(output, unicode_tor_output)
-
- output = executive.run_command(echo.command_arguments("-n", 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)
- 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)
- 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)
- self.assertEquals(output, encoded_tor)
-
- def test_kill_process(self):
- executive = Executive()
- process = subprocess.Popen(never_ending_command(), stdout=subprocess.PIPE)
- self.assertEqual(process.poll(), None) # Process is running
- executive.kill_process(process.pid)
- # Note: Can't use a ternary since signal.SIGKILL is undefined for sys.platform == "win32"
- if sys.platform == "win32":
- expected_exit_code = 1
- else:
- expected_exit_code = -signal.SIGKILL
- self.assertEqual(process.wait(), expected_exit_code)
- # Killing again should fail silently.
- executive.kill_process(process.pid)
-
- def _assert_windows_image_name(self, name, expected_windows_name):
- executive = Executive()
- windows_name = executive._windows_image_name(name)
- self.assertEqual(windows_name, expected_windows_name)
-
- def test_windows_image_name(self):
- self._assert_windows_image_name("foo", "foo.exe")
- self._assert_windows_image_name("foo.exe", "foo.exe")
- self._assert_windows_image_name("foo.com", "foo.com")
- # If the name looks like an extension, even if it isn't
- # supposed to, we have no choice but to return the original name.
- self._assert_windows_image_name("foo.baz", "foo.baz")
- self._assert_windows_image_name("foo.baz.exe", "foo.baz.exe")
-
- def test_kill_all(self):
- executive = Executive()
- # We use "yes" because it loops forever.
- process = subprocess.Popen(never_ending_command(), stdout=subprocess.PIPE)
- self.assertEqual(process.poll(), None) # Process is running
- executive.kill_all(never_ending_command()[0])
- # Note: Can't use a ternary since signal.SIGTERM is undefined for sys.platform == "win32"
- if sys.platform == "cygwin":
- expected_exit_code = 0 # os.kill results in exit(0) for this process.
- elif sys.platform == "win32":
- expected_exit_code = 1
- else:
- expected_exit_code = -signal.SIGTERM
- self.assertEqual(process.wait(), expected_exit_code)
- # Killing again should fail silently.
- executive.kill_all(never_ending_command()[0])
-
- def test_check_running_pid(self):
- executive = Executive()
- self.assertTrue(executive.check_running_pid(os.getpid()))
- # Maximum pid number on Linux is 32768 by default
- self.assertFalse(executive.check_running_pid(100000))
diff --git a/WebKitTools/Scripts/webkitpy/common/system/file_lock.py b/WebKitTools/Scripts/webkitpy/common/system/file_lock.py
deleted file mode 100644
index 7296958..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/file_lock.py
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
-#
-# 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED OR
-# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
-# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""This class helps to lock files exclusively across processes."""
-
-import logging
-import os
-import sys
-import time
-
-
-_log = logging.getLogger("webkitpy.common.system.file_lock")
-
-
-class FileLock(object):
-
- def __init__(self, lock_file_path, max_wait_time_sec=20):
- self._lock_file_path = lock_file_path
- self._lock_file_descriptor = None
- self._max_wait_time_sec = max_wait_time_sec
-
- def _create_lock(self):
- if sys.platform in ('darwin', 'linux2', 'cygwin'):
- import fcntl
- fcntl.flock(self._lock_file_descriptor, fcntl.LOCK_EX | fcntl.LOCK_NB)
- elif sys.platform == 'win32':
- import msvcrt
- msvcrt.locking(self._lock_file_descriptor, msvcrt.LK_NBLCK, 32)
-
- def _remove_lock(self):
- if sys.platform in ('darwin', 'linux2', 'cygwin'):
- import fcntl
- fcntl.flock(self._lock_file_descriptor, fcntl.LOCK_UN)
- elif sys.platform == 'win32':
- import msvcrt
- msvcrt.locking(self._lock_file_descriptor, msvcrt.LK_UNLCK, 32)
-
- def acquire_lock(self):
- self._lock_file_descriptor = os.open(self._lock_file_path, os.O_TRUNC | os.O_CREAT)
- start_time = time.time()
- while True:
- try:
- self._create_lock()
- return True
- except IOError:
- if time.time() - start_time > self._max_wait_time_sec:
- _log.debug("File locking failed: %s" % str(sys.exc_info()))
- os.close(self._lock_file_descriptor)
- self._lock_file_descriptor = None
- return False
-
- def release_lock(self):
- try:
- if self._lock_file_descriptor:
- self._remove_lock()
- os.close(self._lock_file_descriptor)
- self._lock_file_descriptor = None
- os.unlink(self._lock_file_path)
- except (IOError, OSError):
- _log.debug("Warning in release lock: %s" % str(sys.exc_info()))
diff --git a/WebKitTools/Scripts/webkitpy/common/system/file_lock_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/file_lock_unittest.py
deleted file mode 100644
index c5c1db3..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/file_lock_unittest.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
-#
-# 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED OR
-# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
-# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import os
-import tempfile
-import unittest
-
-from webkitpy.common.system.file_lock import FileLock
-
-
-class FileLockTest(unittest.TestCase):
-
- def setUp(self):
- self._lock_name = "TestWebKit" + str(os.getpid()) + ".lock"
- self._lock_path = os.path.join(tempfile.gettempdir(), self._lock_name)
- self._file_lock1 = FileLock(self._lock_path, 1)
- self._file_lock2 = FileLock(self._lock_path, 1)
-
- def tearDown(self):
- self._file_lock1.release_lock()
- self._file_lock2.release_lock()
-
- def test_lock_lifecycle(self):
- # Create the lock.
- self._file_lock1.acquire_lock()
- self.assertTrue(os.path.exists(self._lock_path))
-
- # Try to lock again.
- self.assertFalse(self._file_lock2.acquire_lock())
-
- # Release the lock.
- self._file_lock1.release_lock()
- self.assertFalse(os.path.exists(self._lock_path))
-
- def test_stuck_lock(self):
- open(self._lock_path, 'w').close()
- self._file_lock1.acquire_lock()
- self._file_lock1.release_lock()
diff --git a/WebKitTools/Scripts/webkitpy/common/system/filesystem.py b/WebKitTools/Scripts/webkitpy/common/system/filesystem.py
deleted file mode 100644
index c7efde3..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/filesystem.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Wrapper object for the file system / source tree."""
-
-from __future__ import with_statement
-
-import codecs
-import errno
-import os
-import tempfile
-
-
-class FileSystem(object):
- """FileSystem interface for webkitpy.
-
- Unless otherwise noted, all paths are allowed to be either absolute
- or relative."""
-
- def exists(self, path):
- """Return whether the path exists in the filesystem."""
- return os.path.exists(path)
-
- def isdir(self, path):
- """Return whether the path refers to a directory."""
- return os.path.isdir(path)
-
- def join(self, *comps):
- """Return the path formed by joining the components."""
- return os.path.join(*comps)
-
- def listdir(self, path):
- """Return the contents of the directory pointed to by path."""
- return os.listdir(path)
-
- def mkdtemp(self, **kwargs):
- """Create and return a uniquely named directory.
-
- This is like tempfile.mkdtemp, but if used in a with statement
- the directory will self-delete at the end of the block (if the
- directory is empty; non-empty directories raise errors). The
- directory can be safely deleted inside the block as well, if so
- desired."""
- class TemporaryDirectory(object):
- def __init__(self, **kwargs):
- self._kwargs = kwargs
- self._directory_path = None
-
- def __enter__(self):
- self._directory_path = tempfile.mkdtemp(**self._kwargs)
- return self._directory_path
-
- def __exit__(self, type, value, traceback):
- # Only self-delete if necessary.
-
- # FIXME: Should we delete non-empty directories?
- if os.path.exists(self._directory_path):
- os.rmdir(self._directory_path)
-
- return TemporaryDirectory(**kwargs)
-
- def maybe_make_directory(self, *path):
- """Create the specified directory if it doesn't already exist."""
- try:
- os.makedirs(os.path.join(*path))
- except OSError, e:
- if e.errno != errno.EEXIST:
- raise
-
- def read_binary_file(self, path):
- """Return the contents of the file at the given path as a byte string."""
- with file(path, 'rb') as f:
- return f.read()
-
- def read_text_file(self, path):
- """Return the contents of the file at the given path as a Unicode string.
-
- The file is read assuming it is a UTF-8 encoded file with no BOM."""
- with codecs.open(path, 'r', 'utf8') as f:
- return f.read()
-
- def write_binary_file(self, path, contents):
- """Write the contents to the file at the given location."""
- with file(path, 'wb') as f:
- f.write(contents)
-
- def write_text_file(self, path, contents):
- """Write the contents to the file at the given location.
-
- The file is written encoded as UTF-8 with no BOM."""
- with codecs.open(path, 'w', 'utf8') as f:
- f.write(contents)
diff --git a/WebKitTools/Scripts/webkitpy/common/system/filesystem_mock.py b/WebKitTools/Scripts/webkitpy/common/system/filesystem_mock.py
deleted file mode 100644
index 4e6d3da..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/filesystem_mock.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# Copyright (C) 2009 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import errno
-import os
-import path
-
-
-class MockFileSystem(object):
- def __init__(self, files={}):
- """Initializes a "mock" filesystem that can be used to completely
- stub out a filesystem.
-
- Args:
- files: a dict of filenames -> file contents. A file contents
- value of None is used to indicate that the file should
- not exist.
- """
- self.files = files
-
- def exists(self, path):
- if path in self.files:
- return self.files[path] is not None
- return False
-
- def join(self, *comps):
- # os.path.join ignores trailing slashes on components (i.e.
- # join('foo/', 'bar') and join('foo', 'bar') produce the same result),
- # we emulate that behavior.
- trimmed_comps = []
- for comp in comps:
- if len(comp) and comp[-1] == '/':
- trimmed_comps.append(comp[0:-1])
- else:
- trimmed_comps.append(comp)
- return '/'.join(trimmed_comps)
-
- def maybe_make_directory(self, *path):
- # FIXME: Implement such that subsequent calls to isdir() work?
- pass
-
- def read_text_file(self, path):
- return self.read_binary_file(path)
-
- def read_binary_file(self, path):
- if path in self.files:
- if self.files[path] is None:
- raise IOError(errno.ENOENT, path, os.strerror(errno.ENOENT))
- return self.files[path]
-
- def write_text_file(self, path, contents):
- return self.write_binary_file(path, contents)
-
- def write_binary_file(self, path, contents):
- self.files[path] = contents
diff --git a/WebKitTools/Scripts/webkitpy/common/system/filesystem_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/filesystem_unittest.py
deleted file mode 100644
index 95684b7..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/filesystem_unittest.py
+++ /dev/null
@@ -1,157 +0,0 @@
-# vim: set fileencoding=utf-8 :
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# NOTE: The fileencoding comment on the first line of the file is
-# important; without it, Python will choke while trying to parse the file,
-# since it includes non-ASCII characters.
-
-from __future__ import with_statement
-
-import os
-import stat
-import sys
-import tempfile
-import unittest
-
-from filesystem import FileSystem
-
-
-class FileSystemTest(unittest.TestCase):
- def setUp(self):
- self._this_dir = os.path.dirname(os.path.abspath(__file__))
- 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_exists__true(self):
- fs = FileSystem()
- self.assertTrue(fs.exists(self._this_file))
-
- def test_exists__false(self):
- fs = FileSystem()
- self.assertFalse(fs.exists(self._missing_file))
-
- def test_isdir__true(self):
- fs = FileSystem()
- self.assertTrue(fs.isdir(self._this_dir))
-
- def test_isdir__false(self):
- fs = FileSystem()
- self.assertFalse(fs.isdir(self._this_file))
-
- def test_join(self):
- fs = FileSystem()
- self.assertEqual(fs.join('foo', 'bar'),
- os.path.join('foo', 'bar'))
-
- def test_listdir(self):
- fs = FileSystem()
- with fs.mkdtemp(prefix='filesystem_unittest_') as d:
- self.assertEqual(fs.listdir(d), [])
- new_file = os.path.join(d, 'foo')
- fs.write_text_file(new_file, u'foo')
- self.assertEqual(fs.listdir(d), ['foo'])
- os.remove(new_file)
-
- def test_maybe_make_directory__success(self):
- fs = FileSystem()
-
- with fs.mkdtemp(prefix='filesystem_unittest_') as base_path:
- sub_path = os.path.join(base_path, "newdir")
- self.assertFalse(os.path.exists(sub_path))
- self.assertFalse(fs.isdir(sub_path))
-
- fs.maybe_make_directory(sub_path)
- self.assertTrue(os.path.exists(sub_path))
- self.assertTrue(fs.isdir(sub_path))
-
- # Make sure we can re-create it.
- fs.maybe_make_directory(sub_path)
- self.assertTrue(os.path.exists(sub_path))
- self.assertTrue(fs.isdir(sub_path))
-
- # Clean up.
- os.rmdir(sub_path)
-
- self.assertFalse(os.path.exists(base_path))
- self.assertFalse(fs.isdir(base_path))
-
- def test_maybe_make_directory__failure(self):
- # FIXME: os.chmod() doesn't work on Windows to set directories
- # as readonly, so we skip this test for now.
- if sys.platform in ('win32', 'cygwin'):
- return
-
- fs = FileSystem()
- with fs.mkdtemp(prefix='filesystem_unittest_') as d:
- # Remove write permissions on the parent directory.
- os.chmod(d, stat.S_IRUSR)
-
- # Now try to create a sub directory - should fail.
- sub_dir = fs.join(d, 'subdir')
- self.assertRaises(OSError, fs.maybe_make_directory, sub_dir)
-
- # Clean up in case the test failed and we did create the
- # directory.
- if os.path.exists(sub_dir):
- os.rmdir(sub_dir)
-
- def test_read_and_write_file(self):
- fs = FileSystem()
- text_path = None
- binary_path = None
-
- unicode_text_string = u'Ūnĭcōde̽'
- hex_equivalent = '\xC5\xAA\x6E\xC4\xAD\x63\xC5\x8D\x64\x65\xCC\xBD'
- try:
- text_path = tempfile.mktemp(prefix='tree_unittest_')
- binary_path = tempfile.mktemp(prefix='tree_unittest_')
- fs.write_text_file(text_path, unicode_text_string)
- contents = fs.read_binary_file(text_path)
- self.assertEqual(contents, hex_equivalent)
-
- fs.write_text_file(binary_path, hex_equivalent)
- text_contents = fs.read_text_file(binary_path)
- self.assertEqual(text_contents, unicode_text_string)
- except:
- if text_path:
- os.remove(text_path)
- if binary_path:
- os.remove(binary_path)
-
- def test_read_binary_file__missing(self):
- fs = FileSystem()
- self.assertRaises(IOError, fs.read_binary_file, self._missing_file)
-
- def test_read_text_file__missing(self):
- fs = FileSystem()
- self.assertRaises(IOError, fs.read_text_file, self._missing_file)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/system/fileutils.py b/WebKitTools/Scripts/webkitpy/common/system/fileutils.py
deleted file mode 100644
index 55821f8..0000000
--- a/WebKitTools/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/WebKitTools/Scripts/webkitpy/common/system/logtesting.py b/WebKitTools/Scripts/webkitpy/common/system/logtesting.py
deleted file mode 100644
index e361cb5..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/logtesting.py
+++ /dev/null
@@ -1,258 +0,0 @@
-# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
-#
-# 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.
-
-"""Supports the unit-testing of logging code.
-
-Provides support for unit-testing messages logged using the built-in
-logging module.
-
-Inherit from the LoggingTestCase class for basic testing needs. For
-more advanced needs (e.g. unit-testing methods that configure logging),
-see the TestLogStream class, and perhaps also the LogTesting class.
-
-"""
-
-import logging
-import unittest
-
-
-class TestLogStream(object):
-
- """Represents a file-like object for unit-testing logging.
-
- This is meant for passing to the logging.StreamHandler constructor.
- Log messages captured by instances of this object can be tested
- using self.assertMessages() below.
-
- """
-
- def __init__(self, test_case):
- """Create an instance.
-
- Args:
- test_case: A unittest.TestCase instance.
-
- """
- self._test_case = test_case
- self.messages = []
- """A list of log messages written to the stream."""
-
- # Python documentation says that any object passed to the StreamHandler
- # constructor should support write() and flush():
- #
- # http://docs.python.org/library/logging.html#module-logging.handlers
- def write(self, message):
- self.messages.append(message)
-
- def flush(self):
- pass
-
- def assertMessages(self, messages):
- """Assert that the given messages match the logged messages.
-
- messages: A list of log message strings.
-
- """
- self._test_case.assertEquals(messages, self.messages)
-
-
-class LogTesting(object):
-
- """Supports end-to-end unit-testing of log messages.
-
- Sample usage:
-
- class SampleTest(unittest.TestCase):
-
- def setUp(self):
- self._log = LogTesting.setUp(self) # Turn logging on.
-
- def tearDown(self):
- self._log.tearDown() # Turn off and reset logging.
-
- def test_logging_in_some_method(self):
- call_some_method() # Contains calls to _log.info(), etc.
-
- # Check the resulting log messages.
- self._log.assertMessages(["INFO: expected message #1",
- "WARNING: expected message #2"])
-
- """
-
- def __init__(self, test_stream, handler):
- """Create an instance.
-
- This method should never be called directly. Instances should
- instead be created using the static setUp() method.
-
- Args:
- test_stream: A TestLogStream instance.
- handler: The handler added to the logger.
-
- """
- self._test_stream = test_stream
- self._handler = handler
-
- @staticmethod
- def _getLogger():
- """Return the logger being tested."""
- # It is possible we might want to return something other than
- # the root logger in some special situation. For now, the
- # root logger seems to suffice.
- return logging.getLogger()
-
- @staticmethod
- def setUp(test_case, logging_level=logging.INFO):
- """Configure logging for unit testing.
-
- Configures the root logger to log to a testing log stream.
- Only messages logged at or above the given level are logged
- to the stream. Messages logged to the stream are formatted
- in the following way, for example--
-
- "INFO: This is a test log message."
-
- This method should normally be called in the setUp() method
- of a unittest.TestCase. See the docstring of this class
- for more details.
-
- Returns:
- A LogTesting instance.
-
- Args:
- test_case: A unittest.TestCase instance.
- logging_level: An integer logging level that is the minimum level
- of log messages you would like to test.
-
- """
- stream = TestLogStream(test_case)
- handler = logging.StreamHandler(stream)
- handler.setLevel(logging_level)
- formatter = logging.Formatter("%(levelname)s: %(message)s")
- handler.setFormatter(formatter)
-
- # Notice that we only change the root logger by adding a handler
- # to it. In particular, we do not reset its level using
- # logger.setLevel(). This ensures that we have not interfered
- # with how the code being tested may have configured the root
- # logger.
- logger = LogTesting._getLogger()
- logger.addHandler(handler)
-
- return LogTesting(stream, handler)
-
- def tearDown(self):
- """Assert there are no remaining log messages, and reset logging.
-
- This method asserts that there are no more messages in the array of
- log messages, and then restores logging to its original state.
- This method should normally be called in the tearDown() method of a
- unittest.TestCase. See the docstring of this class for more details.
-
- """
- self.assertMessages([])
- logger = LogTesting._getLogger()
- logger.removeHandler(self._handler)
-
- def messages(self):
- """Return the current list of log messages."""
- return self._test_stream.messages
-
- # FIXME: Add a clearMessages() method for cases where the caller
- # deliberately doesn't want to assert every message.
-
- # We clear the log messages after asserting since they are no longer
- # needed after asserting. This serves two purposes: (1) it simplifies
- # the calling code when we want to check multiple logging calls in a
- # single test method, and (2) it lets us check in the tearDown() method
- # that there are no remaining log messages to be asserted.
- #
- # The latter ensures that no extra log messages are getting logged that
- # the caller might not be aware of or may have forgotten to check for.
- # This gets us a bit more mileage out of our tests without writing any
- # additional code.
- def assertMessages(self, messages):
- """Assert the current array of log messages, and clear its contents.
-
- Args:
- messages: A list of log message strings.
-
- """
- try:
- self._test_stream.assertMessages(messages)
- finally:
- # We want to clear the array of messages even in the case of
- # an Exception (e.g. an AssertionError). Otherwise, another
- # AssertionError can occur in the tearDown() because the
- # array might not have gotten emptied.
- self._test_stream.messages = []
-
-
-# This class needs to inherit from unittest.TestCase. Otherwise, the
-# setUp() and tearDown() methods will not get fired for test case classes
-# that inherit from this class -- even if the class inherits from *both*
-# unittest.TestCase and LoggingTestCase.
-#
-# FIXME: Rename this class to LoggingTestCaseBase to be sure that
-# the unittest module does not interpret this class as a unittest
-# test case itself.
-class LoggingTestCase(unittest.TestCase):
-
- """Supports end-to-end unit-testing of log messages.
-
- Sample usage:
-
- class SampleTest(LoggingTestCase):
-
- def test_logging_in_some_method(self):
- call_some_method() # Contains calls to _log.info(), etc.
-
- # Check the resulting log messages.
- self.assertLog(["INFO: expected message #1",
- "WARNING: expected message #2"])
-
- """
-
- def setUp(self):
- self._log = LogTesting.setUp(self)
-
- def tearDown(self):
- self._log.tearDown()
-
- def logMessages(self):
- """Return the current list of log messages."""
- return self._log.messages()
-
- # FIXME: Add a clearMessages() method for cases where the caller
- # deliberately doesn't want to assert every message.
-
- # See the code comments preceding LogTesting.assertMessages() for
- # an explanation of why we clear the array of messages after
- # asserting its contents.
- def assertLog(self, messages):
- """Assert the current array of log messages, and clear its contents.
-
- Args:
- messages: A list of log message strings.
-
- """
- self._log.assertMessages(messages)
diff --git a/WebKitTools/Scripts/webkitpy/common/system/logutils.py b/WebKitTools/Scripts/webkitpy/common/system/logutils.py
deleted file mode 100644
index cd4e60f..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/logutils.py
+++ /dev/null
@@ -1,207 +0,0 @@
-# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
-#
-# 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.
-
-"""Supports webkitpy logging."""
-
-# FIXME: Move this file to webkitpy/python24 since logging needs to
-# be configured prior to running version-checking code.
-
-import logging
-import os
-import sys
-
-import webkitpy
-
-
-_log = logging.getLogger(__name__)
-
-# We set these directory paths lazily in get_logger() below.
-_scripts_dir = ""
-"""The normalized, absolute path to the ...Scripts directory."""
-
-_webkitpy_dir = ""
-"""The normalized, absolute path to the ...Scripts/webkitpy directory."""
-
-
-def _normalize_path(path):
- """Return the given path normalized.
-
- Converts a path to an absolute path, removes any trailing slashes,
- removes any extension, and lower-cases it.
-
- """
- path = os.path.abspath(path)
- path = os.path.normpath(path)
- path = os.path.splitext(path)[0] # Remove the extension, if any.
- path = path.lower()
-
- return path
-
-
-# Observe that the implementation of this function does not require
-# the use of any hard-coded strings like "webkitpy", etc.
-#
-# The main benefit this function has over using--
-#
-# _log = logging.getLogger(__name__)
-#
-# is that get_logger() returns the same value even if __name__ is
-# "__main__" -- i.e. even if the module is the script being executed
-# from the command-line.
-def get_logger(path):
- """Return a logging.logger for the given path.
-
- Returns:
- A logger whose name is the name of the module corresponding to
- the given path. If the module is in webkitpy, the name is
- the fully-qualified dotted module name beginning with webkitpy....
- Otherwise, the name is the base name of the module (i.e. without
- any dotted module name prefix).
-
- Args:
- path: The path of the module. Normally, this parameter should be
- the __file__ variable of the module.
-
- Sample usage:
-
- import webkitpy.common.system.logutils as logutils
-
- _log = logutils.get_logger(__file__)
-
- """
- # Since we assign to _scripts_dir and _webkitpy_dir in this function,
- # we need to declare them global.
- global _scripts_dir
- global _webkitpy_dir
-
- path = _normalize_path(path)
-
- # Lazily evaluate _webkitpy_dir and _scripts_dir.
- if not _scripts_dir:
- # The normalized, absolute path to ...Scripts/webkitpy/__init__.
- webkitpy_path = _normalize_path(webkitpy.__file__)
-
- _webkitpy_dir = os.path.split(webkitpy_path)[0]
- _scripts_dir = os.path.split(_webkitpy_dir)[0]
-
- if path.startswith(_webkitpy_dir):
- # Remove the initial Scripts directory portion, so the path
- # starts with /webkitpy, for example "/webkitpy/init/logutils".
- path = path[len(_scripts_dir):]
-
- parts = []
- while True:
- (path, tail) = os.path.split(path)
- if not tail:
- break
- parts.insert(0, tail)
-
- logger_name = ".".join(parts) # For example, webkitpy.common.system.logutils.
- else:
- # The path is outside of webkitpy. Default to the basename
- # without the extension.
- basename = os.path.basename(path)
- logger_name = os.path.splitext(basename)[0]
-
- return logging.getLogger(logger_name)
-
-
-def _default_handlers(stream):
- """Return a list of the default logging handlers to use.
-
- Args:
- stream: See the configure_logging() docstring.
-
- """
- # Create the filter.
- def should_log(record):
- """Return whether a logging.LogRecord should be logged."""
- # FIXME: Enable the logging of autoinstall messages once
- # autoinstall is adjusted. Currently, autoinstall logs
- # INFO messages when importing already-downloaded packages,
- # which is too verbose.
- if record.name.startswith("webkitpy.thirdparty.autoinstall"):
- return False
- return True
-
- logging_filter = logging.Filter()
- logging_filter.filter = should_log
-
- # Create the handler.
- handler = logging.StreamHandler(stream)
- formatter = logging.Formatter("%(name)s: [%(levelname)s] %(message)s")
- handler.setFormatter(formatter)
- handler.addFilter(logging_filter)
-
- return [handler]
-
-
-def configure_logging(logging_level=None, logger=None, stream=None,
- handlers=None):
- """Configure logging for standard purposes.
-
- Returns:
- A list of references to the logging handlers added to the root
- logger. This allows the caller to later remove the handlers
- using logger.removeHandler. This is useful primarily during unit
- testing where the caller may want to configure logging temporarily
- and then undo the configuring.
-
- Args:
- logging_level: The minimum logging level to log. Defaults to
- logging.INFO.
- logger: A logging.logger instance to configure. This parameter
- should be used only in unit tests. Defaults to the
- root logger.
- stream: A file-like object to which to log used in creating the default
- handlers. The stream must define an "encoding" data attribute,
- or else logging raises an error. Defaults to sys.stderr.
- handlers: A list of logging.Handler instances to add to the logger
- being configured. If this parameter is provided, then the
- stream parameter is not used.
-
- """
- # If the stream does not define an "encoding" data attribute, the
- # logging module can throw an error like the following:
- #
- # Traceback (most recent call last):
- # File "/System/Library/Frameworks/Python.framework/Versions/2.6/...
- # lib/python2.6/logging/__init__.py", line 761, in emit
- # self.stream.write(fs % msg.encode(self.stream.encoding))
- # LookupError: unknown encoding: unknown
- if logging_level is None:
- logging_level = logging.INFO
- if logger is None:
- logger = logging.getLogger()
- if stream is None:
- stream = sys.stderr
- if handlers is None:
- handlers = _default_handlers(stream)
-
- logger.setLevel(logging_level)
-
- for handler in handlers:
- logger.addHandler(handler)
-
- _log.debug("Debug logging enabled.")
-
- return handlers
diff --git a/WebKitTools/Scripts/webkitpy/common/system/logutils_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/logutils_unittest.py
deleted file mode 100644
index a4a6496..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/logutils_unittest.py
+++ /dev/null
@@ -1,142 +0,0 @@
-# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
-#
-# 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.
-
-"""Unit tests for logutils.py."""
-
-import logging
-import os
-import unittest
-
-from webkitpy.common.system.logtesting import LogTesting
-from webkitpy.common.system.logtesting import TestLogStream
-import webkitpy.common.system.logutils as logutils
-
-
-class GetLoggerTest(unittest.TestCase):
-
- """Tests get_logger()."""
-
- def test_get_logger_in_webkitpy(self):
- logger = logutils.get_logger(__file__)
- self.assertEquals(logger.name, "webkitpy.common.system.logutils_unittest")
-
- def test_get_logger_not_in_webkitpy(self):
- # Temporarily change the working directory so that we
- # can test get_logger() for a path outside of webkitpy.
- working_directory = os.getcwd()
- root_dir = "/"
- os.chdir(root_dir)
-
- logger = logutils.get_logger("/WebKitTools/Scripts/test-webkitpy")
- self.assertEquals(logger.name, "test-webkitpy")
-
- logger = logutils.get_logger("/WebKitTools/Scripts/test-webkitpy.py")
- self.assertEquals(logger.name, "test-webkitpy")
-
- os.chdir(working_directory)
-
-
-class ConfigureLoggingTestBase(unittest.TestCase):
-
- """Base class for configure_logging() unit tests."""
-
- def _logging_level(self):
- raise Exception("Not implemented.")
-
- def setUp(self):
- log_stream = TestLogStream(self)
-
- # Use a logger other than the root logger or one prefixed with
- # "webkitpy." so as not to conflict with test-webkitpy logging.
- logger = logging.getLogger("unittest")
-
- # Configure the test logger not to pass messages along to the
- # root logger. This prevents test messages from being
- # propagated to loggers used by test-webkitpy logging (e.g.
- # the root logger).
- logger.propagate = False
-
- logging_level = self._logging_level()
- self._handlers = logutils.configure_logging(logging_level=logging_level,
- logger=logger,
- stream=log_stream)
- self._log = logger
- self._log_stream = log_stream
-
- def tearDown(self):
- """Reset logging to its original state.
-
- This method ensures that the logging configuration set up
- for a unit test does not affect logging in other unit tests.
-
- """
- logger = self._log
- for handler in self._handlers:
- logger.removeHandler(handler)
-
- def _assert_log_messages(self, messages):
- """Assert that the logged messages equal the given messages."""
- self._log_stream.assertMessages(messages)
-
-
-class ConfigureLoggingTest(ConfigureLoggingTestBase):
-
- """Tests configure_logging() with the default logging level."""
-
- def _logging_level(self):
- return None
-
- def test_info_message(self):
- self._log.info("test message")
- self._assert_log_messages(["unittest: [INFO] test message\n"])
-
- def test_below_threshold_message(self):
- # We test the boundary case of a logging level equal to 19.
- # In practice, we will probably only be calling log.debug(),
- # which corresponds to a logging level of 10.
- level = logging.INFO - 1 # Equals 19.
- self._log.log(level, "test message")
- self._assert_log_messages([])
-
- def test_two_messages(self):
- self._log.info("message1")
- self._log.info("message2")
- self._assert_log_messages(["unittest: [INFO] message1\n",
- "unittest: [INFO] message2\n"])
-
-
-class ConfigureLoggingCustomLevelTest(ConfigureLoggingTestBase):
-
- """Tests configure_logging() with a custom logging level."""
-
- _level = 36
-
- def _logging_level(self):
- return self._level
-
- def test_logged_message(self):
- self._log.log(self._level, "test message")
- self._assert_log_messages(["unittest: [Level 36] test message\n"])
-
- def test_below_threshold_message(self):
- self._log.log(self._level - 1, "test message")
- self._assert_log_messages([])
diff --git a/WebKitTools/Scripts/webkitpy/common/system/ospath.py b/WebKitTools/Scripts/webkitpy/common/system/ospath.py
deleted file mode 100644
index aed7a3d..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/ospath.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
-#
-# 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.
-
-"""Contains a substitute for Python 2.6's os.path.relpath()."""
-
-import os
-
-
-# This function is a replacement for os.path.relpath(), which is only
-# available in Python 2.6:
-#
-# http://docs.python.org/library/os.path.html#os.path.relpath
-#
-# It should behave essentially the same as os.path.relpath(), except for
-# returning None on paths not contained in abs_start_path.
-def relpath(path, start_path, os_path_abspath=None):
- """Return a path relative to the given start path, or None.
-
- Returns None if the path is not contained in the directory start_path.
-
- Args:
- path: An absolute or relative path to convert to a relative path.
- start_path: The path relative to which the given path should be
- converted.
- os_path_abspath: A replacement function for unit testing. This
- function should strip trailing slashes just like
- os.path.abspath(). Defaults to os.path.abspath.
-
- """
- if os_path_abspath is None:
- os_path_abspath = os.path.abspath
-
- # Since os_path_abspath() calls os.path.normpath()--
- #
- # (see http://docs.python.org/library/os.path.html#os.path.abspath )
- #
- # it also removes trailing slashes and converts forward and backward
- # slashes to the preferred slash os.sep.
- start_path = os_path_abspath(start_path)
- path = os_path_abspath(path)
-
- if not path.lower().startswith(start_path.lower()):
- # Then path is outside the directory given by start_path.
- return None
-
- rel_path = path[len(start_path):]
-
- if not rel_path:
- # Then the paths are the same.
- pass
- elif rel_path[0] == os.sep:
- # It is probably sufficient to remove just the first character
- # since os.path.normpath() collapses separators, but we use
- # lstrip() just to be sure.
- rel_path = rel_path.lstrip(os.sep)
- else:
- # We are in the case typified by the following example:
- #
- # start_path = "/tmp/foo"
- # path = "/tmp/foobar"
- # rel_path = "bar"
- return None
-
- return rel_path
diff --git a/WebKitTools/Scripts/webkitpy/common/system/ospath_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/ospath_unittest.py
deleted file mode 100644
index 0493c68..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/ospath_unittest.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
-#
-# 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.
-
-"""Unit tests for ospath.py."""
-
-import os
-import unittest
-
-from webkitpy.common.system.ospath import relpath
-
-
-# Make sure the tests in this class are platform independent.
-class RelPathTest(unittest.TestCase):
-
- """Tests relpath()."""
-
- os_path_abspath = lambda self, path: path
-
- def _rel_path(self, path, abs_start_path):
- return relpath(path, abs_start_path, self.os_path_abspath)
-
- def test_same_path(self):
- rel_path = self._rel_path("WebKit", "WebKit")
- self.assertEquals(rel_path, "")
-
- def test_long_rel_path(self):
- start_path = "WebKit"
- expected_rel_path = os.path.join("test", "Foo.txt")
- path = os.path.join(start_path, expected_rel_path)
-
- rel_path = self._rel_path(path, start_path)
- self.assertEquals(expected_rel_path, rel_path)
-
- def test_none_rel_path(self):
- """Test _rel_path() with None return value."""
- start_path = "WebKit"
- path = os.path.join("other_dir", "foo.txt")
-
- rel_path = self._rel_path(path, start_path)
- self.assertTrue(rel_path is None)
-
- rel_path = self._rel_path("WebKitTools", "WebKit")
- self.assertTrue(rel_path is None)
diff --git a/WebKitTools/Scripts/webkitpy/common/system/outputcapture.py b/WebKitTools/Scripts/webkitpy/common/system/outputcapture.py
deleted file mode 100644
index 45e0e3f..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/outputcapture.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# Copyright (c) 2009, 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Class for unittest support. Used for capturing stderr/stdout.
-
-import sys
-import unittest
-from StringIO import StringIO
-
-class OutputCapture(object):
- def __init__(self):
- self.saved_outputs = dict()
-
- def _capture_output_with_name(self, output_name):
- self.saved_outputs[output_name] = getattr(sys, output_name)
- captured_output = StringIO()
- setattr(sys, output_name, captured_output)
- return captured_output
-
- def _restore_output_with_name(self, output_name):
- captured_output = getattr(sys, output_name).getvalue()
- setattr(sys, output_name, self.saved_outputs[output_name])
- del self.saved_outputs[output_name]
- return captured_output
-
- def capture_output(self):
- return (self._capture_output_with_name("stdout"), self._capture_output_with_name("stderr"))
-
- def restore_output(self):
- return (self._restore_output_with_name("stdout"), self._restore_output_with_name("stderr"))
-
- def assert_outputs(self, testcase, function, args=[], kwargs={}, expected_stdout="", expected_stderr="", expected_exception=None):
- self.capture_output()
- if expected_exception:
- return_value = testcase.assertRaises(expected_exception, function, *args, **kwargs)
- else:
- return_value = function(*args, **kwargs)
- (stdout_string, stderr_string) = self.restore_output()
- testcase.assertEqual(stdout_string, expected_stdout)
- testcase.assertEqual(stderr_string, expected_stderr)
- # This is a little strange, but I don't know where else to return this information.
- return return_value
-
-
-class OutputCaptureTestCaseBase(unittest.TestCase):
- def setUp(self):
- unittest.TestCase.setUp(self)
- self.output_capture = OutputCapture()
- (self.__captured_stdout, self.__captured_stderr) = self.output_capture.capture_output()
-
- def tearDown(self):
- del self.__captured_stdout
- del self.__captured_stderr
- self.output_capture.restore_output()
- unittest.TestCase.tearDown(self)
-
- def assertStdout(self, expected_stdout):
- self.assertEquals(expected_stdout, self.__captured_stdout.getvalue())
-
- def assertStderr(self, expected_stderr):
- self.assertEquals(expected_stderr, self.__captured_stderr.getvalue())
diff --git a/WebKitTools/Scripts/webkitpy/common/system/path.py b/WebKitTools/Scripts/webkitpy/common/system/path.py
deleted file mode 100644
index 09787d7..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/path.py
+++ /dev/null
@@ -1,138 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""generic routines to convert platform-specific paths to URIs."""
-from __future__ import with_statement
-
-import atexit
-import subprocess
-import sys
-import threading
-import urllib
-
-
-def abspath_to_uri(path, platform=None):
- """Converts a platform-specific absolute path to a file: URL."""
- if platform is None:
- platform = sys.platform
- return "file:" + _escape(_convert_path(path, platform))
-
-
-def cygpath(path):
- """Converts an absolute cygwin path to an absolute Windows path."""
- return _CygPath.convert_using_singleton(path)
-
-
-# Note that this object is not threadsafe and must only be called
-# from multiple threads under protection of a lock (as is done in cygpath())
-class _CygPath(object):
- """Manages a long-running 'cygpath' process for file conversion."""
- _lock = None
- _singleton = None
-
- @staticmethod
- def stop_cygpath_subprocess():
- if not _CygPath._lock:
- return
-
- with _CygPath._lock:
- if _CygPath._singleton:
- _CygPath._singleton.stop()
-
- @staticmethod
- def convert_using_singleton(path):
- if not _CygPath._lock:
- _CygPath._lock = threading.Lock()
-
- with _CygPath._lock:
- if not _CygPath._singleton:
- _CygPath._singleton = _CygPath()
- # Make sure the cygpath subprocess always gets shutdown cleanly.
- atexit.register(_CygPath.stop_cygpath_subprocess)
-
- return _CygPath._singleton.convert(path)
-
- def __init__(self):
- self._child_process = None
-
- def start(self):
- assert(self._child_process is None)
- args = ['cygpath', '-f', '-', '-wa']
- self._child_process = subprocess.Popen(args,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE)
-
- def is_running(self):
- if not self._child_process:
- return False
- return self._child_process.returncode is None
-
- def stop(self):
- if self._child_process:
- self._child_process.stdin.close()
- self._child_process.wait()
- self._child_process = None
-
- def convert(self, path):
- if not self.is_running():
- self.start()
- self._child_process.stdin.write("%s\r\n" % path)
- self._child_process.stdin.flush()
- windows_path = self._child_process.stdout.readline().rstrip()
- # Some versions of cygpath use lowercase drive letters while others
- # use uppercase. We always convert to uppercase for consistency.
- windows_path = '%s%s' % (windows_path[0].upper(), windows_path[1:])
- return windows_path
-
-
-def _escape(path):
- """Handle any characters in the path that should be escaped."""
- # FIXME: web browsers don't appear to blindly quote every character
- # when converting filenames to files. Instead of using urllib's default
- # rules, we allow a small list of other characters through un-escaped.
- # It's unclear if this is the best possible solution.
- return urllib.quote(path, safe='/+:')
-
-
-def _convert_path(path, platform):
- """Handles any os-specific path separators, mappings, etc."""
- if platform == 'win32':
- return _winpath_to_uri(path)
- if platform == 'cygwin':
- return _winpath_to_uri(cygpath(path))
- return _unixypath_to_uri(path)
-
-
-def _winpath_to_uri(path):
- """Converts a window absolute path to a file: URL."""
- return "///" + path.replace("\\", "/")
-
-
-def _unixypath_to_uri(path):
- """Converts a unix-style path to a file: URL."""
- return "//" + path
diff --git a/WebKitTools/Scripts/webkitpy/common/system/path_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/path_unittest.py
deleted file mode 100644
index 4dbd38a..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/path_unittest.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-import sys
-
-import path
-
-class AbspathTest(unittest.TestCase):
- def assertMatch(self, test_path, expected_uri,
- platform=None):
- if platform == 'cygwin' and sys.platform != 'cygwin':
- return
- self.assertEqual(path.abspath_to_uri(test_path, platform=platform),
- expected_uri)
-
- def test_abspath_to_uri_cygwin(self):
- if sys.platform != 'cygwin':
- return
-
- self.assertMatch('/cygdrive/c/foo/bar.html',
- 'file:///C:/foo/bar.html',
- platform='cygwin')
- self.assertEqual(path.abspath_to_uri('/cygdrive/c/foo/bar.html',
- platform='cygwin'),
- 'file:///C:/foo/bar.html')
-
- def test_abspath_to_uri_darwin(self):
- self.assertMatch('/foo/bar.html',
- 'file:///foo/bar.html',
- platform='darwin')
- self.assertEqual(path.abspath_to_uri("/foo/bar.html",
- platform='darwin'),
- "file:///foo/bar.html")
-
- def test_abspath_to_uri_linux2(self):
- self.assertMatch('/foo/bar.html',
- 'file:///foo/bar.html',
- platform='darwin')
- self.assertEqual(path.abspath_to_uri("/foo/bar.html",
- platform='linux2'),
- "file:///foo/bar.html")
-
- def test_abspath_to_uri_win(self):
- self.assertMatch('c:\\foo\\bar.html',
- 'file:///c:/foo/bar.html',
- platform='win32')
- self.assertEqual(path.abspath_to_uri("c:\\foo\\bar.html",
- platform='win32'),
- "file:///c:/foo/bar.html")
-
- def test_abspath_to_uri_escaping(self):
- self.assertMatch('/foo/bar + baz%?.html',
- 'file:///foo/bar%20+%20baz%25%3F.html',
- platform='darwin')
- self.assertMatch('/foo/bar + baz%?.html',
- 'file:///foo/bar%20+%20baz%25%3F.html',
- platform='linux2')
-
- # Note that you can't have '?' in a filename on windows.
- self.assertMatch('/cygdrive/c/foo/bar + baz%.html',
- 'file:///C:/foo/bar%20+%20baz%25.html',
- platform='cygwin')
-
- def test_stop_cygpath_subprocess(self):
- if sys.platform != 'cygwin':
- return
-
- # Call cygpath to ensure the subprocess is running.
- path.cygpath("/cygdrive/c/foo.txt")
- self.assertTrue(path._CygPath._singleton.is_running())
-
- # Stop it.
- path._CygPath.stop_cygpath_subprocess()
-
- # Ensure that it is stopped.
- self.assertFalse(path._CygPath._singleton.is_running())
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/system/user.py b/WebKitTools/Scripts/webkitpy/common/system/user.py
deleted file mode 100644
index 8917137..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/user.py
+++ /dev/null
@@ -1,143 +0,0 @@
-# Copyright (c) 2009, 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import logging
-import os
-import re
-import shlex
-import subprocess
-import sys
-import webbrowser
-
-
-_log = logging.getLogger("webkitpy.common.system.user")
-
-
-try:
- import readline
-except ImportError:
- if sys.platform != "win32":
- # There is no readline module for win32, not much to do except cry.
- _log.warn("Unable to import readline.")
- # FIXME: We could give instructions for non-mac platforms.
- # Lack of readline results in a very bad user experiance.
- if sys.platform == "mac":
- _log.warn("If you're using MacPorts, try running:")
- _log.warn(" sudo port install py25-readline")
-
-
-class User(object):
- DEFAULT_NO = 'n'
- DEFAULT_YES = 'y'
-
- # FIXME: These are @classmethods because bugzilla.py doesn't have a Tool object (thus no User instance).
- @classmethod
- def prompt(cls, message, repeat=1, raw_input=raw_input):
- response = None
- while (repeat and not response):
- repeat -= 1
- response = raw_input(message)
- return response
-
- @classmethod
- def prompt_with_list(cls, list_title, list_items, can_choose_multiple=False, raw_input=raw_input):
- print list_title
- i = 0
- for item in list_items:
- i += 1
- print "%2d. %s" % (i, item)
-
- # Loop until we get valid input
- while True:
- if can_choose_multiple:
- response = cls.prompt("Enter one or more numbers (comma-separated), or \"all\": ", raw_input=raw_input)
- if not response.strip() or response == "all":
- return list_items
- try:
- indices = [int(r) - 1 for r in re.split("\s*,\s*", response)]
- except ValueError, err:
- continue
- return [list_items[i] for i in indices]
- else:
- try:
- result = int(cls.prompt("Enter a number: ", raw_input=raw_input)) - 1
- except ValueError, err:
- continue
- return list_items[result]
-
- def edit(self, files):
- editor = os.environ.get("EDITOR") or "vi"
- args = shlex.split(editor)
- # Note: Not thread safe: http://bugs.python.org/issue2320
- subprocess.call(args + files)
-
- def _warn_if_application_is_xcode(self, edit_application):
- if "Xcode" in edit_application:
- print "Instead of using Xcode.app, consider using EDITOR=\"xed --wait\"."
-
- def edit_changelog(self, files):
- edit_application = os.environ.get("CHANGE_LOG_EDIT_APPLICATION")
- if edit_application and sys.platform == "darwin":
- # On Mac we support editing ChangeLogs using an application.
- args = shlex.split(edit_application)
- print "Using editor in the CHANGE_LOG_EDIT_APPLICATION environment variable."
- print "Please quit the editor application when done editing."
- self._warn_if_application_is_xcode(edit_application)
- subprocess.call(["open", "-W", "-n", "-a"] + args + files)
- return
- self.edit(files)
-
- def page(self, message):
- pager = os.environ.get("PAGER") or "less"
- try:
- # Note: Not thread safe: http://bugs.python.org/issue2320
- child_process = subprocess.Popen([pager], stdin=subprocess.PIPE)
- child_process.communicate(input=message)
- except IOError, e:
- pass
-
- def confirm(self, message=None, default=DEFAULT_YES, raw_input=raw_input):
- if not message:
- message = "Continue?"
- choice = {'y': 'Y/n', 'n': 'y/N'}[default]
- response = raw_input("%s [%s]: " % (message, choice))
- if not response:
- response = default
- return response.lower() == 'y'
-
- def can_open_url(self):
- try:
- webbrowser.get()
- return True
- except webbrowser.Error, e:
- return False
-
- def open_url(self, url):
- if not self.can_open_url():
- _log.warn("Failed to open %s" % url)
- webbrowser.open(url)
diff --git a/WebKitTools/Scripts/webkitpy/common/system/user_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/user_unittest.py
deleted file mode 100644
index 7ec9b34..0000000
--- a/WebKitTools/Scripts/webkitpy/common/system/user_unittest.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# Copyright (C) 2010 Research in Motion Ltd. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Research in Motion Ltd. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.common.system.user import User
-
-class UserTest(unittest.TestCase):
-
- example_user_response = "example user response"
-
- def test_prompt_repeat(self):
- self.repeatsRemaining = 2
- def mock_raw_input(message):
- self.repeatsRemaining -= 1
- if not self.repeatsRemaining:
- return UserTest.example_user_response
- return None
- self.assertEqual(User.prompt("input", repeat=self.repeatsRemaining, raw_input=mock_raw_input), UserTest.example_user_response)
-
- def test_prompt_when_exceeded_repeats(self):
- self.repeatsRemaining = 2
- def mock_raw_input(message):
- self.repeatsRemaining -= 1
- return None
- self.assertEqual(User.prompt("input", repeat=self.repeatsRemaining, raw_input=mock_raw_input), None)
-
- def test_prompt_with_list(self):
- def run_prompt_test(inputs, expected_result, can_choose_multiple=False):
- def mock_raw_input(message):
- return inputs.pop(0)
- output_capture = OutputCapture()
- actual_result = output_capture.assert_outputs(
- self,
- User.prompt_with_list,
- args=["title", ["foo", "bar"]],
- kwargs={"can_choose_multiple": can_choose_multiple, "raw_input": mock_raw_input},
- expected_stdout="title\n 1. foo\n 2. bar\n")
- self.assertEqual(actual_result, expected_result)
- self.assertEqual(len(inputs), 0)
-
- run_prompt_test(["1"], "foo")
- run_prompt_test(["badinput", "2"], "bar")
-
- run_prompt_test(["1,2"], ["foo", "bar"], can_choose_multiple=True)
- run_prompt_test([" 1, 2 "], ["foo", "bar"], can_choose_multiple=True)
- run_prompt_test(["all"], ["foo", "bar"], can_choose_multiple=True)
- run_prompt_test([""], ["foo", "bar"], can_choose_multiple=True)
- run_prompt_test([" "], ["foo", "bar"], can_choose_multiple=True)
- run_prompt_test(["badinput", "all"], ["foo", "bar"], can_choose_multiple=True)
-
- def test_confirm(self):
- test_cases = (
- (("Continue? [Y/n]: ", True), (User.DEFAULT_YES, 'y')),
- (("Continue? [Y/n]: ", False), (User.DEFAULT_YES, 'n')),
- (("Continue? [Y/n]: ", True), (User.DEFAULT_YES, '')),
- (("Continue? [Y/n]: ", False), (User.DEFAULT_YES, 'q')),
- (("Continue? [y/N]: ", True), (User.DEFAULT_NO, 'y')),
- (("Continue? [y/N]: ", False), (User.DEFAULT_NO, 'n')),
- (("Continue? [y/N]: ", False), (User.DEFAULT_NO, '')),
- (("Continue? [y/N]: ", False), (User.DEFAULT_NO, 'q')),
- )
- for test_case in test_cases:
- expected, inputs = test_case
-
- def mock_raw_input(message):
- self.assertEquals(expected[0], message)
- return inputs[1]
-
- result = User().confirm(default=inputs[0],
- raw_input=mock_raw_input)
- self.assertEquals(expected[1], result)
-
- def test_warn_if_application_is_xcode(self):
- output = OutputCapture()
- user = User()
- output.assert_outputs(self, user._warn_if_application_is_xcode, ["TextMate"])
- output.assert_outputs(self, user._warn_if_application_is_xcode, ["/Applications/TextMate.app"])
- output.assert_outputs(self, user._warn_if_application_is_xcode, ["XCode"]) # case sensitive matching
-
- xcode_warning = "Instead of using Xcode.app, consider using EDITOR=\"xed --wait\".\n"
- output.assert_outputs(self, user._warn_if_application_is_xcode, ["Xcode"], expected_stdout=xcode_warning)
- output.assert_outputs(self, user._warn_if_application_is_xcode, ["/Developer/Applications/Xcode.app"], expected_stdout=xcode_warning)
diff --git a/WebKitTools/Scripts/webkitpy/common/thread/__init__.py b/WebKitTools/Scripts/webkitpy/common/thread/__init__.py
deleted file mode 100644
index ef65bee..0000000
--- a/WebKitTools/Scripts/webkitpy/common/thread/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Required for Python to search this directory for module files
diff --git a/WebKitTools/Scripts/webkitpy/common/thread/messagepump.py b/WebKitTools/Scripts/webkitpy/common/thread/messagepump.py
deleted file mode 100644
index 0e39285..0000000
--- a/WebKitTools/Scripts/webkitpy/common/thread/messagepump.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-class MessagePumpDelegate(object):
- def schedule(self, interval, callback):
- raise NotImplementedError, "subclasses must implement"
-
- def message_available(self, message):
- raise NotImplementedError, "subclasses must implement"
-
- def final_message_delivered(self):
- raise NotImplementedError, "subclasses must implement"
-
-
-class MessagePump(object):
- interval = 10 # seconds
-
- def __init__(self, delegate, message_queue):
- self._delegate = delegate
- self._message_queue = message_queue
- self._schedule()
-
- def _schedule(self):
- self._delegate.schedule(self.interval, self._callback)
-
- def _callback(self):
- (messages, is_running) = self._message_queue.take_all()
- for message in messages:
- self._delegate.message_available(message)
- if not is_running:
- self._delegate.final_message_delivered()
- return
- self._schedule()
diff --git a/WebKitTools/Scripts/webkitpy/common/thread/messagepump_unittest.py b/WebKitTools/Scripts/webkitpy/common/thread/messagepump_unittest.py
deleted file mode 100644
index f731db2..0000000
--- a/WebKitTools/Scripts/webkitpy/common/thread/messagepump_unittest.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from webkitpy.common.thread.messagepump import MessagePump, MessagePumpDelegate
-from webkitpy.common.thread.threadedmessagequeue import ThreadedMessageQueue
-
-
-class TestDelegate(MessagePumpDelegate):
- def __init__(self):
- self.log = []
-
- def schedule(self, interval, callback):
- self.callback = callback
- self.log.append("schedule")
-
- def message_available(self, message):
- self.log.append("message_available: %s" % message)
-
- def final_message_delivered(self):
- self.log.append("final_message_delivered")
-
-
-class MessagePumpTest(unittest.TestCase):
-
- def test_basic(self):
- queue = ThreadedMessageQueue()
- delegate = TestDelegate()
- pump = MessagePump(delegate, queue)
- self.assertEqual(delegate.log, [
- 'schedule'
- ])
- delegate.callback()
- queue.post("Hello")
- queue.post("There")
- delegate.callback()
- self.assertEqual(delegate.log, [
- 'schedule',
- 'schedule',
- 'message_available: Hello',
- 'message_available: There',
- 'schedule'
- ])
- queue.post("More")
- queue.post("Messages")
- queue.stop()
- delegate.callback()
- self.assertEqual(delegate.log, [
- 'schedule',
- 'schedule',
- 'message_available: Hello',
- 'message_available: There',
- 'schedule',
- 'message_available: More',
- 'message_available: Messages',
- 'final_message_delivered'
- ])
diff --git a/WebKitTools/Scripts/webkitpy/common/thread/threadedmessagequeue.py b/WebKitTools/Scripts/webkitpy/common/thread/threadedmessagequeue.py
deleted file mode 100644
index 17b6277..0000000
--- a/WebKitTools/Scripts/webkitpy/common/thread/threadedmessagequeue.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-from __future__ import with_statement
-
-import threading
-
-
-class ThreadedMessageQueue(object):
- def __init__(self):
- self._messages = []
- self._is_running = True
- self._lock = threading.Lock()
-
- def post(self, message):
- with self._lock:
- self._messages.append(message)
-
- def stop(self):
- with self._lock:
- self._is_running = False
-
- def take_all(self):
- with self._lock:
- messages = self._messages
- is_running = self._is_running
- self._messages = []
- return (messages, is_running)
-
diff --git a/WebKitTools/Scripts/webkitpy/common/thread/threadedmessagequeue_unittest.py b/WebKitTools/Scripts/webkitpy/common/thread/threadedmessagequeue_unittest.py
deleted file mode 100644
index cb67c1e..0000000
--- a/WebKitTools/Scripts/webkitpy/common/thread/threadedmessagequeue_unittest.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# 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
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from webkitpy.common.thread.threadedmessagequeue import ThreadedMessageQueue
-
-class ThreadedMessageQueueTest(unittest.TestCase):
-
- def test_basic(self):
- queue = ThreadedMessageQueue()
- queue.post("Hello")
- queue.post("There")
- (messages, is_running) = queue.take_all()
- self.assertEqual(messages, ["Hello", "There"])
- self.assertTrue(is_running)
- (messages, is_running) = queue.take_all()
- self.assertEqual(messages, [])
- self.assertTrue(is_running)
- queue.post("More")
- queue.stop()
- queue.post("Messages")
- (messages, is_running) = queue.take_all()
- self.assertEqual(messages, ["More", "Messages"])
- self.assertFalse(is_running)
- (messages, is_running) = queue.take_all()
- self.assertEqual(messages, [])
- self.assertFalse(is_running)