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 re 30import sys 31 32 33class PlatformInfo(object): 34 """This class provides a consistent (and mockable) interpretation of 35 system-specific values (like sys.platform and platform.mac_ver()) 36 to be used by the rest of the webkitpy code base. 37 38 Public (static) properties: 39 -- os_name 40 -- os_version 41 42 Note that 'future' is returned for os_version if the operating system is 43 newer than one known to the code. 44 """ 45 46 def __init__(self, sys_module, platform_module, executive): 47 self._executive = executive 48 self._platform_module = platform_module 49 self.os_name = self._determine_os_name(sys_module.platform) 50 if self.os_name == 'linux': 51 self.os_version = self._determine_linux_version() 52 if self.os_name == 'freebsd': 53 self.os_version = platform_module.release() 54 if self.os_name.startswith('mac'): 55 self.os_version = self._determine_mac_version(platform_module.mac_ver()[0]) 56 if self.os_name.startswith('win'): 57 self.os_version = self._determine_win_version(self._win_version_tuple(sys_module)) 58 self._is_cygwin = sys_module.platform == 'cygwin' 59 60 def is_mac(self): 61 return self.os_name == 'mac' 62 63 def is_win(self): 64 return self.os_name == 'win' 65 66 def is_cygwin(self): 67 return self._is_cygwin 68 69 def is_linux(self): 70 return self.os_name == 'linux' 71 72 def is_freebsd(self): 73 return self.os_name == 'freebsd' 74 75 def is_highdpi(self): 76 if self.is_mac(): 77 output = self._executive.run_command(['system_profiler', 'SPDisplaysDataType'], error_handler=self._executive.ignore_error) 78 if output and 'Retina: Yes' in output: 79 return True 80 return False 81 82 def display_name(self): 83 # platform.platform() returns Darwin information for Mac, which is just confusing. 84 if self.is_mac(): 85 return "Mac OS X %s" % self._platform_module.mac_ver()[0] 86 87 # Returns strings like: 88 # Linux-2.6.18-194.3.1.el5-i686-with-redhat-5.5-Final 89 # Windows-2008ServerR2-6.1.7600 90 return self._platform_module.platform() 91 92 def total_bytes_memory(self): 93 if self.is_mac(): 94 return long(self._executive.run_command(["sysctl", "-n", "hw.memsize"])) 95 return None 96 97 def terminal_width(self): 98 """Returns sys.maxint if the width cannot be determined.""" 99 try: 100 if self.is_win(): 101 # From http://code.activestate.com/recipes/440694-determine-size-of-console-window-on-windows/ 102 from ctypes import windll, create_string_buffer 103 handle = windll.kernel32.GetStdHandle(-12) # -12 == stderr 104 console_screen_buffer_info = create_string_buffer(22) # 22 == sizeof(console_screen_buffer_info) 105 if windll.kernel32.GetConsoleScreenBufferInfo(handle, console_screen_buffer_info): 106 import struct 107 _, _, _, _, _, left, _, right, _, _, _ = struct.unpack("hhhhHhhhhhh", console_screen_buffer_info.raw) 108 # Note that we return 1 less than the width since writing into the rightmost column 109 # automatically performs a line feed. 110 return right - left 111 return sys.maxint 112 else: 113 import fcntl 114 import struct 115 import termios 116 packed = fcntl.ioctl(sys.stderr.fileno(), termios.TIOCGWINSZ, '\0' * 8) 117 _, columns, _, _ = struct.unpack('HHHH', packed) 118 return columns 119 except: 120 return sys.maxint 121 122 def _determine_os_name(self, sys_platform): 123 if sys_platform == 'darwin': 124 return 'mac' 125 if sys_platform.startswith('linux'): 126 return 'linux' 127 if sys_platform in ('win32', 'cygwin'): 128 return 'win' 129 if sys_platform.startswith('freebsd'): 130 return 'freebsd' 131 raise AssertionError('unrecognized platform string "%s"' % sys_platform) 132 133 def _determine_mac_version(self, mac_version_string): 134 release_version = int(mac_version_string.split('.')[1]) 135 version_strings = { 136 5: 'leopard', 137 6: 'snowleopard', 138 7: 'lion', 139 8: 'mountainlion', 140 9: 'mavericks', 141 } 142 assert release_version >= min(version_strings.keys()) 143 return version_strings.get(release_version, 'future') 144 145 def _determine_linux_version(self): 146 # FIXME: we ignore whatever the real version is and pretend it's lucid for now. 147 return 'lucid' 148 149 def _determine_win_version(self, win_version_tuple): 150 if win_version_tuple[:3] == (6, 1, 7600): 151 return '7sp0' 152 if win_version_tuple[:2] == (6, 0): 153 return 'vista' 154 if win_version_tuple[:2] == (5, 1): 155 return 'xp' 156 assert win_version_tuple[0] > 6 or win_version_tuple[1] >= 1, 'Unrecognized Windows version tuple: "%s"' % (win_version_tuple,) 157 return 'future' 158 159 def _win_version_tuple(self, sys_module): 160 if hasattr(sys_module, 'getwindowsversion'): 161 return sys_module.getwindowsversion() 162 return self._win_version_tuple_from_cmd() 163 164 def _win_version_tuple_from_cmd(self): 165 # Note that this should only ever be called on windows, so this should always work. 166 ver_output = self._executive.run_command(['cmd', '/c', 'ver'], decode_output=False) 167 match_object = re.search(r'(?P<major>\d)\.(?P<minor>\d)\.(?P<build>\d+)', ver_output) 168 assert match_object, 'cmd returned an unexpected version string: ' + ver_output 169 return tuple(map(int, match_object.groups())) 170