blob: ca1723d25de8f851ec20858a59efe90a417e293e [file] [log] [blame]
# Copyright 2016 Google Inc. All Rights Reserved.
# 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
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# See the License for the specific language governing permissions and
# limitations under the License.
"""Functionality to enumerate and represent starboard ports."""
import importlib
import logging
import os
import re
import _env # pylint: disable=unused-import
from import environment
# The list of files that must be present in a directory to allow it to be
# considered a valid port.
# Whether to emit warnings if it finds a directory that almost has a port.
# TODO: Enable when tree is clean.
def _IsValidPortFilenameList(directory, filenames):
"""Determines if |filenames| contains the required files for a valid port."""
missing = set(_PORT_FILES) - set(filenames)
if missing:
if len(missing) < (len(_PORT_FILES) / 2) and _WARN_ON_ALMOST_PORTS:
logging.warning('Directory %s contains several files needed for a port, '
'but not all of them. In particular, it is missing: %s',
directory, ', '.join(missing))
return not missing
def _GetPortName(root, directory):
"""Gets the name of a port found at |directory| off of |root|."""
assert directory.startswith(root)
start = len(root) + 1 # Remove the trailing slash from the root.
assert start < len(directory)
# Calculate the name based on relative path from search root to port.
return re.sub(r'[^a-zA-Z0-9_]', r'-', directory[start:])
def _GetAllPlatforms(port_root_paths):
"""Retrieves information about all available Cobalt ports.
port_root_paths: List of paths that will be crawled to find ports.
Dict mapping each available port to its location in the filesystem.
platform_dict = {}
for path in port_root_paths:
for port in PlatformInfo.EnumeratePorts(path):
platform_dict[port.port_name] = port.path
return platform_dict
def GetAllPorts():
"""Gets all available starboard ports from the host app.
Dictionary mapping port names to their path in the filesystem.
port_root_paths = environment.GetStarboardPortRoots()
return _GetAllPlatforms(port_root_paths)
def GetAllNames():
"""Gets a list of all valid Starboard platform names.
List of valid platform names.
return sorted(GetAllPorts().keys())
def IsValid(platform):
return platform in GetAllNames()
class PlatformInfo(object):
"""Information about a specific starboard port."""
def EnumeratePorts(cls, root_path, exclusion_set=None):
"""Generator that iterates over starboard ports found under |path|."""
if not exclusion_set:
exclusion_set = set()
for current_path, directories, filenames in os.walk(root_path):
# Don't walk into any directories in the exclusion set.
directories[:] = (x for x in directories
if os.path.join(current_path, x) not in exclusion_set)
# Determine if the current directory is a valid port directory.
if _IsValidPortFilenameList(current_path, filenames):
if current_path == root_path:
logging.warning('Found port at search path root: %s', current_path)
port_name = _GetPortName(root_path, current_path)
yield PlatformInfo(port_name, current_path)
def __init__(self, name, path):
self.port_name = name
self.path = path
def ImportModule(self, root_module, module_name=None):
"""Load a platform specific python module using importlib.
Load the python module named |module_name| relative to |root_module|.
root_module: An already-loaded module
module_name: Name of a python module to load. If None, load the platform
directory as a python module.
A module loaded with importlib.import_module
ImportError if the module fails to be loaded.
# From the relative path to the |root_module|'s directory, construct a full
# python package name and attempt to load it.
relative_path = os.path.relpath(
self.path, os.path.dirname(root_module.__file__))
components = os.path.normpath(relative_path).split(os.sep)
components = [root_module.__name__] + components
if module_name:
full_package_name = '.'.join(components)
return importlib.import_module(full_package_name)