blob: e763abea3a7a69789c7bf2d6d1f636e6b4d87cf2 [file] [log] [blame]
Andrew Topc2b40892017-01-19 14:03:49 -08001#
2# Copyright 2016 Google Inc. All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16"""Functionality to enumerate and represent starboard ports."""
17
18import importlib
19import logging
20import os
21import re
22
23
24# The list of files that must be present in a directory to allow it to be
25# considered a valid port.
26_PORT_FILES = [
27 'gyp_configuration.gypi',
28 'gyp_configuration.py',
29 'starboard_platform.gyp',
30 'configuration_public.h',
31 'atomic_public.h',
32 'thread_types_public.h',
33]
34
35
36# Whether to emit warnings if it finds a directory that almost has a port.
37# TODO: Enable when tree is clean.
38_WARN_ON_ALMOST_PORTS = False
39
40
41def _IsValidPortFilenameList(directory, filenames):
42 """Determines if |filenames| contains the required files for a valid port."""
43 missing = set(_PORT_FILES) - set(filenames)
44 if missing:
45 if len(missing) < (len(_PORT_FILES) / 2) and _WARN_ON_ALMOST_PORTS:
46 logging.warning('Directory %s contains several files needed for a port, '
47 'but not all of them. In particular, it is missing: %s',
48 directory, ', '.join(missing))
49 return not missing
50
51
52def _GetPortName(root, directory):
53 """Gets the name of a port found at |directory| off of |root|."""
54
55 assert directory.startswith(root)
56 start = len(root) + 1 # Remove the trailing slash from the root.
57
58 assert start < len(directory)
59
60 # Calculate the name based on relative path from search root to port.
61 return re.sub(r'[^a-zA-Z0-9_]', r'-', directory[start:])
62
63
64class PlatformInfo(object):
65 """Information about a specific starboard port."""
66
67 @classmethod
68 def EnumeratePorts(cls, root_path):
69 """Generator that iterates over starboard ports found under |path|."""
70 for current_path, _, filenames in os.walk(root_path):
71 if _IsValidPortFilenameList(current_path, filenames):
72 if current_path == root_path:
73 logging.warning('Found port at search path root: %s', current_path)
74 port_name = _GetPortName(root_path, current_path)
75 yield PlatformInfo(port_name, current_path)
76
77 def __init__(self, name, path):
78 self.port_name = name
79 self.path = path
80
81 def ImportModule(self, root_module, module_name=None):
82 """Load a platform specific python module using importlib.
83
84 Load the python module named |module_name| relative to |root_module|.
85 Args:
86 module: Name of a python module to load. If None, load the platform
87 directory as a python module.
88 root_module: An already-loaded module
89 Returns:
90 A module loaded with importlib.import_module
91 Throws:
92 ImportError if the module fails to be loaded.
93 """
94 # From the relative path to the |root_module|'s directory, construct a full
95 # python package name and attempt to load it.
96 relative_path = os.path.relpath(
97 self.path, os.path.dirname(root_module.__file__))
98 components = os.path.normpath(relative_path).split(os.sep)
99 components = [root_module.__name__] + components
100 if module_name:
101 components.append(module_name)
102 full_package_name = '.'.join(components)
103 return importlib.import_module(full_package_name)