blob: 1192c406ccf61268a8e9eb21337a1bc26221ef97 [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Module to resolve the current platform and bitness that works across
infrastructure systems.
"""
import itertools
import platform
import sys
def get():
"""Returns the normalized platform and bitness values.
Platform: linux, mac, win
Machine:
- x86_64 (Intel 64-bit)
- x86 (Intel 32-bit)
- armv6l (ARM 32-bit v6)
- arm64 (ARM 64-bit)
- <other> (Unknown, returned by platform.machine())
Bits: 32, 64
Returns:
plat (str): The name of the current platform.
machine (str): The normalized machine type.
bits (int): The bitness of the current platform, one of 32, 64.
Raises:
ValueError if both the platform and bitness could not be resolved.
"""
plat = sys.platform
machine = platform.machine().lower()
arch = platform.architecture()[0]
if plat.startswith('linux'):
plat = 'linux'
elif plat.startswith(('win', 'cygwin')):
plat = 'win'
elif plat.startswith(('darwin', 'mac')):
plat = 'mac'
else: # pragma: no cover
raise ValueError("Don't understand platform [%s]" % (plat,))
# Normalize "machine".
if any(machine.startswith(x) for x in ('arm64', 'aarch64')):
machine = 'arm64'
elif machine.startswith('arm') and machine.endswith('l'):
# 32-bit ARM: Standardize on ARM v6 baseline.
machine = 'armv6l'
elif machine in ('amd64',):
machine = 'x86_64'
elif machine in ('i386', 'i686'):
machine = 'x86'
# Extract architecture.
if arch == '64bit':
bits = 64
elif arch == '32bit':
bits = 32
else: # pragma: no cover
raise ValueError("Don't understand architecture [%s]" % (arch,))
return plat, machine, bits
def exe_suffix():
"""Returns either '' or '.exe' depending on the platform."""
plat, _, _ = get()
return '.exe' if plat == 'win' else ''
def cipd_os():
"""Returns the equivalent of `cipd ensure`'s ${os}.
Example: 'windows', 'mac', 'linux'
'"""
os_name, _, _ = get()
return _cipd_os(os_name)
def _cipd_os(os_name):
return os_name.replace('win', 'windows')
def cipd_arch():
"""Returns the equivalent of `cipd ensure`'s ${arch}.
Example: 'amd64', '386'
"""
os_name, machine, bits = get()
return _cipd_arch(os_name, machine, bits)
def _cipd_arch(os_name, machine, bits):
# Linux can run a 64bit kernel with a 32bit userspace. `machine` comes from
# platform.machine(), which determines the kernel value, but `bits` comes from
# looking at the architecture of sys.executable. We assume that sys.executable
# is an adequate representation of 'userspace', and so downgrade a 64bit
# machine type to 32bit.
#
# The bitness of the CIPD client executable will determine the value of
# ${arch} and for our purposes here, we want the CIPD client bitness to match
# the bitness of userspace.
if _cipd_os(os_name) == 'linux' and machine == 'x86_64' and bits == 32:
return '386'
return {
'x86': '386',
'x86_64': 'amd64',
}.get(machine, machine)
def cipd_platform():
"""Return the equivalent of `cipd ensure`'s ${platform}."""
os_name, machine, bits = get()
return "%s-%s" % (_cipd_os(os_name), _cipd_arch(os_name, machine, bits))
def cipd_all_targets():
"""Returns an iterable of (platform, arch) tuples for all supported buildslave
platforms that we expect CIPD packages to exist for.
This is used for CIPD presubmit validation.
"""
return (
('linux', 'amd64'),
('linux', 'arm64'),
('linux', 'armv6l'),
('linux', 'mips64'),
('mac', 'amd64'),
('windows', '386'),
('windows', 'amd64'),
)
def cascade_config(config, plat=None):
"""Returns (dict): The constructed configuration dictionary.
Traverses the supplied configuration dictionary, building a cascading
configuration by folding in values of increasingly-specialized platform tuple
keys. The platform tuple that is traversed is the one returned by 'get'.
For example, on a 64-bit Linux platform with a 'config' dictionary of:
config = {
(): {
'foo': 'foo-generic',
'bar': 'bar-generic',
'baz': 'baz-generic',
},
('linux',): {
'bar': 'bar-linux',
'baz': 'baz-linux',
},
('linux', 64): {
'qux': 'qux-linux-64bit-generic',
},
('linux', 'x86_64'): {
'baz': 'baz-linux-amd64',
},
}
The resulting dictionary would be:
{
'foo': 'foo-generic',
'bar': 'bar-linux',
'baz': 'baz-linux-amd64',
'qux': 'qux-linux-64bit-generic',
}
Args:
config (dict): Dictionary keyed on platform tuples.
"""
# Cascade the platform configuration.
plat = plat or get()
result = {}
for r in xrange(len(plat)+1):
for c in itertools.combinations(plat, r):
result.update(config.get(c, {}))
return result