| # |
| # Copyright (C) 2017 Codethink Limited |
| # |
| # This program is free software; you can redistribute it and/or |
| # modify it under the terms of the GNU Lesser General Public |
| # License as published by the Free Software Foundation; either |
| # version 2 of the License, or (at your option) any later version. |
| # |
| # This library is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| # Lesser General Public License for more details. |
| # |
| # You should have received a copy of the GNU Lesser General Public |
| # License along with this library. If not, see <http://www.gnu.org/licenses/>. |
| # |
| # Authors: |
| # Tristan Maat <tristan.maat@codethink.co.uk> |
| |
| import os |
| import sys |
| import resource |
| |
| from .._exceptions import PlatformError, ImplError |
| |
| |
| class Platform(): |
| _instance = None |
| |
| # Platform() |
| # |
| # A class to manage platform-specific details. Currently holds the |
| # sandbox factory as well as platform helpers. |
| # |
| def __init__(self): |
| self.set_resource_limits() |
| |
| @classmethod |
| def _create_instance(cls): |
| # Meant for testing purposes and therefore hidden in the |
| # deepest corners of the source code. Try not to abuse this, |
| # please? |
| if os.getenv('BST_FORCE_BACKEND'): |
| backend = os.getenv('BST_FORCE_BACKEND') |
| elif sys.platform.startswith('linux'): |
| backend = 'linux' |
| elif sys.platform.startswith('darwin'): |
| backend = 'darwin' |
| else: |
| backend = 'unix' |
| |
| if backend == 'linux': |
| from .linux import Linux as PlatformImpl |
| elif backend == 'darwin': |
| from .darwin import Darwin as PlatformImpl |
| elif backend == 'unix': |
| from .unix import Unix as PlatformImpl |
| else: |
| raise PlatformError("No such platform: '{}'".format(backend)) |
| |
| cls._instance = PlatformImpl() |
| |
| @classmethod |
| def get_platform(cls): |
| if not cls._instance: |
| cls._create_instance() |
| return cls._instance |
| |
| def get_cpu_count(self, cap=None): |
| cpu_count = len(os.sched_getaffinity(0)) |
| if cap is None: |
| return cpu_count |
| else: |
| return min(cpu_count, cap) |
| |
| @staticmethod |
| def get_host_os(): |
| return os.uname()[0] |
| |
| # canonicalize_arch(): |
| # |
| # This returns the canonical, OS-independent architecture name |
| # or raises a PlatformError if the architecture is unknown. |
| # |
| @staticmethod |
| def canonicalize_arch(arch): |
| aliases = { |
| "aarch32": "aarch32", |
| "aarch64": "aarch64", |
| "aarch64-be": "aarch64-be", |
| "amd64": "x86-64", |
| "arm": "aarch32", |
| "armv8l": "aarch64", |
| "armv8b": "aarch64-be", |
| "i386": "x86-32", |
| "i486": "x86-32", |
| "i586": "x86-32", |
| "i686": "x86-32", |
| "power-isa-be": "power-isa-be", |
| "power-isa-le": "power-isa-le", |
| "ppc64": "power-isa-be", |
| "ppc64le": "power-isa-le", |
| "sparc": "sparc-v9", |
| "sparc64": "sparc-v9", |
| "sparc-v9": "sparc-v9", |
| "x86-32": "x86-32", |
| "x86-64": "x86-64" |
| } |
| |
| try: |
| return aliases[arch.replace('_', '-')] |
| except KeyError: |
| raise PlatformError("Unknown architecture: {}".format(arch)) |
| |
| # get_host_arch(): |
| # |
| # This returns the architecture of the host machine. The possible values |
| # map from uname -m in order to be a OS independent list. |
| # |
| # Returns: |
| # (string): String representing the architecture |
| @staticmethod |
| def get_host_arch(): |
| # get the hardware identifier from uname |
| uname_machine = os.uname()[4] |
| return Platform.canonicalize_arch(uname_machine) |
| |
| ################################################################## |
| # Sandbox functions # |
| ################################################################## |
| |
| # create_sandbox(): |
| # |
| # Create a build sandbox suitable for the environment |
| # |
| # Args: |
| # args (dict): The arguments to pass to the sandbox constructor |
| # kwargs (file): The keyword arguments to pass to the sandbox constructor |
| # |
| # Returns: |
| # (Sandbox) A sandbox |
| # |
| def create_sandbox(self, *args, **kwargs): |
| raise ImplError("Platform {platform} does not implement create_sandbox()" |
| .format(platform=type(self).__name__)) |
| |
| def check_sandbox_config(self, config): |
| raise ImplError("Platform {platform} does not implement check_sandbox_config()" |
| .format(platform=type(self).__name__)) |
| |
| def set_resource_limits(self, soft_limit=None, hard_limit=None): |
| # Need to set resources for _frontend/app.py as this is dependent on the platform |
| # SafeHardlinks FUSE needs to hold file descriptors for all processes in the sandbox. |
| # Avoid hitting the limit too quickly. |
| limits = resource.getrlimit(resource.RLIMIT_NOFILE) |
| if limits[0] != limits[1]: |
| if soft_limit is None: |
| soft_limit = limits[1] |
| if hard_limit is None: |
| hard_limit = limits[1] |
| resource.setrlimit(resource.RLIMIT_NOFILE, (soft_limit, hard_limit)) |