Python 3: Add support in webkitpy.common.net.buildbot 
https://bugs.webkit.org/show_bug.cgi?id=202466

Reviewed by Stephanie Lewis.

* Scripts/test-webkitpy-python3: Add webkitpy.common.net.buildbot to the test list.
* Scripts/webkitpy/common/net/buildbot/buildbot.py:
(Builder.url_encoded_name): Call compatible urllib quote.
(Builder.revision_build_pairs_with_results): Convert iterator to list before returning.
(Build.results_url): Call compatible urllib quote.
(BuildBot._parse_last_build_cell):renderContents needs to be decoded in Python 3.
(BuildBot._parse_current_build_cell): BeautifulSoup and bs4 render breaks differently.
(BuildBot._fetch_build_dictionary): Call compatible urllib quote.
* Scripts/webkitpy/common/net/regressionwindow.py:
(RegressionWindow.revisions): Convert range(...) to list.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251259 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index 13c2afc..64aaa6d 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,21 @@
+2019-10-17  Jonathan Bedard  <jbedard@apple.com>
+
+        Python 3: Add support in webkitpy.common.net.buildbot 
+        https://bugs.webkit.org/show_bug.cgi?id=202466
+
+        Reviewed by Stephanie Lewis.
+
+        * Scripts/test-webkitpy-python3: Add webkitpy.common.net.buildbot to the test list.
+        * Scripts/webkitpy/common/net/buildbot/buildbot.py:
+        (Builder.url_encoded_name): Call compatible urllib quote.
+        (Builder.revision_build_pairs_with_results): Convert iterator to list before returning.
+        (Build.results_url): Call compatible urllib quote.
+        (BuildBot._parse_last_build_cell):renderContents needs to be decoded in Python 3.
+        (BuildBot._parse_current_build_cell): BeautifulSoup and bs4 render breaks differently.
+        (BuildBot._fetch_build_dictionary): Call compatible urllib quote.
+        * Scripts/webkitpy/common/net/regressionwindow.py:
+        (RegressionWindow.revisions): Convert range(...) to list.
+
 2019-10-17  Aakash Jain  <aakash_jain@apple.com>
 
         [ews] status bubbles should show details from all the builds in case build is retried
diff --git a/Tools/Scripts/test-webkitpy-python3 b/Tools/Scripts/test-webkitpy-python3
index 600e820..2189e68 100755
--- a/Tools/Scripts/test-webkitpy-python3
+++ b/Tools/Scripts/test-webkitpy-python3
@@ -35,6 +35,7 @@
   'webkitpy.common.system',
   'webkitpy.common.thread',
   'webkitpy.common.net.bugzilla',
+  'webkitpy.common.net.buildbot',
   'webkitpy.common.net.irc',
 ]
 
diff --git a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py
index 3cf3da1..2b42f84d 100644
--- a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py
+++ b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py
@@ -1,4 +1,5 @@
 # Copyright (c) 2009, Google Inc. All rights reserved.
+# Copyright (C) 2019 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
@@ -39,6 +40,7 @@
 from webkitpy.common.net.networktransaction import NetworkTransaction
 from webkitpy.common.net.regressionwindow import RegressionWindow
 from webkitpy.common.system.logutils import get_logger
+from webkitpy.common.unicode_compatibility import decode_for, unicode
 from webkitpy.thirdparty.autoinstalled.mechanize import Browser
 from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup
 
@@ -95,7 +97,7 @@
         return LayoutTestResults.results_from_string(results_file)
 
     def url_encoded_name(self):
-        return urllib.quote(self._name)
+        return quote(self._name)
 
     def url(self):
         return "%s/builders/%s" % (self._buildbot.buildbot_url, self.url_encoded_name())
@@ -191,7 +193,7 @@
         return self._revision_to_build_number
 
     def revision_build_pairs_with_results(self):
-        return self._revision_to_build_map().items()
+        return list(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):
@@ -274,7 +276,7 @@
 
     def results_url(self):
         results_directory = "r%s (%s)" % (self.revision(), self._number)
-        return "%s/%s" % (self._builder.results_url(), urllib.quote(results_directory))
+        return "%s/%s" % (self._builder.results_url(), quote(results_directory))
 
     def results_zip_url(self):
         return "%s.zip" % self.results_url()
@@ -312,15 +314,13 @@
             # 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
+            builder['built_revision'] = int(revision_string) if not re.match(r'\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())
+            builder['is_green'] = not re.search('fail', decode_for(cell.renderContents(), str)) or \
+                                 bool(re.search('lost', decode_for(cell.renderContents(), str)))
 
             status_link_regexp = r"builders/(?P<builder_name>.*)/builds/(?P<build_number>\d+)"
             link_match = re.match(status_link_regexp, status_link['href'])
@@ -335,7 +335,15 @@
             builder['build_number'] = None
 
     def _parse_current_build_cell(self, builder, cell):
-        activity_lines = cell.renderContents().split("<br />")
+        # Convert rendered contents to native string
+        rendered = decode_for(cell.renderContents(), str)
+
+        # BeautifulSoup and bs4 render differently
+        if '<br/>' in rendered:
+            activity_lines = rendered.split('<br/>')
+        else:
+            activity_lines = rendered.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])
@@ -369,7 +377,7 @@
         # cause keys to be missing which you might otherwise expect.
         # FIXME: The bot sends a *huge* amount of data for each request, we should
         # find a way to reduce the response size further.
-        json_url = "%s/json/builders/%s/builds/%s?filter=1" % (self.buildbot_url, urllib.quote(builder.name()), build_number)
+        json_url = "%s/json/builders/%s/builds/%s?filter=1" % (self.buildbot_url, quote(builder.name()), build_number)
         try:
             return json.load(urlopen(json_url))
         except URLError as err:
diff --git a/Tools/Scripts/webkitpy/common/net/regressionwindow.py b/Tools/Scripts/webkitpy/common/net/regressionwindow.py
index 3960ba2..5ca6bfe 100644
--- a/Tools/Scripts/webkitpy/common/net/regressionwindow.py
+++ b/Tools/Scripts/webkitpy/common/net/regressionwindow.py
@@ -1,4 +1,5 @@
 # Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2019 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
@@ -47,6 +48,6 @@
     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 = list(range(self._failing_build.revision(), self._build_before_failure.revision(), -1))
             self._revisions.reverse()
         return self._revisions