1#!/usr/bin/env python3 2# 3# Copyright 2019 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""Project config class.""" 18 19import os 20 21from aidegen import constant 22from aidegen.lib import common_util 23from aidegen.lib import errors 24 25SKIP_BUILD_INFO = ('If you are sure the related modules and dependencies have ' 26 'been already built, please try to use command {} to skip ' 27 'the building process.') 28_SKIP_BUILD_CMD = 'aidegen {} -s' 29_SKIP_BUILD_WARN = ( 30 'You choose "--skip-build". Skip building jar and module might increase ' 31 'the risk of the absence of some jar or R/AIDL/logtags java files and ' 32 'cause the red lines to appear in IDE tool.') 33_INSTANCE_NOT_EXIST_ERROR = ('The instance of {} does not exist. Please ' 34 'initialize it before using.') 35 36 37class ProjectConfig(): 38 """A singleton class manages AIDEGen's configurations. 39 40 ProjectConfig is a singleton class that can be accessed in other modules. 41 42 Usage: 43 1. Main module should do it once by instantiating a ProjectConfig with 44 users' input arguments and calling init_environment(). 45 args = aidegen_main.main(sys.argv[1:]) 46 project_config.ProjectConfig(args).init_environment() 47 2. All others can get the ProjectConfig instance by calling 48 get_instance(). 49 project_config.ProjectConfig.get_instance() 50 51 Class attributes: 52 _instance: A singleton instance of ProjectConfig. 53 54 Attributes: 55 ide_name: The IDE name which user prefer to launch. 56 is_launch_ide: A boolean for launching IDE in the end of AIDEGen. 57 depth: The depth of module referenced by source. 58 full_repo: A boolean decides import whole Android source repo. 59 is_skip_build: A boolean decides skipping building jars or modules. 60 targets: A string list with Android module names or paths. 61 verbose: A boolean. If true, display DEBUG level logs. 62 ide_installed_path: A string of IDE installed path. 63 config_reset: A boolean if true to reset all saved configurations. 64 atest_module_info: A ModuleInfo instance. 65 """ 66 67 _instance = None 68 69 def __init__(self, args): 70 """ProjectConfig initialize. 71 72 Args: 73 An argparse.Namespace object holds parsed args. 74 """ 75 self.ide_name = constant.IDE_NAME_DICT[args.ide[0]] 76 self.is_launch_ide = not args.no_launch 77 self.depth = args.depth 78 self.full_repo = args.android_tree 79 self.is_skip_build = args.skip_build 80 self.targets = args.targets.copy() 81 self.verbose = args.verbose 82 self.ide_installed_path = args.ide_installed_path 83 self.config_reset = args.config_reset 84 self.exclude_paths = args.exclude_paths 85 self.atest_module_info = None 86 ProjectConfig._instance = self 87 88 def init_environment(self): 89 """Initialize the environment settings for the whole project.""" 90 self._show_skip_build_msg() 91 self.atest_module_info = common_util.get_atest_module_info(self.targets) 92 self.exclude_paths = _transform_exclusive_paths( 93 self.atest_module_info, self.exclude_paths) 94 self.targets = _check_whole_android_tree(self.targets, self.full_repo) 95 self.full_repo = (self.targets[0] == constant.WHOLE_ANDROID_TREE_TARGET) 96 97 def _show_skip_build_msg(self): 98 """Display different messages if users skip building targets or not.""" 99 if self.is_skip_build: 100 print('\n{} {}\n'.format( 101 common_util.COLORED_INFO('Warning:'), _SKIP_BUILD_WARN)) 102 else: 103 msg = SKIP_BUILD_INFO.format( 104 common_util.COLORED_INFO( 105 _SKIP_BUILD_CMD.format(' '.join(self.targets)))) 106 print('\n{} {}\n'.format(common_util.COLORED_INFO('INFO:'), msg)) 107 108 @classmethod 109 def get_instance(cls): 110 """Get a singleton's instance. 111 112 Returns: 113 A singleton instance of ProjectConfig. 114 115 Raises: 116 An exception of errors.InstanceNotExistError if users didn't 117 instantiate a ProjectConfig object before calling this method. 118 """ 119 if not cls._instance: 120 raise errors.InstanceNotExistError( 121 _INSTANCE_NOT_EXIST_ERROR.format(str(cls))) 122 return cls._instance 123 124 125def _check_whole_android_tree(targets, android_tree): 126 """Check if it's a building project file for the whole Android tree. 127 128 The rules: 129 1. If users command aidegen under Android root, e.g., 130 root$ aidegen 131 that implies users would like to launch the whole Android tree, AIDEGen 132 should set the flag android_tree True. 133 2. If android_tree is True, add whole Android tree to the project. 134 135 Args: 136 targets: A list of targets to be imported. 137 android_tree: A boolean, True if it's a whole Android tree case, 138 otherwise False. 139 140 Returns: 141 A list of targets to be built. 142 """ 143 if common_util.is_android_root(os.getcwd()) and targets == ['']: 144 return [constant.WHOLE_ANDROID_TREE_TARGET] 145 new_targets = targets.copy() 146 if android_tree: 147 new_targets.insert(0, constant.WHOLE_ANDROID_TREE_TARGET) 148 return new_targets 149 150 151def is_whole_android_tree(targets, android_tree): 152 """Checks is AIDEGen going to process whole android tree. 153 154 Args: 155 targets: A list of targets to be imported. 156 android_tree: A boolean, True if it's a whole Android tree case, 157 otherwise False. 158 Returns: 159 A boolean, True when user is going to import whole Android tree. 160 """ 161 return (android_tree or 162 (common_util.is_android_root(os.getcwd()) and targets == [''])) 163 164 165def _transform_exclusive_paths(atest_module_info, exclude_paths): 166 """Transforms exclusive paths to relative paths. 167 168 Args: 169 exclude_paths: A list of strings of exclusive paths. 170 171 Returns: 172 A list of relative paths. 173 """ 174 if not exclude_paths: 175 return None 176 excludes = [] 177 for path in exclude_paths: 178 exclude_path, _ = common_util.get_related_paths(atest_module_info, path) 179 excludes.append(exclude_path) 180 return excludes 181