mozinfo.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. #!/usr/bin/env python
  2. # This Source Code Form is subject to the terms of the Mozilla Public
  3. # License, v. 2.0. If a copy of the MPL was not distributed with this file,
  4. # You can obtain one at http://mozilla.org/MPL/2.0/.
  5. # TODO: it might be a good idea of adding a system name (e.g. 'Ubuntu' for
  6. # linux) to the information; I certainly wouldn't want anyone parsing this
  7. # information and having behaviour depend on it
  8. import json
  9. import os
  10. import platform
  11. import re
  12. import sys
  13. import mozfile
  14. # keep a copy of the os module since updating globals overrides this
  15. _os = os
  16. class unknown(object):
  17. """marker class for unknown information"""
  18. def __nonzero__(self):
  19. return False
  20. def __str__(self):
  21. return 'UNKNOWN'
  22. unknown = unknown() # singleton
  23. # get system information
  24. info = {'os': unknown,
  25. 'processor': unknown,
  26. 'version': unknown,
  27. 'bits': unknown }
  28. (system, node, release, version, machine, processor) = platform.uname()
  29. (bits, linkage) = platform.architecture()
  30. # get os information and related data
  31. if system in ["Microsoft", "Windows"]:
  32. info['os'] = 'win'
  33. # There is a Python bug on Windows to determine platform values
  34. # http://bugs.python.org/issue7860
  35. if "PROCESSOR_ARCHITEW6432" in os.environ:
  36. processor = os.environ.get("PROCESSOR_ARCHITEW6432", processor)
  37. else:
  38. processor = os.environ.get('PROCESSOR_ARCHITECTURE', processor)
  39. system = os.environ.get("OS", system).replace('_', ' ')
  40. service_pack = os.sys.getwindowsversion()[4]
  41. info['service_pack'] = service_pack
  42. elif system == "Linux":
  43. if hasattr(platform, "linux_distribution"):
  44. (distro, version, codename) = platform.linux_distribution()
  45. else:
  46. (distro, version, codename) = platform.dist()
  47. version = "%s %s" % (distro, version)
  48. if not processor:
  49. processor = machine
  50. info['os'] = 'linux'
  51. elif system in ['DragonFly', 'FreeBSD', 'NetBSD', 'OpenBSD']:
  52. info['os'] = 'bsd'
  53. version = sys.platform
  54. elif system == "Darwin":
  55. (release, versioninfo, machine) = platform.mac_ver()
  56. version = "OS X %s" % release
  57. info['os'] = 'mac'
  58. elif sys.platform in ('solaris', 'sunos5'):
  59. info['os'] = 'unix'
  60. version = sys.platform
  61. info['version'] = version # os version
  62. # processor type and bits
  63. if processor in ["i386", "i686"]:
  64. if bits == "32bit":
  65. processor = "x86"
  66. elif bits == "64bit":
  67. processor = "x86_64"
  68. elif processor.upper() == "AMD64":
  69. bits = "64bit"
  70. processor = "x86_64"
  71. elif processor == "Power Macintosh":
  72. processor = "ppc"
  73. bits = re.search('(\d+)bit', bits).group(1)
  74. info.update({'processor': processor,
  75. 'bits': int(bits),
  76. })
  77. # standard value of choices, for easy inspection
  78. choices = {'os': ['linux', 'bsd', 'win', 'mac', 'unix'],
  79. 'bits': [32, 64],
  80. 'processor': ['x86', 'x86_64', 'ppc']}
  81. def sanitize(info):
  82. """Do some sanitization of input values, primarily
  83. to handle universal Mac builds."""
  84. if "processor" in info and info["processor"] == "universal-x86-x86_64":
  85. # If we're running on OS X 10.6 or newer, assume 64-bit
  86. if release[:4] >= "10.6": # Note this is a string comparison
  87. info["processor"] = "x86_64"
  88. info["bits"] = 64
  89. else:
  90. info["processor"] = "x86"
  91. info["bits"] = 32
  92. # method for updating information
  93. def update(new_info):
  94. """
  95. Update the info.
  96. :param new_info: Either a dict containing the new info or a path/url
  97. to a json file containing the new info.
  98. """
  99. if isinstance(new_info, basestring):
  100. f = mozfile.load(new_info)
  101. new_info = json.loads(f.read())
  102. f.close()
  103. info.update(new_info)
  104. sanitize(info)
  105. globals().update(info)
  106. # convenience data for os access
  107. for os_name in choices['os']:
  108. globals()['is' + os_name.title()] = info['os'] == os_name
  109. # unix is special
  110. if isLinux or isBsd:
  111. globals()['isUnix'] = True
  112. def find_and_update_from_json(*dirs):
  113. """
  114. Find a mozinfo.json file, load it, and update the info with the
  115. contents.
  116. :param dirs: Directories in which to look for the file. They will be
  117. searched after first looking in the root of the objdir
  118. if the current script is being run from a Mozilla objdir.
  119. Returns the full path to mozinfo.json if it was found, or None otherwise.
  120. """
  121. # First, see if we're in an objdir
  122. try:
  123. from mozbuild.base import MozbuildObject
  124. build = MozbuildObject.from_environment()
  125. json_path = _os.path.join(build.topobjdir, "mozinfo.json")
  126. if _os.path.isfile(json_path):
  127. update(json_path)
  128. return json_path
  129. except ImportError:
  130. pass
  131. for d in dirs:
  132. d = _os.path.abspath(d)
  133. json_path = _os.path.join(d, "mozinfo.json")
  134. if _os.path.isfile(json_path):
  135. update(json_path)
  136. return json_path
  137. return None
  138. update({})
  139. # exports
  140. __all__ = info.keys()
  141. __all__ += ['is' + os_name.title() for os_name in choices['os']]
  142. __all__ += [
  143. 'info',
  144. 'unknown',
  145. 'main',
  146. 'choices',
  147. 'update',
  148. 'find_and_update_from_json',
  149. ]
  150. def main(args=None):
  151. # parse the command line
  152. from optparse import OptionParser
  153. parser = OptionParser(description=__doc__)
  154. for key in choices:
  155. parser.add_option('--%s' % key, dest=key,
  156. action='store_true', default=False,
  157. help="display choices for %s" % key)
  158. options, args = parser.parse_args()
  159. # args are JSON blobs to override info
  160. if args:
  161. for arg in args:
  162. if _os.path.exists(arg):
  163. string = file(arg).read()
  164. else:
  165. string = arg
  166. update(json.loads(string))
  167. # print out choices if requested
  168. flag = False
  169. for key, value in options.__dict__.items():
  170. if value is True:
  171. print '%s choices: %s' % (key, ' '.join([str(choice)
  172. for choice in choices[key]]))
  173. flag = True
  174. if flag: return
  175. # otherwise, print out all info
  176. for key, value in info.items():
  177. print '%s: %s' % (key, value)
  178. if __name__ == '__main__':
  179. main()