Tools/ChangeLog

 12011-06-27 Adam Barth <abarth@webkit.org>
 2
 3 Reviewed by NOBODY (OOPS!).
 4
 5 webkitpy should understand crash logs
 6 https://bugs.webkit.org/show_bug.cgi?id=63468
 7
 8 We're planning to use this functionality to upload crash logs along
 9 with test results for new-run-webkit-tests.
 10
 11 * Scripts/webkitpy/common/system/crashlog.py: Added.
 12 * Scripts/webkitpy/common/system/crashlog_unittest.py: Added.
 13 * Scripts/webkitpy/common/system/executive.py:
 14 * Scripts/webkitpy/common/system/executive_unittest.py:
 15 * Scripts/webkitpy/common/system/filesystem.py:
 16 * Scripts/webkitpy/common/system/filesystem_mock.py:
 17 * Scripts/webkitpy/tool/commands/queries.py:
 18
1192011-06-27 Chang Shu <cshu@webkit.org>
220
321 Reviewed by Darin Adler.
89833

Tools/Scripts/webkitpy/common/system/crashlog.py

 1# Copyright (c) 2011, Google Inc. All rights reserved.
 2#
 3# Redistribution and use in source and binary forms, with or without
 4# modification, are permitted provided that the following conditions are
 5# met:
 6#
 7# * Redistributions of source code must retain the above copyright
 8# notice, this list of conditions and the following disclaimer.
 9# * Redistributions in binary form must reproduce the above
 10# copyright notice, this list of conditions and the following disclaimer
 11# in the documentation and/or other materials provided with the
 12# distribution.
 13# * Neither the name of Google Inc. nor the names of its
 14# contributors may be used to endorse or promote products derived from
 15# this software without specific prior written permission.
 16#
 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28
 29import os
 30import re
 31import sys
 32
 33
 34def _is_crash_reporter(process_name):
 35 return re.match(r"ReportCrash", process_name)
 36
 37
 38class CrashLog(object):
 39 def __init__(self, executive, filesystem, process_name):
 40 self._executive = executive
 41 self._filesystem = filesystem
 42 self._log = None
 43 if sys.platform == "darwin":
 44 self._capture_log_darwin(process_name)
 45
 46 def log(self):
 47 return self._log
 48
 49 def _log_directory_darwin(self):
 50 log_directory = self._filesystem.expanduser("~")
 51 log_directory = os.path.join(log_directory, "Library", "Logs")
 52 if self._filesystem.exists(os.path.join(log_directory, "DiagnosticReports")):
 53 log_directory = os.path.join(log_directory, "DiagnosticReports")
 54 else:
 55 log_directory = os.path.join(log_directory, "CrashReporter")
 56 return log_directory
 57
 58 def _capture_log_darwin(self, process_name):
 59 def is_crash_log(fs, dirpath, basename):
 60 return basename.startswith(process_name + "_") and basename.endswith(".crash")
 61
 62 log_directory = self._log_directory_darwin()
 63 logs = self._filesystem.files_under(log_directory, file_filter=is_crash_log)
 64 if not logs:
 65 return
 66
 67 self._executive.wait_newest(_is_crash_reporter)
 68 self._log = self._filesystem.read_binary_file(sorted(logs)[-1])
0

Tools/Scripts/webkitpy/common/system/crashlog_unittest.py

 1# Copyright (C) 2011 Google Inc. All rights reserved.
 2#
 3# Redistribution and use in source and binary forms, with or without
 4# modification, are permitted provided that the following conditions
 5# are met:
 6#
 7# 1. Redistributions of source code must retain the above copyright
 8# notice, this list of conditions and the following disclaimer.
 9# 2. Redistributions in binary form must reproduce the above copyright
 10# notice, this list of conditions and the following disclaimer in the
 11# documentation and/or other materials provided with the distribution.
 12#
 13# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 14# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 15# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 16# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 17# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 18# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 19# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 20# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 21# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 22# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 23
 24import unittest
 25import sys
 26
 27from webkitpy.common.system.crashlog import *
 28from webkitpy.common.system.filesystem_mock import MockFileSystem
 29from webkitpy.thirdparty.mock import Mock
 30
 31
 32class CrashLogTest(unittest.TestCase):
 33 def test_find_log_darwin(self):
 34 if sys.platform != "darwin":
 35 return
 36 mock_crash_report = "Mock Crash Report"
 37 files = {}
 38 files['/Users/mock/Library/Logs/DiagnosticReports/TextMate_2011-06-13-150719_quadzen.crash'] = mock_crash_report
 39 filesystem = MockFileSystem(files)
 40 crash_log = CrashLog(Mock(), filesystem, "TextMate")
 41 self.assertTrue(crash_log.log(), mock_crash_report)
0

Tools/Scripts/webkitpy/common/system/executive.py

@@class Executive(object):
289289
290290 assert(False)
291291
 292 def running_pids(self, process_name_filter=None):
 293 if not process_name_filter:
 294 process_name_filter = lambda process_name: True
 295
 296 running_pids = []
 297
 298 if sys.platform in ("win32", "cygwin"):
 299 raise NotImplemented()
 300
 301 ps_process = self.popen(['ps', '-eo', 'pid,comm'], stdout=self.PIPE, stderr=self.PIPE)
 302 stdout, _ = ps_process.communicate()
 303 for line in stdout.splitlines():
 304 try:
 305 pid, process_name = line.split(' ', 1)
 306 if process_name_filter(process_name):
 307 running_pids.append(int(pid))
 308 except ValueError, e:
 309 pass
 310
 311 return sorted(running_pids)
 312
 313 def wait_newest(self, process_name_filter=None):
 314 if not process_name_filter:
 315 process_name_filter = lambda process_name: True
 316
 317 running_pids = self.running_pids(process_name_filter)
 318 if not running_pids:
 319 return
 320 pid = running_pids[-1]
 321
 322 while self.check_running_pid(pid):
 323 time.sleep(0.25)
 324
292325 def _windows_image_name(self, process_name):
293326 name, extension = os.path.splitext(process_name)
294327 if not extension:
89824

Tools/Scripts/webkitpy/common/system/executive_unittest.py

@@class ExecutiveTest(unittest.TestCase):
199199 self.assertTrue(executive.check_running_pid(os.getpid()))
200200 # Maximum pid number on Linux is 32768 by default
201201 self.assertFalse(executive.check_running_pid(100000))
 202
 203 def test_running_pids(self):
 204 if sys.platform in ("win32", "cygwin"):
 205 return # This function isn't implemented on Windows yet.
 206
 207 executive = Executive()
 208 pids = executive.running_pids()
 209 self.assertTrue(os.getpid() in pids)
89824

Tools/Scripts/webkitpy/common/system/filesystem.py

@@class FileSystem(object):
5757 def abspath(self, path):
5858 return os.path.abspath(path)
5959
 60 def expanduser(self, path):
 61 return os.path.expanduser(path)
 62
6063 def basename(self, path):
61  """Wraps os.path.basename()."""
6264 return os.path.basename(path)
6365
6466 def chdir(self, path):
65  """Wraps os.chdir()."""
6667 return os.chdir(path)
6768
6869 def copyfile(self, source, destination):
89824

Tools/Scripts/webkitpy/common/system/filesystem_mock.py

@@class MockFileSystem(object):
7070 def basename(self, path):
7171 return self._split(path)[1]
7272
 73 def expanduser(self, path):
 74 if path[0] != "~":
 75 return path
 76 parts = path.split(self.sep, 1)
 77 home_directory = self.sep + "Users" + self.sep + "mock"
 78 if len(parts) == 1:
 79 return home_directory
 80 return home_directory + self.sep + parts[1]
 81
7382 def chdir(self, path):
7483 path = self.normpath(path)
7584 if not self.isdir(path):
89824

Tools/Scripts/webkitpy/tool/commands/queries.py

@@from webkitpy.common.checkout.commitinfo
3636from webkitpy.common.config.committers import CommitterList
3737from webkitpy.common.net.buildbot import BuildBot
3838from webkitpy.common.net.regressionwindow import RegressionWindow
 39from webkitpy.common.system.crashlog import CrashLog
3940from webkitpy.common.system.user import User
4041from webkitpy.tool.grammar import pluralize
4142from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
4243from webkitpy.common.system.deprecated_logging import log
4344from webkitpy.layout_tests import port
4445
45 
4646class SuggestReviewers(AbstractDeclarativeCommand):
4747 name = "suggest-reviewers"
4848 help_text = "Suggest reviewers for a patch based on recent changes to the modified files."

@@and displayes the status of each builder
368368 print "%s : %s" % (status_string.ljust(4), builder["name"])
369369
370370
 371class CrashLog(AbstractDeclarativeCommand):
 372 name = "crash-log"
 373 argument_names = "PROCESS_NAME"
 374
 375 def execute(self, options, args, tool):
 376 crash_log = CrashLog(tool.executive, tool.filesystem, args[0])
 377 print crash_log.log()
 378
 379
371380class SkippedPorts(AbstractDeclarativeCommand):
372381 name = "skipped-ports"
373382 help_text = "Print the list of ports skipping the given layout test(s)"
89824