diff options
author | Ari Hausman-Cohen <arihc@google.com> | 2016-05-02 16:55:22 -0700 |
---|---|---|
committer | Ari Hausman-Cohen <arihc@google.com> | 2016-05-03 15:23:06 -0700 |
commit | b2b082128abb2bc060c0ef101ee7cc7162624c39 (patch) | |
tree | 5c41446d7200ecfbe060a5d23883bca8faf3966b | |
parent | 3be19546686aa051bf36ff9ddb0b3af6e4900b86 (diff) | |
download | bdk-b2b082128abb2bc060c0ef101ee7cc7162624c39.tar.gz |
Adding platform object.
Abstracts Platforms into a unified object. Not yet
integrated.
BUG: 28401438
Change-Id: I7c727f277c4493e0bd93339fc614f2d2d93e77c7
TEST: unit tests pass
-rw-r--r-- | cli/lib/bsp/device_stub.py | 6 | ||||
-rw-r--r-- | cli/lib/bsp/manifest_stub.py | 15 | ||||
-rw-r--r-- | cli/lib/project/common.py | 5 | ||||
-rw-r--r-- | cli/lib/project/platform.py | 212 | ||||
-rw-r--r-- | cli/lib/project/platform_unittest.py | 165 |
5 files changed, 389 insertions, 14 deletions
diff --git a/cli/lib/bsp/device_stub.py b/cli/lib/bsp/device_stub.py index 257aac2..6372f6d 100644 --- a/cli/lib/bsp/device_stub.py +++ b/cli/lib/bsp/device_stub.py @@ -22,6 +22,10 @@ from bsp import device from test import stubs +class Error(device.Error): + """Raised when a caller attempts to link to the incorrect OS version.""" + + class StubDevice(object): def __init__(self, name='', vendor='', arch='', package_map=None, @@ -36,7 +40,7 @@ class StubDevice(object): def linked(self, os_version): if not self.should_link_version == os_version: - raise device.Error('Not supposed to link to {} (only to {})'.format( + raise Error('Not supposed to link to {} (only to {})'.format( os_version, self.should_link_version)) return stubs.StubContextManager() diff --git a/cli/lib/bsp/manifest_stub.py b/cli/lib/bsp/manifest_stub.py index ed4e50f..b533b24 100644 --- a/cli/lib/bsp/manifest_stub.py +++ b/cli/lib/bsp/manifest_stub.py @@ -26,20 +26,15 @@ class StubManifest(object): from_json_devices = {} def __init__(self, devices): - """devices should be {name: (device, available)}""" - self.devices = {name: device - for (name, (device, _)) - in devices.iteritems()} - self._available = {name: available - for (name, (_, available)) - in devices.iteritems()} + """devices should be {name: device}.""" + self.devices = devices def is_bsp_available(self, device): if not device in self.devices: - raise StubManifestGenerator.UnknownBspError( + raise StubManifestModule.UnknownBspError( 'No such device {}, options are {}'.format( device, self.devices.keys())) - return self._available[device] + return self.devices[device].is_available() # pylint: disable=unused-argument @classmethod @@ -47,7 +42,7 @@ class StubManifest(object): return cls(cls.from_json_devices) -class StubManifestGenerator(object): +class StubManifestModule(object): class Error(error.Error): pass diff --git a/cli/lib/project/common.py b/cli/lib/project/common.py index 40b78fc..836e4db 100644 --- a/cli/lib/project/common.py +++ b/cli/lib/project/common.py @@ -84,11 +84,10 @@ class LoadError(Error): class LoadErrorWithOrigin(LoadError): - def __init__(self, origin, message): + def __init__(self, origin, message='', errno=error.GENERIC_ERRNO): # Prefix where the error occurred at. message = '{}: {}'.format(origin, message) - super(LoadErrorWithOrigin, self).__init__(message) - + super(LoadErrorWithOrigin, self).__init__(message, errno=errno) class UnknownAttributes(LoadErrorWithOrigin): pass diff --git a/cli/lib/project/platform.py b/cli/lib/project/platform.py new file mode 100644 index 0000000..b1884fb --- /dev/null +++ b/cli/lib/project/platform.py @@ -0,0 +1,212 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +"""An object representing a Platform (OS + BSP combination).""" + + +import os + +from bsp import manifest +from core import user_config +from core import util +from project import common + + +BUILD_TYPES = ('user', 'userdebug', 'eng') + + +# Note: this should be kept in sync with +# commands.environment.setup.SAMPLE_MAKEFILE_TEMPLATE +PLATFORM_CACHE_FORMAT = os.path.join('{user_configured_platform_cache}', + '{os_namespace}', + '{board_namespace}') + + +class Error(common.Error): + """General Error for targets.""" + + +class OsError(Error): + """Raised when there is a problem with the specified os/version.""" + description = 'Invalid OS' + + +class BoardError(Error): + """Raised when there is a problem with the specified board/version.""" + description = 'Invalid board' + + +class BuildTypeError(Error): + """Raised when an invalid build type is specified.""" + description = 'Invalid build type' + + +class NotDownloadedError(Error): + """Raised when the specified OS or BSP isn't downloaded.""" + description = 'Missing download' + + +class Platform(object): + """A (read-only) OS + BSP combination. + + Initialization raises an Error if an invalid OS, board, or build_type + is requested. + """ + + def __init__(self, os_name='', os_version='', board='', board_version='', + build_type=''): + """Initialize a Platform. + + Args: + os_name: The name of the OS for this platform. Must be "brillo". + os_version: The version of the OS for this platform. + board: The name of the board for this platform. + board_version: The version of the board for this platform. + build_type: The type of build for this platform. Must be one of + the designated platform.BUILD_TYPES. + + Raises: + OsError: If the OS requested is invalid. + BoardError: If the board requested is invalid. + BuildTypeError: If the build type requested is invalid. + """ + # OS. + if os_name != 'brillo': + raise OsError('"{}" ("brillo" is the only supported ' + 'operating system).'.format(os_name)) + if os_version != util.GetOSVersion(): + # Eventually we will support multiple OS versions, + # at which point this check should just confirm that + # the requested version exists, and an additional check + # should be added to verify_downloaded(). + raise OsError('version {} ({} is the only supported ' + 'OS version).'.format( + util.GetOSVersion(), os_version)) + self._os = os_name + self._os_version = os_version + + # Board. + self._board = board + self._board_version = board_version + self._device = None + # Init device raises a BoardError if it can't get the device. + self._init_device() + + # TODO(b/27654613): Check OS and board compatibility. + + # Build type. + if build_type not in BUILD_TYPES: + raise BuildTypeError('{} (acceptable values are {}).'.format( + build_type, BUILD_TYPES)) + self._build_type = build_type + + # Helper variable. + self._cache_path = PLATFORM_CACHE_FORMAT.format( + user_configured_platform_cache=( + user_config.USER_CONFIG.platform_cache), + os_namespace=self.os_namespace, + board_namespace=self.board_namespace) + + def _init_device(self): + """Initialize the bsp.Device associated with this Target. + + Raises: + BoardError: If the target board and version is not in the manifest. + """ + bsp_manifest = manifest.Manifest.from_json() + device = bsp_manifest.devices.get(self.board) + if not device: + raise BoardError('unrecognized name "{}". Run `bdk bsp list` ' + 'to see available boards.'.format( + self.board)) + if device.version != self.board_version: + raise BoardError('version {} ({} is the only available ' + 'version for {}).'.format( + self.board_version, device.version, self.board)) + self._device = device + + @property + def os(self): + return self._os + + @property + def os_version(self): + return self._os_version + + @property + def os_namespace(self): + return '{}.{}'.format(self.os, self.os_version) + + @property + def board(self): + return self._board + + @property + def board_version(self): + return self._board_version + + @property + def board_namespace(self): + return '{}.{}'.format(self.board, self.board_version) + + @property + def build_type(self): + return self._build_type + + @property + def device(self): + return self._device + + @property + def build_cache(self): + return self.cache_path(self.build_type) + + @property + def product_out_cache(self): + return os.path.join(self.build_cache, 'target', 'product', self.board) + + @property + def toolchain(self): + return self.cache_path('toolchain') + + @property + def sysroot(self): + return self.cache_path('sysroot') + + def cache_path(self, *relpath): + return os.path.join(self._cache_path, *relpath) + + def os_path(self, *relpath): + # TODO(b/28527859): implemented here instead of wrapping. + return util.GetOSPath(self.os_version, *relpath) + + def linked(self): + return self.device.linked(self.os_version) + + def verify_downloaded(self): + """Checks that a platform is downloaded. + + Raises: + NotDownloadedError: If the platform isn't downloaded. + """ + # TODO + # Check that the known OS version matches the desired version. + + # Check that the BSP is downloaded. + if not self.device.is_available(): + raise NotDownloadedError( + 'Board Support Package for "{0}". ' + 'Run `bdk bsp download {0}`.'.format(self.board)) diff --git a/cli/lib/project/platform_unittest.py b/cli/lib/project/platform_unittest.py new file mode 100644 index 0000000..601f54c --- /dev/null +++ b/cli/lib/project/platform_unittest.py @@ -0,0 +1,165 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +"""Unit tests for platform.py.""" + + +import unittest + +from bsp import device_stub +from bsp import manifest_stub +from core import user_config_stub +from core import util_stub +from project import platform +from test import stubs + + +class PlatformTest(unittest.TestCase): + + _OS = 'brillo' + _OS_VERSION = '99.11' + _BSP = 'this_is_a_board' + _BSP_VERSION = '80.80' + _BUILD_TYPE = 'userdebug' + # Should not match any other version used above. + _BAD_VERSION = '0.0' + + def setUp(self): + self.stub_manifest = manifest_stub.StubManifestModule() + self.stub_os = stubs.StubOs() + self.stub_user_config = user_config_stub.StubUserConfig() + self.stub_util = util_stub.StubUtil(os_version=self._OS_VERSION) + + platform.manifest = self.stub_manifest + platform.os = self.stub_os + platform.user_config = self.stub_user_config + platform.util = self.stub_util + + self.dev = device_stub.StubDevice(self._BSP, version=self._BSP_VERSION, + downloaded=True) + self.stub_manifest.Manifest.from_json_devices = {self._BSP: self.dev} + self.platform = platform.Platform( + os_name=self._OS, os_version=self._OS_VERSION, board=self._BSP, + board_version=self._BSP_VERSION, build_type=self._BUILD_TYPE) + + def test_init_valid(self): + # Check all the properties of our correctly initialized platform. + + # Boring ones. + self.assertEqual(self.platform.os, self._OS) + self.assertEqual(self.platform.os_version, self._OS_VERSION) + self.assertEqual(self.platform.board, self._BSP) + self.assertEqual(self.platform.board_version, self._BSP_VERSION) + self.assertEqual(self.platform.build_type, self._BUILD_TYPE) + + # Generated ones. + # Namespaces should somehow be related to names & versions. + self.assertIn(self._OS, self.platform.os_namespace) + self.assertIn(self._OS_VERSION, self.platform.os_namespace) + self.assertIn(self._BSP, self.platform.board_namespace) + self.assertIn(self._BSP_VERSION, self.platform.board_namespace) + self.assertEqual(self.platform.device, self.dev) + cache_root = self.stub_os.path.join( + self.stub_user_config.USER_CONFIG.platform_cache, + self.platform.os_namespace, + self.platform.board_namespace) + self.assertEqual( + self.platform.build_cache, + self.stub_os.path.join(cache_root, self.platform.build_type)) + self.assertEqual(self.platform.sysroot, + self.stub_os.path.join(cache_root, 'sysroot')) + self.assertEqual(self.platform.toolchain, + self.stub_os.path.join(cache_root, 'toolchain')) + self.assertEqual( + self.platform.product_out_cache, + self.stub_os.path.join( + self.platform.build_cache, 'target', 'product', + self.platform.board)) + + def test_init_bad_build_type(self): + with self.assertRaises(platform.BuildTypeError): + platform.Platform(os_name=self._OS, + os_version=self._OS_VERSION, + board=self._BSP, + board_version=self._BSP_VERSION, + build_type='not_a_build_type') + + def test_init_bad_board_version(self): + with self.assertRaises(platform.BoardError): + platform.Platform(os_name=self._OS, + os_version=self._OS_VERSION, + board=self._BSP, + board_version=self._BAD_VERSION, + build_type=self._BUILD_TYPE) + + def test_init_bad_board(self): + with self.assertRaises(platform.BoardError): + platform.Platform(os_name=self._OS, + os_version=self._OS_VERSION, + board='not_a_board', + board_version=self._BSP_VERSION, + build_type=self._BUILD_TYPE) + + def test_init_bad_os_version(self): + with self.assertRaises(platform.OsError): + platform.Platform(os_name=self._OS, + os_version=self._BAD_VERSION, + board=self._BSP, + board_version=self._BSP_VERSION, + build_type=self._BUILD_TYPE) + + def test_init_bad_os(self): + with self.assertRaises(platform.OsError): + platform.Platform(os_name='not_brillo', + os_version=self._OS_VERSION, + board=self._BSP, + board_version=self._BSP_VERSION, + build_type=self._BUILD_TYPE) + + def test_cache_path(self): + cache_root = self.stub_os.path.join( + self.stub_user_config.USER_CONFIG.platform_cache, + self.platform.os_namespace, + self.platform.board_namespace) + self.assertEqual( + self.platform.cache_path('a', 'nother', 'path'), + self.stub_os.path.join(cache_root, 'a', 'nother', 'path')) + + def test_os_path(self): + self.assertEqual( + self.platform.os_path('going', 'down', 'into', 'files'), + self.stub_util.GetOSPath(self._OS_VERSION, + 'going', 'down', 'into', 'files')) + + def test_link(self): + self.dev.should_link_version = self._OS_VERSION + with self.platform.linked(): + pass + + def test_no_link(self): + self.dev.should_link_version = None + with self.assertRaises(device_stub.Error): + with self.platform.linked(): + pass + + def test_verify_downloaded(self): + self.platform.verify_downloaded() + + def test_verify_not_downloaded(self): + self.dev.downloaded = False + with self.assertRaises(platform.NotDownloadedError): + self.platform.verify_downloaded() |