You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
217 lines
7.9 KiB
217 lines
7.9 KiB
#!/usr/bin/env python3
|
|
#
|
|
# Copyright 2020 - 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.
|
|
|
|
"""Config Android SDK information.
|
|
|
|
In order to create the configuration of Android SDK in IntelliJ automatically,
|
|
parses the Android SDK information from the Android SDK path.
|
|
|
|
Usage example:
|
|
android_sdk = AndroidSDK()
|
|
android_sdk.path_analysis(default_sdk_path)
|
|
api_level = android_sdk.max_api_level
|
|
android_sdk_path = android_sdk.android_sdk_path
|
|
platform_mapping = android_sdk.platform_mapping
|
|
"""
|
|
|
|
from __future__ import absolute_import
|
|
|
|
import glob
|
|
import os
|
|
import re
|
|
|
|
from aidegen.lib import common_util
|
|
|
|
|
|
class AndroidSDK:
|
|
"""Configures API level from the Android SDK path.
|
|
|
|
Attributes:
|
|
_android_sdk_path: The path to the Android SDK, None if the Android SDK
|
|
doesn't exist.
|
|
_max_api_level: An integer, the max API level in the platforms folder.
|
|
_max_code_name: A string, the code name of the max API level.
|
|
_platform_mapping: A dictionary of Android platform versions mapping to
|
|
the API level and the Android version code name.
|
|
e.g.
|
|
{
|
|
'android-29': {'api_level': 29, 'code_name': '29'},
|
|
'android-Q': {'api_level': 29, 'code_name': 'Q'}
|
|
}
|
|
"""
|
|
|
|
_API_LEVEL = 'api_level'
|
|
_CODE_NAME = 'code_name'
|
|
_RE_API_LEVEL = re.compile(r'AndroidVersion.ApiLevel=(?P<api_level>[\d]+)')
|
|
_RE_CODE_NAME = re.compile(r'AndroidVersion.CodeName=(?P<code_name>[A-Z])')
|
|
_GLOB_PROPERTIES_FILE = os.path.join('platforms', 'android-*',
|
|
'source.properties')
|
|
_INPUT_QUERY_TIMES = 3
|
|
_ENTER_ANDROID_SDK_PATH = ('\nThe Android SDK folder:{} doesn\'t exist. '
|
|
'The debug function "Attach debugger to Android '
|
|
'process" is disabled without Android SDK in '
|
|
'IntelliJ or Android Studio. Please set it up '
|
|
'to enable the function. \nPlease enter the '
|
|
'absolute path to Android SDK:')
|
|
_WARNING_NO_ANDROID_SDK = ('Please install the Android SDK, otherwise the '
|
|
'debug function "Attach debugger to Android '
|
|
'process" cannot be enabled in IntelliJ or '
|
|
'Android Studio.')
|
|
|
|
def __init__(self):
|
|
"""Initializes AndroidSDK."""
|
|
self._max_api_level = 0
|
|
self._max_code_name = None
|
|
self._platform_mapping = {}
|
|
self._android_sdk_path = None
|
|
|
|
@property
|
|
def max_api_level(self):
|
|
"""Gets the max API level."""
|
|
return self._max_api_level
|
|
|
|
@property
|
|
def max_code_name(self):
|
|
"""Gets the max code name."""
|
|
return self._max_code_name
|
|
|
|
@property
|
|
def platform_mapping(self):
|
|
"""Gets the Android platform mapping."""
|
|
return self._platform_mapping
|
|
|
|
@property
|
|
def android_sdk_path(self):
|
|
"""Gets the Android SDK path."""
|
|
return self._android_sdk_path
|
|
|
|
def _parse_max_api_level(self):
|
|
"""Parses the max API level from self._platform_mapping.
|
|
|
|
Returns:
|
|
An integer of API level and 0 means no Android platform exists.
|
|
"""
|
|
return max(
|
|
[v[self._API_LEVEL] for v in self._platform_mapping.values()],
|
|
default=0)
|
|
|
|
def _parse_max_code_name(self):
|
|
"""Parses the max code name from self._platform_mapping.
|
|
|
|
Returns:
|
|
A string of code name.
|
|
"""
|
|
code_name = ''
|
|
for data in self._platform_mapping.values():
|
|
if (data[self._API_LEVEL] == self._max_api_level
|
|
and data[self._CODE_NAME] > code_name):
|
|
code_name = data[self._CODE_NAME]
|
|
return code_name
|
|
|
|
def _parse_api_info(self, properties_file):
|
|
"""Parses the API information from the source.properties file.
|
|
|
|
For the preview platform like android-Q, the source.properties file
|
|
contains two properties named AndroidVersion.ApiLevel, API level of
|
|
the platform, and AndroidVersion.CodeName such as Q, the code name of
|
|
the platform.
|
|
However, the formal platform like android-29, there is no property
|
|
AndroidVersion.CodeName.
|
|
|
|
Args:
|
|
properties_file: A path of the source.properties file.
|
|
|
|
Returns:
|
|
A tuple contains the API level and Code name of the
|
|
source.properties file.
|
|
API level: An integer of the platform, e.g. 29.
|
|
Code name: A string, e.g. 29 or Q.
|
|
"""
|
|
api_level = 0
|
|
properties = common_util.read_file_content(properties_file)
|
|
match_api_level = self._RE_API_LEVEL.search(properties)
|
|
if match_api_level:
|
|
api_level = match_api_level.group(self._API_LEVEL)
|
|
match_code_name = self._RE_CODE_NAME.search(properties)
|
|
if match_code_name:
|
|
code_name = match_code_name.group(self._CODE_NAME)
|
|
else:
|
|
code_name = api_level
|
|
return api_level, code_name
|
|
|
|
def _gen_platform_mapping(self, path):
|
|
"""Generates the Android platforms mapping.
|
|
|
|
Args:
|
|
path: A string, the absolute path of Android SDK.
|
|
|
|
Returns:
|
|
True when successful generates platform mapping, otherwise False.
|
|
"""
|
|
prop_files = glob.glob(os.path.join(path, self._GLOB_PROPERTIES_FILE))
|
|
for prop_file in prop_files:
|
|
api_level, code_name = self._parse_api_info(prop_file)
|
|
if not api_level:
|
|
continue
|
|
platform = os.path.basename(os.path.dirname(prop_file))
|
|
self._platform_mapping[platform] = {
|
|
self._API_LEVEL: int(api_level),
|
|
self._CODE_NAME: code_name
|
|
}
|
|
return bool(self._platform_mapping)
|
|
|
|
def is_android_sdk_path(self, path):
|
|
"""Checks if the Android SDK path is correct.
|
|
|
|
Confirm the Android SDK path is correct by checking if it has
|
|
platform versions.
|
|
|
|
Args:
|
|
path: A string, the path of Android SDK user input.
|
|
|
|
Returns:
|
|
True when get a platform version, otherwise False.
|
|
"""
|
|
if self._gen_platform_mapping(path):
|
|
self._android_sdk_path = path
|
|
self._max_api_level = self._parse_max_api_level()
|
|
self._max_code_name = self._parse_max_code_name()
|
|
return True
|
|
return False
|
|
|
|
def path_analysis(self, sdk_path):
|
|
"""Analyses the Android SDK path.
|
|
|
|
Confirm the path is a Android SDK folder. If it's not correct, ask user
|
|
to enter a new one. Skip asking when enter nothing.
|
|
|
|
Args:
|
|
sdk_path: A string, the path of Android SDK.
|
|
|
|
Returns:
|
|
True when get an Android SDK path, otherwise False.
|
|
"""
|
|
for _ in range(self._INPUT_QUERY_TIMES):
|
|
if self.is_android_sdk_path(sdk_path):
|
|
return True
|
|
sdk_path = input(common_util.COLORED_FAIL(
|
|
self._ENTER_ANDROID_SDK_PATH.format(sdk_path)))
|
|
if not sdk_path:
|
|
break
|
|
print('\n{} {}\n'.format(common_util.COLORED_INFO('Warning:'),
|
|
self._WARNING_NO_ANDROID_SDK))
|
|
return False
|