| #!/usr/bin/env python3 |
| # |
| # Copyright 2019 - 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. |
| |
| """Project config class.""" |
| |
| import os |
| |
| from aidegen import constant |
| from aidegen.lib import common_util |
| from aidegen.lib import errors |
| |
| SKIP_BUILD_INFO = ('If you are sure the related modules and dependencies have ' |
| 'been already built, please try to use command {} to skip ' |
| 'the building process.') |
| _SKIP_BUILD_CMD = 'aidegen {} -s' |
| _SKIP_BUILD_WARN = ( |
| 'You chose "--skip-build". Skip building jar and module might increase ' |
| 'the risk of the absence of some jar or R/AIDL/logtags java files and ' |
| 'cause the red lines to appear in IDE tool.') |
| _INSTANCE_NOT_EXIST_ERROR = ('The instance of {} does not exist. Please ' |
| 'initialize it before using.') |
| |
| |
| class ProjectConfig: |
| """A singleton class manages AIDEGen's configurations. |
| |
| ProjectConfig is a singleton class that can be accessed in other modules. |
| |
| Usage: |
| 1. Main module should do it once by instantiating a ProjectConfig with |
| users' input arguments and calling init_environment(). |
| args = aidegen_main.main(sys.argv[1:]) |
| project_config.ProjectConfig(args).init_environment() |
| 2. All others can get the ProjectConfig instance by calling |
| get_instance(). |
| project_config.ProjectConfig.get_instance() |
| |
| Class attributes: |
| _instance: A singleton instance of ProjectConfig. |
| |
| Attributes: |
| ide_name: The IDE name which users prefer to launch. |
| is_launch_ide: A boolean for launching IDE in the end of AIDEGen. |
| depth: The depth of module referenced by source. |
| full_repo: A boolean decides import whole Android source repo. |
| is_skip_build: A boolean decides skipping building jars or modules. |
| targets: A string list with Android module names or paths. |
| verbose: A boolean. If true, display DEBUG level logs. |
| ide_installed_path: A string of IDE installed path. |
| config_reset: A boolean if true to reset all saved configurations. |
| atest_module_info: A ModuleInfo instance. |
| language: The programming language users prefer to deal with. |
| """ |
| |
| _instance = None |
| |
| def __init__(self, args): |
| """ProjectConfig initialize. |
| |
| Args: |
| An argparse.Namespace object holds parsed args. |
| """ |
| self.language = constant.LANGUAGE_NAME_DICT[args.language[0]] |
| self.ide_name = constant.IDE_NAME_DICT[args.ide[0]] |
| self.is_launch_ide = not args.no_launch |
| self.depth = args.depth |
| self.full_repo = args.android_tree |
| self.is_skip_build = args.skip_build |
| self.targets = args.targets.copy() |
| self.verbose = args.verbose |
| self.ide_installed_path = args.ide_installed_path |
| self.config_reset = args.config_reset |
| self.exclude_paths = args.exclude_paths |
| self.atest_module_info = None |
| ProjectConfig._instance = self |
| |
| def init_environment(self): |
| """Initialize the environment settings for the whole project.""" |
| self._show_skip_build_msg() |
| # TODO(b/159078170): Avoid CLion IDE case for now, we should avoid |
| # Android Studio's native project's case in the future. |
| targets = self.targets if self.language == constant.JAVA else None |
| self.atest_module_info = common_util.get_atest_module_info(targets) |
| self.exclude_paths = _transform_exclusive_paths( |
| self.atest_module_info, self.exclude_paths) |
| self.targets = _check_whole_android_tree(self.targets, self.full_repo) |
| self.full_repo = (self.targets[0] == constant.WHOLE_ANDROID_TREE_TARGET) |
| |
| def _show_skip_build_msg(self): |
| """Display different messages if users skip building targets or not.""" |
| if self.is_skip_build: |
| print('\n{} {}\n'.format( |
| common_util.COLORED_INFO('Warning:'), _SKIP_BUILD_WARN)) |
| else: |
| msg = SKIP_BUILD_INFO.format( |
| common_util.COLORED_INFO( |
| _SKIP_BUILD_CMD.format(' '.join(self.targets)))) |
| print('\n{} {}\n'.format(common_util.COLORED_INFO('INFO:'), msg)) |
| |
| @classmethod |
| def get_instance(cls): |
| """Get a singleton's instance. |
| |
| Returns: |
| A singleton instance of ProjectConfig. |
| |
| Raises: |
| An exception of errors.InstanceNotExistError if users didn't |
| instantiate a ProjectConfig object before calling this method. |
| """ |
| if not cls._instance: |
| raise errors.InstanceNotExistError( |
| _INSTANCE_NOT_EXIST_ERROR.format(str(cls))) |
| return cls._instance |
| |
| |
| def _check_whole_android_tree(targets, android_tree): |
| """Check if it's a building project file for the whole Android tree. |
| |
| The rules: |
| 1. If users command aidegen under Android root, e.g., |
| root$ aidegen |
| that implies users would like to launch the whole Android tree, AIDEGen |
| should set the flag android_tree True. |
| 2. If android_tree is True, add whole Android tree to the project. |
| |
| Args: |
| targets: A list of targets to be imported. |
| android_tree: A boolean, True if it's a whole Android tree case, |
| otherwise False. |
| |
| Returns: |
| A list of targets to be built. |
| """ |
| if common_util.is_android_root(os.getcwd()) and targets == ['']: |
| return [constant.WHOLE_ANDROID_TREE_TARGET] |
| new_targets = targets.copy() |
| if android_tree: |
| new_targets.insert(0, constant.WHOLE_ANDROID_TREE_TARGET) |
| return new_targets |
| |
| |
| def is_whole_android_tree(targets, android_tree): |
| """Checks is AIDEGen going to process whole android tree. |
| |
| Args: |
| targets: A list of targets to be imported. |
| android_tree: A boolean, True if it's a whole Android tree case, |
| otherwise False. |
| Returns: |
| A boolean, True when user is going to import whole Android tree. |
| """ |
| return (android_tree or |
| (common_util.is_android_root(os.getcwd()) and targets == [''])) |
| |
| |
| def _transform_exclusive_paths(atest_module_info, exclude_paths): |
| """Transforms exclusive paths to relative paths. |
| |
| Args: |
| exclude_paths: A list of strings of exclusive paths. |
| |
| Returns: |
| A list of relative paths. |
| """ |
| if not exclude_paths: |
| return None |
| excludes = [] |
| for path in exclude_paths: |
| exclude_path, _ = common_util.get_related_paths(atest_module_info, path) |
| excludes.append(exclude_path) |
| return excludes |