diff options
Diffstat (limited to 'Tools/Scripts/webkitpy/common/system')
12 files changed, 139 insertions, 72 deletions
diff --git a/Tools/Scripts/webkitpy/common/system/crashlogs.py b/Tools/Scripts/webkitpy/common/system/crashlogs.py index a6b6575f6..0dd37d255 100644 --- a/Tools/Scripts/webkitpy/common/system/crashlogs.py +++ b/Tools/Scripts/webkitpy/common/system/crashlogs.py @@ -26,51 +26,46 @@ # (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 re -import sys class CrashLogs(object): - def __init__(self, filesystem): - self._filesystem = filesystem + def __init__(self, host): + self._host = host - def find_newest_log(self, process_name, pid=None): - if sys.platform == "darwin": - return self._find_newest_log_darwin(process_name, pid) + def find_newest_log(self, process_name, pid=None, include_errors=False, newer_than=None): + if self._host.platform.is_mac(): + return self._find_newest_log_darwin(process_name, pid, include_errors, newer_than) + return None def _log_directory_darwin(self): - log_directory = self._filesystem.expanduser("~") - log_directory = self._filesystem.join(log_directory, "Library", "Logs") - if self._filesystem.exists(self._filesystem.join(log_directory, "DiagnosticReports")): - log_directory = self._filesystem.join(log_directory, "DiagnosticReports") + log_directory = self._host.filesystem.expanduser("~") + log_directory = self._host.filesystem.join(log_directory, "Library", "Logs") + if self._host.filesystem.exists(self._host.filesystem.join(log_directory, "DiagnosticReports")): + log_directory = self._host.filesystem.join(log_directory, "DiagnosticReports") else: - log_directory = self._filesystem.join(log_directory, "CrashReporter") + log_directory = self._host.filesystem.join(log_directory, "CrashReporter") return log_directory - def _find_newest_log_darwin(self, process_name, pid): + def _find_newest_log_darwin(self, process_name, pid, include_errors, newer_than): def is_crash_log(fs, dirpath, basename): return basename.startswith(process_name + "_") and basename.endswith(".crash") log_directory = self._log_directory_darwin() - logs = self._filesystem.files_under(log_directory, file_filter=is_crash_log) - if not logs: - return None + logs = self._host.filesystem.files_under(log_directory, file_filter=is_crash_log) first_line_regex = re.compile(r'^Process:\s+(?P<process_name>.*) \[(?P<pid>\d+)\]$') + errors = '' for path in reversed(sorted(logs)): - try: - with self._filesystem.open_text_file_for_reading(path) as f: - first_line = f.readline() + if not newer_than or self._host.filesystem.mtime(path) > newer_than: + try: + f = self._host.filesystem.read_text_file(path) + match = first_line_regex.match(f[0:f.find('\n')]) + if match and match.group('process_name') == process_name and (pid is None or int(match.group('pid')) == pid): + return errors + f + except IOError, e: + if include_errors: + errors += "ERROR: Failed to read '%s': %s\n" % (path, str(e)) - match = first_line_regex.match(first_line) - if not match: - continue - if match.group('process_name') != process_name: - continue - if pid is not None and int(match.group('pid')) != pid: - continue - - f.seek(0, os.SEEK_SET) - return f.read() - except IOError: - continue + if include_errors and errors: + return errors + return None diff --git a/Tools/Scripts/webkitpy/common/system/crashlogs_unittest.py b/Tools/Scripts/webkitpy/common/system/crashlogs_unittest.py index ab1a6c2ad..d93feec0e 100644 --- a/Tools/Scripts/webkitpy/common/system/crashlogs_unittest.py +++ b/Tools/Scripts/webkitpy/common/system/crashlogs_unittest.py @@ -22,10 +22,11 @@ # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import unittest -import sys -from webkitpy.common.system.crashlogs import * +from webkitpy.common.system.crashlogs import CrashLogs from webkitpy.common.system.filesystem_mock import MockFileSystem +from webkitpy.common.system.systemhost import SystemHost +from webkitpy.common.system.systemhost_mock import MockSystemHost from webkitpy.thirdparty.mock import Mock @@ -75,7 +76,7 @@ class CrashLogsTest(unittest.TestCase): self.assertEqual(a.splitlines(), b.splitlines()) def test_find_log_darwin(self): - if sys.platform != "darwin": + if not SystemHost().platform.is_mac(): return older_mock_crash_report = make_mock_crash_report_darwin('DumpRenderTree', 28528) @@ -91,7 +92,7 @@ class CrashLogsTest(unittest.TestCase): files['/Users/mock/Library/Logs/DiagnosticReports/DumpRenderTree_2011-06-13-150722_quadzen.crash'] = other_process_mock_crash_report files['/Users/mock/Library/Logs/DiagnosticReports/DumpRenderTree_2011-06-13-150723_quadzen.crash'] = misformatted_mock_crash_report filesystem = MockFileSystem(files) - crash_logs = CrashLogs(filesystem) + crash_logs = CrashLogs(MockSystemHost(filesystem=filesystem)) log = crash_logs.find_newest_log("DumpRenderTree") self.assertLinesEqual(log, newer_mock_crash_report) log = crash_logs.find_newest_log("DumpRenderTree", 28529) @@ -100,3 +101,12 @@ class CrashLogsTest(unittest.TestCase): self.assertLinesEqual(log, mock_crash_report) log = crash_logs.find_newest_log("DumpRenderTree", 28531) self.assertEqual(log, None) + log = crash_logs.find_newest_log("DumpRenderTree", newer_than=1.0) + self.assertEqual(log, None) + + def bad_read(path): + raise IOError('No such file or directory') + + filesystem.read_text_file = bad_read + log = crash_logs.find_newest_log("DumpRenderTree", 28531, include_errors=True) + self.assertTrue('No such file or directory' in log) diff --git a/Tools/Scripts/webkitpy/common/system/executive.py b/Tools/Scripts/webkitpy/common/system/executive.py index 06f870c72..43dcbca1b 100644 --- a/Tools/Scripts/webkitpy/common/system/executive.py +++ b/Tools/Scripts/webkitpy/common/system/executive.py @@ -32,7 +32,6 @@ import ctypes import errno import logging import os -import platform import StringIO import signal import subprocess @@ -255,16 +254,14 @@ class Executive(object): def check_running_pid(self, pid): """Return True if pid is alive, otherwise return False.""" - if sys.platform.startswith('linux') or sys.platform in ('darwin', 'cygwin'): - try: - os.kill(pid, 0) - return True - except OSError: - return False - elif sys.platform == 'win32': + if sys.platform == 'win32': return self._win32_check_running_pid(pid) - assert(False) + try: + os.kill(pid, 0) + return True + except OSError: + return False def running_pids(self, process_name_filter=None): if not process_name_filter: diff --git a/Tools/Scripts/webkitpy/common/system/executive_mock.py b/Tools/Scripts/webkitpy/common/system/executive_mock.py index a76268129..d57a5c480 100644 --- a/Tools/Scripts/webkitpy/common/system/executive_mock.py +++ b/Tools/Scripts/webkitpy/common/system/executive_mock.py @@ -27,15 +27,20 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import os +import StringIO from webkitpy.common.system.deprecated_logging import log from webkitpy.common.system.executive import ScriptError class MockProcess(object): - def __init__(self): + def __init__(self, stdout='MOCK STDOUT\n'): self.pid = 42 + self.stdout = StringIO.StringIO(stdout) + self.stdin = StringIO.StringIO() + def wait(self): + return # FIXME: This should be unified with MockExecutive2 class MockExecutive(object): @@ -52,6 +57,7 @@ class MockExecutive(object): self._should_throw_when_run = should_throw_when_run or set() # FIXME: Once executive wraps os.getpid() we can just use a static pid for "this" process. self._running_pids = [os.getpid()] + self._proc = None def check_running_pid(self, pid): return pid in self._running_pids @@ -89,9 +95,18 @@ class MockExecutive(object): def cpu_count(self): return 2 - def popen(self, *args, **kwargs): - # FIXME: Implement logging when self._should_log is set. - return MockProcess() + def popen(self, args, cwd=None, env=None, **kwargs): + if self._should_log: + cwd_string = "" + if cwd: + cwd_string = ", cwd=%s" % cwd + env_string = "" + if env: + env_string = ", env=%s" % env + log("MOCK popen: %s%s%s" % (args, cwd_string, env_string)) + if not self._proc: + self._proc = MockProcess() + return self._proc class MockExecutive2(object): diff --git a/Tools/Scripts/webkitpy/common/system/file_lock.py b/Tools/Scripts/webkitpy/common/system/file_lock.py index b4bfffc40..c542777f2 100644 --- a/Tools/Scripts/webkitpy/common/system/file_lock.py +++ b/Tools/Scripts/webkitpy/common/system/file_lock.py @@ -43,20 +43,20 @@ class FileLock(object): self._max_wait_time_sec = max_wait_time_sec def _create_lock(self): - if sys.platform.startswith('linux') or sys.platform in ('darwin', 'cygwin'): - import fcntl - fcntl.flock(self._lock_file_descriptor, fcntl.LOCK_EX | fcntl.LOCK_NB) - elif sys.platform == 'win32': + if sys.platform == 'win32': import msvcrt msvcrt.locking(self._lock_file_descriptor, msvcrt.LK_NBLCK, 32) + else: + import fcntl + fcntl.flock(self._lock_file_descriptor, fcntl.LOCK_EX | fcntl.LOCK_NB) def _remove_lock(self): - if sys.platform.startswith('linux') or sys.platform in ('darwin', 'cygwin'): - import fcntl - fcntl.flock(self._lock_file_descriptor, fcntl.LOCK_UN) - elif sys.platform == 'win32': + if sys.platform == 'win32': import msvcrt msvcrt.locking(self._lock_file_descriptor, msvcrt.LK_UNLCK, 32) + else: + import fcntl + fcntl.flock(self._lock_file_descriptor, fcntl.LOCK_UN) def acquire_lock(self): self._lock_file_descriptor = os.open(self._lock_file_path, os.O_TRUNC | os.O_CREAT) diff --git a/Tools/Scripts/webkitpy/common/system/filesystem.py b/Tools/Scripts/webkitpy/common/system/filesystem.py index 60b680c06..687a31322 100644 --- a/Tools/Scripts/webkitpy/common/system/filesystem.py +++ b/Tools/Scripts/webkitpy/common/system/filesystem.py @@ -55,6 +55,9 @@ class FileSystem(object): def abspath(self, path): return os.path.abspath(path) + def realpath(self, path): + return os.path.realpath(path) + def path_to_module(self, module_name): """A wrapper for all calls to __file__ to allow easy unit testing.""" # FIXME: This is the only use of sys in this file. It's possible this function should move elsewhere. @@ -201,6 +204,8 @@ class FileSystem(object): f.write(contents) def open_text_file_for_reading(self, path): + # Note: There appears to be an issue with the returned file objects + # not being seekable. See http://stackoverflow.com/questions/1510188/can-seek-and-tell-work-with-utf-8-encoded-documents-in-python . return codecs.open(path, 'r', 'utf8') def open_text_file_for_writing(self, path): diff --git a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py index 2ff688af7..d4a955080 100644 --- a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py +++ b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py @@ -82,6 +82,9 @@ class MockFileSystem(object): return self.normpath(path) return self.abspath(self.join(self.cwd, path)) + def realpath(self, path): + return self.abspath(path) + def basename(self, path): return self._split(path)[1] @@ -129,7 +132,7 @@ class MockFileSystem(object): file_filter = file_filter or filter_all files = [] if self.isfile(path): - if file_filter(self, self.dirname(path), self.basename(path)): + if file_filter(self, self.dirname(path), self.basename(path)) and self.files[path] is not None: files.append(path) return files @@ -149,7 +152,7 @@ class MockFileSystem(object): continue dirpath, basename = self._split(filename) - if file_filter(self, dirpath, basename): + if file_filter(self, dirpath, basename) and self.files[filename] is not None: files.append(filename) return files @@ -275,7 +278,7 @@ class MockFileSystem(object): def normpath(self, path): # This function is called a lot, so we try to optimize the common cases # instead of always calling _slow_but_correct_normpath(), above. - if '..' in path: + if '..' in path or '/./' in path: # This doesn't happen very often; don't bother trying to optimize it. return self._slow_but_correct_normpath(path) if not path: diff --git a/Tools/Scripts/webkitpy/common/system/platforminfo.py b/Tools/Scripts/webkitpy/common/system/platforminfo.py index dd6d6844c..22cafbbee 100644 --- a/Tools/Scripts/webkitpy/common/system/platforminfo.py +++ b/Tools/Scripts/webkitpy/common/system/platforminfo.py @@ -48,6 +48,8 @@ class PlatformInfo(object): self.os_name = self._determine_os_name(sys_module.platform) if self.os_name == 'linux': self.os_version = self._determine_linux_version() + if self.os_name == 'freebsd': + self.os_version = platform_module.release() if self.os_name.startswith('mac'): self.os_version = self._determine_mac_version(platform_module.mac_ver()[0]) if self.os_name.startswith('win'): @@ -62,6 +64,9 @@ class PlatformInfo(object): def is_linux(self): return self.os_name == 'linux' + def is_freebsd(self): + return self.os_name == 'freebsd' + def display_name(self): # platform.platform() returns Darwin information for Mac, which is just confusing. if self.is_mac(): @@ -93,6 +98,8 @@ class PlatformInfo(object): return 'linux' if sys_platform in ('win32', 'cygwin'): return 'win' + if sys_platform.startswith('freebsd'): + return 'freebsd' raise AssertionError('unrecognized platform string "%s"' % sys_platform) def _determine_mac_version(self, mac_version_string): diff --git a/Tools/Scripts/webkitpy/common/system/platforminfo_mock.py b/Tools/Scripts/webkitpy/common/system/platforminfo_mock.py index 7302761de..c953aa185 100644 --- a/Tools/Scripts/webkitpy/common/system/platforminfo_mock.py +++ b/Tools/Scripts/webkitpy/common/system/platforminfo_mock.py @@ -28,8 +28,9 @@ class MockPlatformInfo(object): - os_name = 'mac' - os_version = 'snowleopard' + def __init__(self, os_name='mac', os_version='snowleopard'): + self.os_name = os_name + self.os_version = os_version def is_mac(self): return self.os_name == 'mac' @@ -40,6 +41,9 @@ class MockPlatformInfo(object): def is_win(self): return self.os_name == 'win' + def is_freebsd(self): + return self.os_name == 'freebsd' + def display_name(self): return "MockPlatform 1.0" diff --git a/Tools/Scripts/webkitpy/common/system/platforminfo_unittest.py b/Tools/Scripts/webkitpy/common/system/platforminfo_unittest.py index ac9cfb0d7..5a1f85fc3 100644 --- a/Tools/Scripts/webkitpy/common/system/platforminfo_unittest.py +++ b/Tools/Scripts/webkitpy/common/system/platforminfo_unittest.py @@ -45,7 +45,7 @@ def fake_sys(platform_str='darwin', windows_version_tuple=None): return FakeSysModule() -def fake_platform(mac_version_string='10.6.3'): +def fake_platform(mac_version_string='10.6.3', release_string='bar'): class FakePlatformModule(object): def mac_ver(self): @@ -54,6 +54,9 @@ def fake_platform(mac_version_string='10.6.3'): def platform(self): return 'foo' + def release(self): + return release_string + return FakePlatformModule() @@ -75,7 +78,7 @@ class TestPlatformInfo(unittest.TestCase): self.assertNotEquals(info.os_name, '') self.assertNotEquals(info.os_version, '') self.assertNotEquals(info.display_name(), '') - self.assertTrue(info.is_mac() or info.is_win() or info.is_linux()) + self.assertTrue(info.is_mac() or info.is_win() or info.is_linux() or info.is_freebsd()) if info.is_mac(): self.assertTrue(info.total_bytes_memory() > 0) @@ -89,29 +92,41 @@ class TestPlatformInfo(unittest.TestCase): self.assertTrue(info.is_linux()) self.assertFalse(info.is_mac()) self.assertFalse(info.is_win()) + self.assertFalse(info.is_freebsd()) info = self.make_info(fake_sys('linux3')) self.assertTrue(info.is_linux()) self.assertFalse(info.is_mac()) self.assertFalse(info.is_win()) + self.assertFalse(info.is_freebsd()) info = self.make_info(fake_sys('darwin'), fake_platform('10.6.3')) self.assertEquals(info.os_name, 'mac') self.assertFalse(info.is_linux()) self.assertTrue(info.is_mac()) self.assertFalse(info.is_win()) + self.assertFalse(info.is_freebsd()) info = self.make_info(fake_sys('win32', tuple([6, 1, 7600]))) self.assertEquals(info.os_name, 'win') self.assertFalse(info.is_linux()) self.assertFalse(info.is_mac()) self.assertTrue(info.is_win()) + self.assertFalse(info.is_freebsd()) info = self.make_info(fake_sys('cygwin'), executive=fake_executive('6.1.7600')) self.assertEquals(info.os_name, 'win') self.assertFalse(info.is_linux()) self.assertFalse(info.is_mac()) self.assertTrue(info.is_win()) + self.assertFalse(info.is_freebsd()) + + info = self.make_info(fake_sys('freebsd8')) + self.assertEquals(info.os_name, 'freebsd') + self.assertFalse(info.is_linux()) + self.assertFalse(info.is_mac()) + self.assertFalse(info.is_win()) + self.assertTrue(info.is_freebsd()) self.assertRaises(AssertionError, self.make_info, fake_sys('vms')) @@ -124,6 +139,9 @@ class TestPlatformInfo(unittest.TestCase): self.assertEquals(self.make_info(fake_sys('linux2')).os_version, 'lucid') + self.assertEquals(self.make_info(fake_sys('freebsd8'), fake_platform('', '8.3-PRERELEASE')).os_version, '8.3-PRERELEASE') + self.assertEquals(self.make_info(fake_sys('freebsd9'), fake_platform('', '9.0-RELEASE')).os_version, '9.0-RELEASE') + self.assertRaises(AssertionError, self.make_info, fake_sys('win32', tuple([5, 0, 1234]))) self.assertEquals(self.make_info(fake_sys('win32', tuple([6, 2, 1234]))).os_version, 'future') self.assertEquals(self.make_info(fake_sys('win32', tuple([6, 1, 7600]))).os_version, '7sp0') @@ -146,6 +164,9 @@ class TestPlatformInfo(unittest.TestCase): info = self.make_info(fake_sys('linux2')) self.assertNotEquals(info.display_name(), '') + info = self.make_info(fake_sys('freebsd9')) + self.assertNotEquals(info.display_name(), '') + def test_total_bytes_memory(self): info = self.make_info(fake_sys('darwin'), fake_platform('10.6.3'), fake_executive('1234')) self.assertEquals(info.total_bytes_memory(), 1234) @@ -156,6 +177,9 @@ class TestPlatformInfo(unittest.TestCase): info = self.make_info(fake_sys('linux2')) self.assertEquals(info.total_bytes_memory(), None) + info = self.make_info(fake_sys('freebsd9')) + self.assertEquals(info.total_bytes_memory(), None) + def test_free_bytes_memory(self): vmstat_output = ("Mach Virtual Memory Statistics: (page size of 4096 bytes)\n" "Pages free: 1.\n" @@ -169,6 +193,9 @@ class TestPlatformInfo(unittest.TestCase): info = self.make_info(fake_sys('linux2')) self.assertEquals(info.free_bytes_memory(), None) + info = self.make_info(fake_sys('freebsd9')) + self.assertEquals(info.free_bytes_memory(), None) + if __name__ == '__main__': unittest.main() diff --git a/Tools/Scripts/webkitpy/common/system/systemhost_mock.py b/Tools/Scripts/webkitpy/common/system/systemhost_mock.py index f3bc94139..4667b08b9 100644 --- a/Tools/Scripts/webkitpy/common/system/systemhost_mock.py +++ b/Tools/Scripts/webkitpy/common/system/systemhost_mock.py @@ -35,9 +35,9 @@ from webkitpy.common.system.workspace_mock import MockWorkspace class MockSystemHost(object): - def __init__(self, log_executive=False, executive_throws_when_run=None, os_name=None, os_version=None): - self.executive = MockExecutive(should_log=log_executive, should_throw_when_run=executive_throws_when_run) - self.filesystem = MockFileSystem() + def __init__(self, log_executive=False, executive_throws_when_run=None, os_name=None, os_version=None, executive=None, filesystem=None): + self.executive = executive or MockExecutive(should_log=log_executive, should_throw_when_run=executive_throws_when_run) + self.filesystem = filesystem or MockFileSystem() self.user = MockUser() self.platform = MockPlatformInfo() if os_name: diff --git a/Tools/Scripts/webkitpy/common/system/user.py b/Tools/Scripts/webkitpy/common/system/user.py index 31b218c2f..e20405912 100644 --- a/Tools/Scripts/webkitpy/common/system/user.py +++ b/Tools/Scripts/webkitpy/common/system/user.py @@ -29,12 +29,16 @@ import getpass import logging import os +import platform import re import shlex import subprocess import sys import webbrowser +from webkitpy.common.system.executive import Executive +from webkitpy.common.system.platforminfo import PlatformInfo + _log = logging.getLogger(__name__) @@ -45,17 +49,17 @@ 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 == "darwin": - _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' + def __init__(self, platforminfo=None): + # We cannot get the PlatformInfo object from a SystemHost because + # User is part of SystemHost itself. + self._platforminfo = platforminfo or PlatformInfo(sys, platform, Executive()) + # 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): @@ -107,7 +111,7 @@ class User(object): def edit_changelog(self, files): edit_application = os.environ.get("CHANGE_LOG_EDIT_APPLICATION") - if edit_application and sys.platform == "darwin": + if edit_application and self._platforminfo.is_mac(): # 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." |