| #!/usr/bin/python |
| |
| # Copyright 2017 The Cobalt Authors. 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 |
| # |
| # 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. |
| """Extracts the API versions for all available builds. |
| |
| Example usage: |
| cd cobalt/src/ |
| extract_starboard_versions.py |
| """ |
| |
| from __future__ import print_function |
| |
| import os |
| import re |
| import sys |
| |
| from starboard.build.platforms import PLATFORMS |
| from starboard.tools import paths |
| |
| |
| # Sometimes files have weird encodings. This function will use a variety of |
| # hand selected encoders that work on the starboard codebase. |
| def AutoDecodeString(file_data): |
| for encoding in ['UTF-8', 'utf_16', 'windows-1253', 'iso-8859-7', 'macgreek']: |
| try: |
| return file_data.decode(encoding) |
| except ValueError: |
| continue |
| raise IOError('Could not read file') |
| |
| |
| # Given a search_term, this will open the file_path and return the first |
| # line that contains the search term. This will ignore C-style comments. |
| def SearchInFileReturnFirstMatchingLine(file_path, search_term): |
| try: |
| lines = OpenFileAndDecodeLinesAndRemoveComments(file_path) |
| for line in lines: |
| if search_term in line: |
| return line |
| return None |
| except IOError: |
| print(' error while reading file ', file_path) |
| |
| |
| # Opens a header or cc file and decodes it to utf8 using a variety |
| # of decoders. All lines will have their comments stripped out. |
| # This will return the lines of the given file. |
| def OpenFileAndDecodeLinesAndRemoveComments(file_path): |
| with open(file_path, 'rb+') as fd: |
| lines = AutoDecodeString(fd.read()).splitlines() |
| # remove c-style comments. |
| lines = [re.sub('//.*', '', line) for line in lines] |
| return lines |
| |
| |
| def FindIncludeFiles(file_path): |
| """Given a file_path, return all include files that it contains.""" |
| try: |
| output_list = [] |
| lines = OpenFileAndDecodeLinesAndRemoveComments(file_path) |
| for line in lines: |
| # Remove c-style comments. |
| if '#include' in line: |
| line = re.sub('#include ', '', line).replace('"', '') |
| output_list.append(line) |
| return output_list |
| except IOError: |
| print(' error while reading file ', file_path) |
| |
| |
| # Searches from the search_location for a configuration.h file that |
| # contains the definition of the SB_EXPERIMENTAL_API_VERSION and then |
| # returns that as type int. |
| def ExtractExperimentalApiVersion(config_file_path): |
| """Searches for and extracts the current experimental API version.""" |
| needle = '#define SB_EXPERIMENTAL_API_VERSION' |
| line = SearchInFileReturnFirstMatchingLine( |
| config_file_path, '#define SB_EXPERIMENTAL_API_VERSION') |
| if not line: |
| raise ValueError('Could not find ' + needle + ' in ' + config_file_path) |
| |
| elements = line.split(' ') |
| exp_api_version = int(elements[2]) |
| return exp_api_version |
| |
| |
| # Given platform path, this function will try and find the version. Returns |
| # either the version if found, or None. |
| # If the version string is returned, note that it could be |
| # 'SB_EXPERIMENTAL_VERSION' or a number string. |
| def FindVersion(platform_path): |
| api_version_str = '#define SB_API_VERSION' |
| result = SearchInFileReturnFirstMatchingLine(platform_path, api_version_str) |
| if not result: |
| return None |
| version_str = result.replace(api_version_str, '') |
| return version_str.strip() |
| |
| |
| # Given the path to the platform_include_file, this will find the include |
| # files with "configuration_public.h" in the name and return those. |
| def FindConfigIncludefile(platform_path_config_file): |
| include_files = FindIncludeFiles(platform_path_config_file) |
| include_files = [x for x in include_files if 'configuration_public.h' in x] |
| return include_files |
| |
| |
| def GeneratePlatformPathMap(): |
| """Return a map of platform-name -> full-path-to-platform-config-header.""" |
| |
| def GenPath(platform_path): |
| full_path = os.path.abspath( |
| os.path.join(platform_path, 'configuration_public.h')) |
| if not os.path.exists(full_path): |
| raise IOError('Could not find path ' + full_path) |
| return full_path |
| |
| return { |
| platform_name: GenPath(platform_path) |
| for platform_name, platform_path in PLATFORMS.items() |
| } |
| |
| |
| # Given the root starboard directory, and the full path to the platform, |
| # this function will search for the API_VERSION of the platform. It will |
| # first see if the version is defined within the include file, if it is |
| # not then the include paths for shared platform configurations are |
| # searched in the recursive step. |
| def FindVersionRecursive(starboard_dir, platform_path): |
| version_str = FindVersion(platform_path) |
| if version_str: |
| return version_str |
| else: |
| config_include_paths = FindConfigIncludefile(platform_path) |
| if not config_include_paths: |
| return '<UNKNOWN>' |
| elif len(config_include_paths) > 1: |
| return '<AMBIGUOUS>' |
| else: |
| include_path = config_include_paths[0] |
| include_path = re.sub(r'^starboard/', '', include_path) |
| full_include_path = os.path.join(starboard_dir, include_path) |
| return FindVersionRecursive(starboard_dir, full_include_path) |
| |
| |
| def Main(): |
| """Prints the API versions of all known ports.""" |
| print('\n***** Listing the API versions of all known ports. *****\n') |
| |
| port_dict = GeneratePlatformPathMap() |
| |
| experimental_api_version = ExtractExperimentalApiVersion( |
| os.path.join(paths.STARBOARD_ROOT, 'configuration.h')) |
| |
| path_map = {} |
| |
| print('Experimental API Version: ' + str(experimental_api_version) + '\n') |
| |
| for platform_name, platform_path in port_dict.items(): |
| version_str = FindVersionRecursive(paths.STARBOARD_ROOT, platform_path) |
| if 'SB_EXPERIMENTAL_API_VERSION' in version_str: |
| version_str = str(experimental_api_version) |
| path_map[platform_name] = version_str |
| |
| for platform_name, api_version in sorted(path_map.items()): |
| print(platform_name + ': ' + api_version) |
| |
| return 0 |
| |
| |
| if __name__ == '__main__': |
| # All functionality stored in Main() to avoid py-lint from warning about |
| # about shadowing global variables in local functions. |
| sys.exit(Main()) |