# # 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 . # # Authors: # Tristan Maat 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))