runtime.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. # -*- test-case-name: twisted.python.test.test_runtime -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. from __future__ import division, absolute_import
  5. import os
  6. import sys
  7. import time
  8. import warnings
  9. from twisted.python._oldstyle import _oldStyle
  10. def shortPythonVersion():
  11. """
  12. Returns the Python version as a dot-separated string.
  13. """
  14. return "%s.%s.%s" % sys.version_info[:3]
  15. knownPlatforms = {
  16. 'nt': 'win32',
  17. 'ce': 'win32',
  18. 'posix': 'posix',
  19. 'java': 'java',
  20. 'org.python.modules.os': 'java',
  21. }
  22. _timeFunctions = {
  23. #'win32': time.clock,
  24. 'win32': time.time,
  25. }
  26. @_oldStyle
  27. class Platform:
  28. """
  29. Gives us information about the platform we're running on.
  30. """
  31. type = knownPlatforms.get(os.name)
  32. seconds = staticmethod(_timeFunctions.get(type, time.time))
  33. _platform = sys.platform
  34. def __init__(self, name=None, platform=None):
  35. if name is not None:
  36. self.type = knownPlatforms.get(name)
  37. self.seconds = _timeFunctions.get(self.type, time.time)
  38. if platform is not None:
  39. self._platform = platform
  40. def isKnown(self):
  41. """
  42. Do we know about this platform?
  43. @return: Boolean indicating whether this is a known platform or not.
  44. @rtype: C{bool}
  45. """
  46. return self.type != None
  47. def getType(self):
  48. """
  49. Get platform type.
  50. @return: Either 'posix', 'win32' or 'java'
  51. @rtype: C{str}
  52. """
  53. return self.type
  54. def isMacOSX(self):
  55. """
  56. Check if current platform is Mac OS X.
  57. @return: C{True} if the current platform has been detected as OS X.
  58. @rtype: C{bool}
  59. """
  60. return self._platform == "darwin"
  61. def isWinNT(self):
  62. """
  63. Are we running in Windows NT?
  64. This is deprecated and always returns C{True} on win32 because
  65. Twisted only supports Windows NT-derived platforms at this point.
  66. @return: C{True} if the current platform has been detected as
  67. Windows NT.
  68. @rtype: C{bool}
  69. """
  70. warnings.warn(
  71. "twisted.python.runtime.Platform.isWinNT was deprecated in "
  72. "Twisted 13.0. Use Platform.isWindows instead.",
  73. DeprecationWarning, stacklevel=2)
  74. return self.isWindows()
  75. def isWindows(self):
  76. """
  77. Are we running in Windows?
  78. @return: C{True} if the current platform has been detected as
  79. Windows.
  80. @rtype: C{bool}
  81. """
  82. return self.getType() == 'win32'
  83. def isVista(self):
  84. """
  85. Check if current platform is Windows Vista or Windows Server 2008.
  86. @return: C{True} if the current platform has been detected as Vista
  87. @rtype: C{bool}
  88. """
  89. if getattr(sys, "getwindowsversion", None) is not None:
  90. return sys.getwindowsversion()[0] == 6
  91. else:
  92. return False
  93. def isLinux(self):
  94. """
  95. Check if current platform is Linux.
  96. @return: C{True} if the current platform has been detected as Linux.
  97. @rtype: C{bool}
  98. """
  99. return self._platform.startswith("linux")
  100. def isDocker(self, _initCGroupLocation="/proc/1/cgroup"):
  101. """
  102. Check if the current platform is Linux in a Docker container.
  103. @return: C{True} if the current platform has been detected as Linux
  104. inside a Docker container.
  105. @rtype: C{bool}
  106. """
  107. if not self.isLinux():
  108. return False
  109. from twisted.python.filepath import FilePath
  110. # Ask for the cgroups of init (pid 1)
  111. initCGroups = FilePath(_initCGroupLocation)
  112. if initCGroups.exists():
  113. # The cgroups file looks like "2:cpu:/". The third element will
  114. # begin with /docker if it is inside a Docker container.
  115. controlGroups = [x.split(b":")
  116. for x in initCGroups.getContent().split(b"\n")]
  117. for group in controlGroups:
  118. if len(group) == 3 and group[2].startswith(b"/docker/"):
  119. # If it starts with /docker/, we're in a docker container
  120. return True
  121. return False
  122. def _supportsSymlinks(self):
  123. """
  124. Check for symlink support usable for Twisted's purposes.
  125. @return: C{True} if symlinks are supported on the current platform,
  126. otherwise C{False}.
  127. @rtype: L{bool}
  128. """
  129. if self.isWindows():
  130. # We do the isWindows() check as newer Pythons support the symlink
  131. # support in Vista+, but only if you have some obscure permission
  132. # (SeCreateSymbolicLinkPrivilege), which can only be given on
  133. # platforms with msc.exe (so, Business/Enterprise editions).
  134. # This uncommon requirement makes the Twisted test suite test fail
  135. # in 99.99% of cases as general users don't have permission to do
  136. # it, even if there is "symlink support".
  137. return False
  138. else:
  139. # If we're not on Windows, check for existence of os.symlink.
  140. try:
  141. os.symlink
  142. except AttributeError:
  143. return False
  144. else:
  145. return True
  146. def supportsThreads(self):
  147. """
  148. Can threads be created?
  149. @return: C{True} if the threads are supported on the current platform.
  150. @rtype: C{bool}
  151. """
  152. try:
  153. import threading
  154. return threading is not None # shh pyflakes
  155. except ImportError:
  156. return False
  157. def supportsINotify(self):
  158. """
  159. Return C{True} if we can use the inotify API on this platform.
  160. @since: 10.1
  161. """
  162. try:
  163. from twisted.python._inotify import INotifyError, init
  164. except ImportError:
  165. return False
  166. if self.isDocker():
  167. return False
  168. try:
  169. os.close(init())
  170. except INotifyError:
  171. return False
  172. return True
  173. platform = Platform()
  174. platformType = platform.getType()
  175. seconds = platform.seconds