summaryrefslogtreecommitdiffstats
path: root/WebKitTools/Scripts/webkitpy/common
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2010-11-04 12:00:17 -0700
committerJohn Reck <jreck@google.com>2010-11-09 11:35:04 -0800
commite14391e94c850b8bd03680c23b38978db68687a8 (patch)
tree3fed87e6620fecaf3edc7259ae58a11662bedcb2 /WebKitTools/Scripts/webkitpy/common
parent1bd705833a68f07850cf7e204b26f8d328d16951 (diff)
downloadexternal_webkit-e14391e94c850b8bd03680c23b38978db68687a8.zip
external_webkit-e14391e94c850b8bd03680c23b38978db68687a8.tar.gz
external_webkit-e14391e94c850b8bd03680c23b38978db68687a8.tar.bz2
Merge Webkit at r70949: Initial merge by git.
Change-Id: I77b8645c083b5d0da8dba73ed01d4014aab9848e
Diffstat (limited to 'WebKitTools/Scripts/webkitpy/common')
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/__init__.py2
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/api.py14
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/api_unittest.py4
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/scm.py47
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py9
-rw-r--r--WebKitTools/Scripts/webkitpy/common/config/__init__.py5
-rw-r--r--WebKitTools/Scripts/webkitpy/common/config/committers.py4
-rw-r--r--WebKitTools/Scripts/webkitpy/common/memoized.py (renamed from WebKitTools/Scripts/webkitpy/common/net/rietveld_unittest.py)32
-rw-r--r--WebKitTools/Scripts/webkitpy/common/memoized_unittest.py65
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/bugzilla.py25
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/bugzilla_unittest.py7
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/credentials.py57
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/credentials_unittest.py66
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/rietveld.py79
-rw-r--r--WebKitTools/Scripts/webkitpy/common/net/statusserver.py2
15 files changed, 233 insertions, 185 deletions
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/__init__.py b/WebKitTools/Scripts/webkitpy/common/checkout/__init__.py
index ef65bee..597dcbd 100644
--- a/WebKitTools/Scripts/webkitpy/common/checkout/__init__.py
+++ b/WebKitTools/Scripts/webkitpy/common/checkout/__init__.py
@@ -1 +1,3 @@
# 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
index 72cad8d..dbe1e84 100644
--- a/WebKitTools/Scripts/webkitpy/common/checkout/api.py
+++ b/WebKitTools/Scripts/webkitpy/common/checkout/api.py
@@ -32,6 +32,7 @@ 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
@@ -59,6 +60,7 @@ class Checkout(object):
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)
@@ -98,8 +100,8 @@ class Checkout(object):
def modified_non_changelogs(self, git_commit, changed_files=None):
return self._modified_files_matching_predicate(git_commit, lambda path: not self._is_path_to_changelog(path), changed_files=changed_files)
- def commit_message_for_this_commit(self, git_commit):
- changelog_paths = self.modified_changelogs(git_commit)
+ 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"
@@ -120,16 +122,16 @@ class Checkout(object):
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 = self.modified_non_changelogs(git_commit)
+ 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):
+ 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).message())
+ return parse_bug_id(self.commit_message_for_this_commit(git_commit, changed_files).message())
except ScriptError, e:
pass # We might not have ChangeLogs.
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/api_unittest.py b/WebKitTools/Scripts/webkitpy/common/checkout/api_unittest.py
index d7bd95e..1f97abd 100644
--- a/WebKitTools/Scripts/webkitpy/common/checkout/api_unittest.py
+++ b/WebKitTools/Scripts/webkitpy/common/checkout/api_unittest.py
@@ -114,7 +114,7 @@ class CommitMessageForThisCommitTest(unittest.TestCase):
# ChangeLog is difficult to mock at current.
def test_commit_message_for_this_commit(self):
checkout = Checkout(None)
- checkout.modified_changelogs = lambda git_commit: ["ChangeLog1", "ChangeLog2"]
+ 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,
@@ -163,7 +163,7 @@ class CheckoutTest(unittest.TestCase):
def test_bug_id_for_this_commit(self):
scm = Mock()
checkout = Checkout(scm)
- checkout.commit_message_for_this_commit = lambda git_commit: CommitMessage(ChangeLogEntry(_changelog1entry1).contents().splitlines())
+ 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):
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/scm.py b/WebKitTools/Scripts/webkitpy/common/checkout/scm.py
index 4bd9ed6..9b602c3 100644
--- a/WebKitTools/Scripts/webkitpy/common/checkout/scm.py
+++ b/WebKitTools/Scripts/webkitpy/common/checkout/scm.py
@@ -36,6 +36,7 @@ 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():
@@ -319,7 +320,6 @@ class SVN(SCM):
def __init__(self, cwd):
SCM.__init__(self, cwd)
- self.cached_version = None
self._bogus_dir = None
@staticmethod
@@ -369,16 +369,20 @@ class SVN(SCM):
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):
- if not self.cached_version:
- self.cached_version = self.run(['svn', '--version', '--quiet'])
-
- return self.cached_version
+ 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
@@ -432,6 +436,7 @@ class SVN(SCM):
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)
@@ -565,6 +570,7 @@ class SVN(SCM):
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):
@@ -667,7 +673,8 @@ class Git(SCM):
return self._changes_files_for_commit(commit_id)
def revisions_changing_file(self, path, limit=5):
- commit_ids = self.run(["git", "log", "--pretty=format:%H", "-%s" % limit, path]).splitlines()
+ # 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):
@@ -696,21 +703,29 @@ class Git(SCM):
# FIXME: This should probably use cwd=self.checkout_root
return self.run(['git', 'diff', '--binary', "--no-ext-diff", "--full-index", "-M", self.merge_base(git_commit), "--"] + changed_files, decode_output=False)
- @classmethod
- def git_commit_from_svn_revision(cls, revision):
- # FIXME: This should probably use cwd=self.checkout_root
- git_commit = run_command(['git', 'svn', 'find-rev', 'r%s' % revision]).rstrip()
- # git svn find-rev always exits 0, even when the revision is not found.
- if not git_commit:
- raise ScriptError(message='Failed to find git commit for revision %s, your checkout likely needs an update.' % revision)
- return git_commit
+ 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 svn_revision_from_git_commit(self, commit_id):
+ def _string_to_int_or_none(self, string):
try:
- return int(self.run(['git', 'svn', 'find-rev', commit_id]).rstrip())
+ 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."""
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py b/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py
index 4aa5279..8af9ad5 100644
--- a/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py
+++ b/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py
@@ -760,6 +760,15 @@ Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
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):
diff --git a/WebKitTools/Scripts/webkitpy/common/config/__init__.py b/WebKitTools/Scripts/webkitpy/common/config/__init__.py
index 62d129e..ef65bee 100644
--- a/WebKitTools/Scripts/webkitpy/common/config/__init__.py
+++ b/WebKitTools/Scripts/webkitpy/common/config/__init__.py
@@ -1,6 +1 @@
# Required for Python to search this directory for module files
-
-import re
-
-codereview_server_host = "wkrietveld.appspot.com"
-codereview_server_url = "https://%s/" % codereview_server_host
diff --git a/WebKitTools/Scripts/webkitpy/common/config/committers.py b/WebKitTools/Scripts/webkitpy/common/config/committers.py
index f768cf9..71d764c 100644
--- a/WebKitTools/Scripts/webkitpy/common/config/committers.py
+++ b/WebKitTools/Scripts/webkitpy/common/config/committers.py
@@ -137,6 +137,7 @@ committers_unable_to_review = [
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"),
@@ -146,6 +147,7 @@ committers_unable_to_review = [
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"]),
Committer("Matt Delaney", "mdelaney@apple.com"),
Committer("Matt Lilek", ["webkit@mattlilek.com", "pewtermoose@webkit.org"]),
Committer("Matt Perry", "mpcomplete@chromium.org"),
@@ -213,7 +215,7 @@ reviewers_list = [
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@sencha.com", "ariya.hidayat@gmail.com", "ariya@webkit.org"], "ariya"),
+ 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"]),
diff --git a/WebKitTools/Scripts/webkitpy/common/net/rietveld_unittest.py b/WebKitTools/Scripts/webkitpy/common/memoized.py
index 9c5a29e..dc844a5 100644
--- a/WebKitTools/Scripts/webkitpy/common/net/rietveld_unittest.py
+++ b/WebKitTools/Scripts/webkitpy/common/memoized.py
@@ -26,14 +26,30 @@
# (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
+# Python does not (yet) seem to provide automatic memoization. So we've
+# written a small decorator to do so.
-from webkitpy.common.net.rietveld import Rietveld
-from webkitpy.thirdparty.mock import Mock
+import functools
-class RietveldTest(unittest.TestCase):
- def test_url_for_issue(self):
- rietveld = Rietveld(Mock())
- self.assertEqual(rietveld.url_for_issue(34223),
- "https://wkrietveld.appspot.com/34223")
+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
new file mode 100644
index 0000000..dd7c793
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/common/memoized_unittest.py
@@ -0,0 +1,65 @@
+# 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/bugzilla.py b/WebKitTools/Scripts/webkitpy/common/net/bugzilla.py
index 94519a7..1cc8e2e 100644
--- a/WebKitTools/Scripts/webkitpy/common/net/bugzilla.py
+++ b/WebKitTools/Scripts/webkitpy/common/net/bugzilla.py
@@ -113,9 +113,6 @@ class Attachment(object):
def commit_queue(self):
return self._attachment_dictionary.get("commit-queue")
- def in_rietveld(self):
- return self._attachment_dictionary.get("in-rietveld")
-
def url(self):
# FIXME: This should just return
# self._bugzilla().attachment_url_for_id(self.id()). scm_unittest.py
@@ -221,9 +218,6 @@ class Bug(object):
# a valid committer.
return filter(lambda patch: patch.committer(), patches)
- def in_rietveld_queue_patches(self):
- return [patch for patch in self.patches() if patch.in_rietveld() == None]
-
# A container for all of the logic for making and parsing buzilla queries.
class BugzillaQueries(object):
@@ -287,16 +281,6 @@ class BugzillaQueries(object):
return sum([self._fetch_bug(bug_id).commit_queued_patches()
for bug_id in self.fetch_bug_ids_from_commit_queue()], [])
- def fetch_first_patch_from_rietveld_queue(self):
- # rietveld-queue processes all patches that don't have in-rietveld set.
- 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=notsubstring&value0-0-0=in-rietveld&field0-1-0=attachments.ispatch&type0-1-0=equals&value0-1-0=1&order=Last+Changed&field0-2-0=attachments.isobsolete&type0-2-0=equals&value0-2-0=0"
- bugs = self._fetch_bug_ids_advanced_query(query_url)
- if not len(bugs):
- return None
-
- patches = self._fetch_bug(bugs[0]).in_rietveld_queue_patches()
- return patches[0] if len(patches) else None
-
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)
@@ -502,8 +486,6 @@ class Bugzilla(object):
self._parse_attachment_flag(
element, 'review', attachment, 'reviewer_email')
self._parse_attachment_flag(
- element, 'in-rietveld', attachment, 'rietveld_uploader_email')
- self._parse_attachment_flag(
element, 'commit-queue', attachment, 'committer_email')
return attachment
@@ -591,11 +573,12 @@ class Bugzilla(object):
self.authenticated = True
return
+ credentials = Credentials(self.bug_server_host, git_prefix="bugzilla")
+
attempts = 0
while not self.authenticated:
attempts += 1
- (username, password) = Credentials(
- self.bug_server_host, git_prefix="bugzilla").read_credentials()
+ username, password = credentials.read_credentials()
log("Logging in as %s..." % username)
self.browser.open(self.bug_server_url +
@@ -766,8 +749,6 @@ class Bugzilla(object):
return self.browser.find_control(type='select', nr=0)
elif flag_name == "commit-queue":
return self.browser.find_control(type='select', nr=1)
- elif flag_name == "in-rietveld":
- return self.browser.find_control(type='select', nr=2)
raise Exception("Don't know how to find flag named \"%s\"" % flag_name)
def clear_attachment_flags(self,
diff --git a/WebKitTools/Scripts/webkitpy/common/net/bugzilla_unittest.py b/WebKitTools/Scripts/webkitpy/common/net/bugzilla_unittest.py
index 3a454d6..df1fcf6 100644
--- a/WebKitTools/Scripts/webkitpy/common/net/bugzilla_unittest.py
+++ b/WebKitTools/Scripts/webkitpy/common/net/bugzilla_unittest.py
@@ -83,11 +83,6 @@ class BugzillaTest(unittest.TestCase):
status="+"
setter="two@test.com"
/>
- <flag name="in-rietveld"
- id="17933"
- status="+"
- setter="three@test.com"
- />
</attachment>
'''
_expected_example_attachment_parsing = {
@@ -103,8 +98,6 @@ class BugzillaTest(unittest.TestCase):
'reviewer_email' : 'one@test.com',
'commit-queue' : '+',
'committer_email' : 'two@test.com',
- 'in-rietveld': '+',
- 'rietveld_uploader_email': 'three@test.com',
'attacher_email' : 'christian.plesner.hansen@gmail.com',
}
diff --git a/WebKitTools/Scripts/webkitpy/common/net/credentials.py b/WebKitTools/Scripts/webkitpy/common/net/credentials.py
index 1c3e6c0..30480b3 100644
--- a/WebKitTools/Scripts/webkitpy/common/net/credentials.py
+++ b/WebKitTools/Scripts/webkitpy/common/net/credentials.py
@@ -48,6 +48,7 @@ except ImportError:
class Credentials(object):
+ _environ_prefix = "webkit_bugzilla_"
def __init__(self, host, git_prefix=None, executive=None, cwd=os.getcwd(),
keyring=keyring):
@@ -58,8 +59,17 @@ class Credentials(object):
self._keyring = keyring
def _credentials_from_git(self):
- return [Git.read_git_config(self.git_prefix + "username"),
- Git.read_git_config(self.git_prefix + "password")]
+ 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,
@@ -110,21 +120,28 @@ class Credentials(object):
else:
return [None, None]
- def read_credentials(self):
- username = None
- password = None
+ def _read_environ(self, key):
+ environ_key = self._environ_prefix + key
+ return os.environ.get(environ_key.upper())
- try:
- if Git.in_working_directory(self.cwd):
- (username, password) = self._credentials_from_git()
- 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
+ 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)
+ username, password = self._credentials_from_keychain(username)
if username and not password and self._keyring:
password = self._keyring.get_password(self.host, username)
@@ -132,13 +149,7 @@ class Credentials(object):
if not username:
username = User.prompt("%s login: " % self.host)
if not password:
- password = getpass.getpass("%s password for %s: " % (self.host,
- username))
+ password = getpass.getpass("%s password for %s: " % (self.host, username))
+ self._offer_to_store_credentials_in_keyring(username, password)
- if self._keyring:
- store_password = User().confirm(
- "Store password in system keyring?", User.DEFAULT_NO)
- if store_password:
- self._keyring.set_password(self.host, username, password)
-
- return [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
index d30291b..6f2d909 100644
--- a/WebKitTools/Scripts/webkitpy/common/net/credentials_unittest.py
+++ b/WebKitTools/Scripts/webkitpy/common/net/credentials_unittest.py
@@ -26,6 +26,8 @@
# (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
@@ -34,6 +36,21 @@ 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"
@@ -101,40 +118,59 @@ password: "SECRETSAUCE"
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"]
+ 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"))
- temp_dir_path = tempfile.mkdtemp(suffix="not_a_git_repo")
- credentials = FakeCredentials("bugs.webkit.org", cwd=temp_dir_path)
- self.assertEqual(credentials.read_credentials(), ["test@webkit.org", "SECRETSAUCE"])
- os.rmdir(temp_dir_path)
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 __init__(self, cwd):
- Credentials.__init__(self, "fake.hostname", cwd=cwd,
- keyring=MockKeyring())
-
def _is_mac_os_x(self):
return True
def _credentials_from_keychain(self, username):
return ("test@webkit.org", None)
- temp_dir_path = tempfile.mkdtemp(suffix="not_a_git_repo")
- credentials = FakeCredentials(temp_dir_path)
- try:
- self.assertEqual(credentials.read_credentials(), ["test@webkit.org", "NOMNOMNOM"])
- finally:
- os.rmdir(temp_dir_path)
+ 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/rietveld.py b/WebKitTools/Scripts/webkitpy/common/net/rietveld.py
deleted file mode 100644
index b9a0821..0000000
--- a/WebKitTools/Scripts/webkitpy/common/net/rietveld.py
+++ /dev/null
@@ -1,79 +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 os
-import re
-import stat
-
-import webkitpy.common.config as config
-from webkitpy.common.system.deprecated_logging import log
-from webkitpy.common.system.executive import ScriptError
-import webkitpy.thirdparty.autoinstalled.rietveld.upload as upload
-
-
-class Rietveld(object):
- def __init__(self, executive, dryrun=False):
- self.dryrun = dryrun
- self._executive = executive
-
- def url_for_issue(self, codereview_issue):
- if not codereview_issue:
- return None
- return "%s%s" % (config.codereview_server_url, codereview_issue)
-
- def post(self, diff, patch_id, codereview_issue, message=None, cc=None):
- if not message:
- raise ScriptError("Rietveld requires a message.")
-
- # Rietveld has a 100 character limit on message length.
- if len(message) > 100:
- message = message[:100]
-
- args = [
- # First argument is empty string to mimic sys.argv.
- "",
- "--assume_yes",
- "--server=%s" % config.codereview_server_host,
- "--message=%s" % message,
- "--webkit_patch_id=%s" % patch_id,
- ]
- if codereview_issue:
- args.append("--issue=%s" % codereview_issue)
- if cc:
- args.append("--cc=%s" % cc)
-
- if self.dryrun:
- log("Would have run %s" % args)
- return
-
- # Use RealMain instead of calling upload from the commandline so that
- # we can pass in the diff ourselves. Otherwise, upload will just use
- # git diff for git checkouts, which doesn't respect --git-commit.
- issue, patchset = upload.RealMain(args, data=diff)
- return issue
diff --git a/WebKitTools/Scripts/webkitpy/common/net/statusserver.py b/WebKitTools/Scripts/webkitpy/common/net/statusserver.py
index 3d03dcd..64dd77b 100644
--- a/WebKitTools/Scripts/webkitpy/common/net/statusserver.py
+++ b/WebKitTools/Scripts/webkitpy/common/net/statusserver.py
@@ -127,7 +127,7 @@ class StatusServer:
self._browser.submit()
def release_work_item(self, queue_name, patch):
- _log.debug("Releasing work item %s from %s" % (patch.id(), queue_name))
+ _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):