Index: third_party/WebKit/LayoutTests/external/wpt/check_stability.py |
diff --git a/third_party/WebKit/LayoutTests/external/wpt/check_stability.py b/third_party/WebKit/LayoutTests/external/wpt/check_stability.py |
index a9c7a8fdda84ac095e72ba71182ad1af6071ac82..4e6d3232358c6bbc2a721aa055481b73c8d51d6e 100644 |
--- a/third_party/WebKit/LayoutTests/external/wpt/check_stability.py |
+++ b/third_party/WebKit/LayoutTests/external/wpt/check_stability.py |
@@ -10,11 +10,10 @@ import sys |
import tarfile |
import zipfile |
from abc import ABCMeta, abstractmethod |
-from cStringIO import StringIO |
+from cStringIO import StringIO as CStringIO |
from collections import defaultdict |
from ConfigParser import RawConfigParser |
-from io import BytesIO |
-from tools.manifest import manifest |
+from io import BytesIO, StringIO |
import requests |
@@ -24,14 +23,14 @@ LogHandler = None |
LogLevelFilter = None |
StreamHandler = None |
TbplFormatter = None |
+manifest = None |
reader = None |
wptcommandline = None |
wptrunner = None |
wpt_root = None |
wptrunner_root = None |
-logger = logging.getLogger(os.path.splitext(__file__)[0]) |
- |
+logger = None |
def do_delayed_imports(): |
"""Import and set up modules only needed if execution gets to this point.""" |
@@ -39,12 +38,14 @@ def do_delayed_imports(): |
global LogLevelFilter |
global StreamHandler |
global TbplFormatter |
+ global manifest |
global reader |
global wptcommandline |
global wptrunner |
from mozlog import reader |
from mozlog.formatters import TbplFormatter |
from mozlog.handlers import BaseHandler, LogLevelFilter, StreamHandler |
+ from tools.manifest import manifest |
from wptrunner import wptcommandline, wptrunner |
setup_log_handler() |
setup_action_filter() |
@@ -58,8 +59,6 @@ def setup_logging(): |
logger.addHandler(handler) |
logger.setLevel(logging.DEBUG) |
-setup_logging() |
- |
def setup_action_filter(): |
"""Create global LogActionFilter class as part of deferred module load.""" |
@@ -107,6 +106,50 @@ class TravisFold(object): |
print("travis_fold:end:%s" % self.name, file=sys.stderr) |
+class FilteredIO(object): |
+ """Wrap a file object, invoking the provided callback for every call to |
+ `write` and only proceeding with the operation when that callback returns |
+ True.""" |
+ def __init__(self, original, on_write): |
+ self.original = original |
+ self.on_write = on_write |
+ |
+ def __getattr__(self, name): |
+ return getattr(self.original, name) |
+ |
+ def disable(self): |
+ self.write = lambda msg: None |
+ |
+ def write(self, msg): |
+ encoded = msg.encode("utf8", "backslashreplace").decode("utf8") |
+ if self.on_write(self.original, encoded) is True: |
+ self.original.write(encoded) |
+ |
+ |
+def replace_streams(capacity, warning_msg): |
+ # Value must be boxed to support modification from inner function scope |
+ count = [0] |
+ capacity -= 2 + len(warning_msg) |
+ stderr = sys.stderr |
+ |
+ def on_write(handle, msg): |
+ length = len(msg) |
+ count[0] += length |
+ |
+ if count[0] > capacity: |
+ sys.stdout.disable() |
+ sys.stderr.disable() |
+ handle.write(msg[0:capacity - count[0]]) |
+ handle.flush() |
+ stderr.write("\n%s\n" % warning_msg) |
+ return False |
+ |
+ return True |
+ |
+ sys.stdout = FilteredIO(sys.stdout, on_write) |
+ sys.stderr = FilteredIO(sys.stderr, on_write) |
+ |
+ |
class Browser(object): |
__metaclass__ = ABCMeta |
@@ -275,7 +318,7 @@ def seekable(fileobj): |
try: |
fileobj.seek(fileobj.tell()) |
except Exception: |
- return StringIO(fileobj.read()) |
+ return CStringIO(fileobj.read()) |
else: |
return fileobj |
@@ -522,7 +565,6 @@ def table(headings, data, log): |
log("|%s|" % "|".join(" %s" % row[i].ljust(max_widths[i] - 1) for i in cols)) |
log("") |
- |
def write_inconsistent(inconsistent, iterations): |
"""Output inconsistent tests to logger.error.""" |
logger.error("## Unstable results ##\n") |
@@ -582,6 +624,10 @@ def get_parser(): |
# This is a workaround to get what should be the same value |
default=os.environ.get("TRAVIS_REPO_SLUG").split('/')[0], |
help="Travis user name") |
+ parser.add_argument("--output-bytes", |
+ action="store", |
+ type=int, |
+ help="Maximum number of bytes to write to standard output/error") |
parser.add_argument("product", |
action="store", |
help="Product to run against (`browser-name` or 'browser-name:channel')") |
@@ -592,11 +638,19 @@ def main(): |
"""Perform check_stability functionality and return exit code.""" |
global wpt_root |
global wptrunner_root |
+ global logger |
retcode = 0 |
parser = get_parser() |
args = parser.parse_args() |
+ if args.output_bytes is not None: |
+ replace_streams(args.output_bytes, |
+ "Log reached capacity (%s bytes); output disabled." % args.output_bytes) |
+ |
+ logger = logging.getLogger(os.path.splitext(__file__)[0]) |
+ setup_logging() |
+ |
wpt_root = os.path.abspath(os.curdir) |
wptrunner_root = os.path.normpath(os.path.join(wpt_root, "..", "wptrunner")) |