bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # Copyright 2018 - 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 | """Functional test for aidegen project files.""" |
| 18 | |
| 19 | from __future__ import absolute_import |
morrislin | 23b618e | 2020-10-22 14:36:51 +0800 | [diff] [blame] | 20 | from __future__ import print_function |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 21 | |
| 22 | import argparse |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 23 | import functools |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 24 | import itertools |
| 25 | import json |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 26 | import logging |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 27 | import os |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 28 | import subprocess |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 29 | import sys |
| 30 | import xml.etree.ElementTree |
| 31 | import xml.parsers.expat |
| 32 | |
| 33 | from aidegen import aidegen_main |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 34 | from aidegen import constant |
bralee | c89ed9f | 2020-01-23 22:26:58 +0800 | [diff] [blame] | 35 | from aidegen.lib import clion_project_file_gen |
morrislin | 23b618e | 2020-10-22 14:36:51 +0800 | [diff] [blame] | 36 | # pylint: disable=no-name-in-module |
bralee | 627fcd9 | 2019-06-04 08:41:28 +0800 | [diff] [blame] | 37 | from aidegen.lib import common_util |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 38 | from aidegen.lib import errors |
bralee | c89ed9f | 2020-01-23 22:26:58 +0800 | [diff] [blame] | 39 | from aidegen.lib import module_info_util |
| 40 | from aidegen.lib import project_config |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 41 | from aidegen.lib import project_file_gen |
| 42 | |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 43 | from atest import module_info |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 44 | |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 45 | _PRODUCT_DIR = '$PROJECT_DIR$' |
bralee | 627fcd9 | 2019-06-04 08:41:28 +0800 | [diff] [blame] | 46 | _ROOT_DIR = os.path.join(common_util.get_android_root_dir(), |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 47 | 'tools/asuite/aidegen_functional_test') |
| 48 | _TEST_DATA_PATH = os.path.join(_ROOT_DIR, 'test_data') |
bralee | 7731882 | 2018-11-23 15:56:06 +0800 | [diff] [blame] | 49 | _VERIFY_COMMANDS_JSON = os.path.join(_TEST_DATA_PATH, 'verify_commands.json') |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 50 | _GOLDEN_SAMPLES_JSON = os.path.join(_TEST_DATA_PATH, 'golden_samples.json') |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 51 | _VERIFY_BINARY_JSON = os.path.join(_TEST_DATA_PATH, 'verify_binary_upload.json') |
morrislin | 23b618e | 2020-10-22 14:36:51 +0800 | [diff] [blame] | 52 | _VERIFY_PRESUBMIT_JSON = os.path.join(_TEST_DATA_PATH, 'verify_presubmit.json') |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 53 | _ANDROID_COMMON = 'android_common' |
| 54 | _LINUX_GLIBC_COMMON = 'linux_glibc_common' |
| 55 | _SRCS = 'srcs' |
| 56 | _JARS = 'jars' |
| 57 | _URL = 'url' |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 58 | _TEST_ERROR = 'AIDEGen functional test error: {}-{} is different.' |
| 59 | _MSG_NOT_IN_PROJECT_FILE = ('{} is expected, but not found in the created ' |
| 60 | 'project file: {}') |
| 61 | _MSG_NOT_IN_SAMPLE_DATA = ('{} is unexpected, but found in the created project ' |
| 62 | 'file: {}') |
bralee | 7731882 | 2018-11-23 15:56:06 +0800 | [diff] [blame] | 63 | _ALL_PASS = 'All tests passed!' |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 64 | _GIT_COMMIT_ID_JSON = os.path.join( |
| 65 | _TEST_DATA_PATH, 'baseline_code_commit_id.json') |
| 66 | _GIT = 'git' |
| 67 | _CHECKOUT = 'checkout' |
| 68 | _BRANCH = 'branch' |
| 69 | _COMMIT = 'commit' |
| 70 | _LOG = 'log' |
| 71 | _ALL = '--all' |
| 72 | _COMMIT_ID_NOT_EXIST_ERROR = ('Commit ID: {} does not exist in path: {}. ' |
| 73 | 'Please use "git log" command to check if it ' |
| 74 | 'exists. If it does not, try to update your ' |
| 75 | 'source files to the latest version or do not ' |
| 76 | 'use "repo init --depth=1" command.') |
| 77 | _GIT_LOG_ERROR = 'Command "git log -n 1" failed.' |
bralee | c89ed9f | 2020-01-23 22:26:58 +0800 | [diff] [blame] | 78 | _BE_REPLACED = '${config.X86_64GccRoot}' |
| 79 | _TO_REPLACE = 'prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9' |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 80 | |
| 81 | |
| 82 | def _parse_args(args): |
| 83 | """Parse command line arguments. |
| 84 | |
| 85 | Args: |
| 86 | args: A list of arguments. |
| 87 | |
| 88 | Returns: |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 89 | An argparse.Namespace object holding parsed args. |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 90 | """ |
| 91 | parser = argparse.ArgumentParser( |
| 92 | description=__doc__, |
| 93 | formatter_class=argparse.RawDescriptionHelpFormatter, |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 94 | usage='aidegen_functional_test [-c | -u | -b | -a] -v -r') |
bralee | 7731882 | 2018-11-23 15:56:06 +0800 | [diff] [blame] | 95 | group = parser.add_mutually_exclusive_group() |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 96 | parser.required = False |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 97 | parser.add_argument( |
| 98 | 'targets', |
| 99 | type=str, |
| 100 | nargs='*', |
| 101 | default=[''], |
| 102 | help='Android module name or path.e.g. frameworks/base') |
bralee | 7731882 | 2018-11-23 15:56:06 +0800 | [diff] [blame] | 103 | group.add_argument( |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 104 | '-c', |
| 105 | '--create-sample', |
| 106 | action='store_true', |
| 107 | dest='create_sample', |
| 108 | help=('Create aidegen project files and write data to sample json file ' |
| 109 | 'for aidegen_functional_test to compare.')) |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 110 | parser.add_argument( |
bralee | 7731882 | 2018-11-23 15:56:06 +0800 | [diff] [blame] | 111 | '-v', |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 112 | '--verbose', |
bralee | 7731882 | 2018-11-23 15:56:06 +0800 | [diff] [blame] | 113 | action='store_true', |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 114 | help='Show DEBUG level logging.') |
| 115 | parser.add_argument( |
| 116 | '-r', |
| 117 | '--remove_bp_json', |
| 118 | action='store_true', |
| 119 | help='Remove module_bp_java_deps.json for each use case test.') |
bralee | 50284e3 | 2020-10-26 11:32:32 +0800 | [diff] [blame] | 120 | parser.add_argument( |
| 121 | '-m', |
| 122 | '--make_clean', |
| 123 | action='store_true', |
| 124 | help=('Make clean before testing to create a clean environment, the ' |
| 125 | 'aidegen_functional_test can run only once if users command it.')) |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 126 | group.add_argument( |
| 127 | '-u', |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 128 | '--use_cases', |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 129 | action='store_true', |
| 130 | dest='use_cases_verified', |
bralee | 7731882 | 2018-11-23 15:56:06 +0800 | [diff] [blame] | 131 | help='Verify various use cases of executing aidegen.') |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 132 | group.add_argument( |
| 133 | '-b', |
| 134 | action='store_true', |
| 135 | dest='binary_upload_verified', |
| 136 | help=('Verify aidegen\'s use cases by executing different aidegen ' |
| 137 | 'commands.')) |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 138 | group.add_argument( |
morrislin | 23b618e | 2020-10-22 14:36:51 +0800 | [diff] [blame] | 139 | '-p', |
| 140 | action='store_true', |
| 141 | dest='binary_presubmit_verified', |
| 142 | help=('Verify aidegen\'s tool in presubmit test by executing' |
| 143 | 'different aidegen commands.')) |
| 144 | group.add_argument( |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 145 | '-a', |
| 146 | '--test-all', |
| 147 | action='store_true', |
| 148 | dest='test_all_samples', |
| 149 | help='Test all modules listed in module-info.json.') |
bralee | c89ed9f | 2020-01-23 22:26:58 +0800 | [diff] [blame] | 150 | group.add_argument( |
| 151 | '-n', |
| 152 | '--compare-sample-native', |
| 153 | action='store_true', |
| 154 | dest='compare_sample_native', |
| 155 | help=('Compare if sample native project file is the same as generated ' |
| 156 | 'by the build system.')) |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 157 | return parser.parse_args(args) |
| 158 | |
| 159 | |
| 160 | def _import_project_file_xml_etree(filename): |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 161 | """Import iml project file and load its data into a dictionary. |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 162 | |
| 163 | Args: |
| 164 | filename: The input project file name. |
bralee | 30fedf3 | 2019-05-20 08:30:28 +0800 | [diff] [blame] | 165 | |
| 166 | Returns: |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 167 | A dictionary contains dependent files' data of project file's contents. |
| 168 | The samples are like: |
| 169 | "srcs": [ |
| 170 | ... |
| 171 | "file://$PROJECT_DIR$/frameworks/base/cmds/am/src", |
| 172 | "file://$PROJECT_DIR$/frameworks/base/cmds/appwidget/src", |
| 173 | ... |
| 174 | ] |
| 175 | "jars": [ |
| 176 | ... |
| 177 | "jar://$PROJECT_DIR$/out/host/common/obj/**/classes-header.jar!/" |
| 178 | ... |
| 179 | ] |
| 180 | |
| 181 | Raises: |
| 182 | EnvironmentError and xml parsing or format errors. |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 183 | """ |
| 184 | data = {} |
| 185 | try: |
| 186 | tree = xml.etree.ElementTree.parse(filename) |
| 187 | data[_SRCS] = [] |
| 188 | root = tree.getroot() |
| 189 | for element in root.iter('sourceFolder'): |
bralee | 627fcd9 | 2019-06-04 08:41:28 +0800 | [diff] [blame] | 190 | src = element.get(_URL).replace(common_util.get_android_root_dir(), |
| 191 | _PRODUCT_DIR) |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 192 | data[_SRCS].append(src) |
| 193 | data[_JARS] = [] |
| 194 | for element in root.iter('root'): |
bralee | 627fcd9 | 2019-06-04 08:41:28 +0800 | [diff] [blame] | 195 | jar = element.get(_URL).replace(common_util.get_android_root_dir(), |
| 196 | _PRODUCT_DIR) |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 197 | data[_JARS].append(jar) |
| 198 | except (EnvironmentError, ValueError, LookupError, |
| 199 | xml.parsers.expat.ExpatError) as err: |
| 200 | print("{0}: import error: {1}".format(os.path.basename(filename), err)) |
| 201 | raise |
| 202 | return data |
| 203 | |
| 204 | |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 205 | def _get_project_file_names(abs_path): |
| 206 | """Get project file name and depenencies name by relative path. |
| 207 | |
| 208 | Args: |
| 209 | abs_path: an absolute module's path. |
bralee | 30fedf3 | 2019-05-20 08:30:28 +0800 | [diff] [blame] | 210 | |
| 211 | Returns: |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 212 | file_name: a string of the project file name. |
| 213 | dep_name: a string of the merged project and dependencies file's name, |
| 214 | e.g., frameworks-dependencies.iml. |
| 215 | """ |
morrislin | 23b618e | 2020-10-22 14:36:51 +0800 | [diff] [blame] | 216 | # pylint: disable=maybe-no-member |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 217 | code_name = project_file_gen.ProjectFileGenerator.get_unique_iml_name( |
| 218 | abs_path) |
| 219 | file_name = ''.join([code_name, '.iml']) |
| 220 | dep_name = ''.join([constant.KEY_DEPENDENCIES, '.iml']) |
| 221 | return file_name, dep_name |
| 222 | |
| 223 | |
| 224 | def _get_unique_module_name(rel_path, filename): |
| 225 | """Get a unique project file name or dependencies name by relative path. |
| 226 | |
| 227 | Args: |
| 228 | rel_path: a relative module's path to aosp root path. |
| 229 | filename: the file name to be generated in module_in type file name. |
| 230 | |
| 231 | Returns: |
| 232 | A string, the unique file name for the whole module-info.json. |
| 233 | """ |
| 234 | code_names = rel_path.split(os.sep) |
| 235 | code_names[-1] = filename |
| 236 | return '-'.join(code_names) |
| 237 | |
| 238 | |
| 239 | def _get_git_current_commit_id(abs_path): |
| 240 | """Get target's git checkout command list. |
| 241 | |
| 242 | When we run command 'git log -n 1' and get the top first git log record, the |
| 243 | commit id is next to the specific word 'commit'. |
| 244 | |
| 245 | Args: |
| 246 | abs_path: a string of the absolute path of the target branch. |
| 247 | |
| 248 | Return: |
| 249 | The current git commit id. |
| 250 | |
| 251 | Raises: |
| 252 | Call subprocess.check_output cause subprocess.CalledProcessError. |
| 253 | """ |
| 254 | cwd = os.getcwd() |
| 255 | os.chdir(abs_path) |
| 256 | git_log_cmds = [_GIT, _LOG, '-n', '1'] |
| 257 | try: |
| 258 | out_put = subprocess.check_output(git_log_cmds).decode("utf-8") |
| 259 | except subprocess.CalledProcessError: |
| 260 | logging.error(_GIT_LOG_ERROR) |
| 261 | raise |
| 262 | finally: |
| 263 | os.chdir(cwd) |
| 264 | com_list = out_put.split() |
| 265 | return com_list[com_list.index(_COMMIT) + 1] |
| 266 | |
| 267 | |
| 268 | def _get_commit_id_dictionary(): |
| 269 | """Get commit id from dictionary of key, value 'module': 'commit id'.""" |
| 270 | data_id_dict = {} |
| 271 | with open(_GIT_COMMIT_ID_JSON, 'r') as jsfile: |
| 272 | data_id_dict = json.load(jsfile) |
| 273 | return data_id_dict |
| 274 | |
| 275 | |
| 276 | def _git_checkout_commit_id(abs_path, commit_id): |
| 277 | """Command to checkout specific commit id. |
| 278 | |
| 279 | Change directory to the module's absolute path which users want to get its |
| 280 | specific commit id. |
| 281 | |
| 282 | Args: |
| 283 | abs_path: the absolute path of the target branch. E.g., abs_path/.git |
| 284 | commit_id: the commit id users want to checkout. |
| 285 | |
| 286 | Raises: |
| 287 | Call git checkout commit id failed, raise errors.CommitIDNotExistError. |
| 288 | """ |
| 289 | git_chekout_cmds = [_GIT, _CHECKOUT, commit_id] |
| 290 | cwd = os.getcwd() |
| 291 | try: |
| 292 | os.chdir(abs_path) |
| 293 | subprocess.check_output(git_chekout_cmds) |
| 294 | except subprocess.CalledProcessError: |
| 295 | err = _COMMIT_ID_NOT_EXIST_ERROR.format(commit_id, abs_path) |
| 296 | logging.error(err) |
| 297 | raise errors.CommitIDNotExistError(err) |
| 298 | finally: |
| 299 | os.chdir(cwd) |
| 300 | |
| 301 | |
| 302 | def _git_checkout_target_commit_id(target, commit_id): |
| 303 | """Command to checkout target commit id. |
| 304 | |
| 305 | Switch code base to specific commit id which is kept in data_id_dict with |
| 306 | target: commit_id as key: value. If the data is missing in data_id_dict, the |
| 307 | target isn't a selected golden sample raise error for it. |
| 308 | |
| 309 | Args: |
| 310 | target: the string of target's module name or module path to checkout |
| 311 | the relevant git to its specific commit id. |
| 312 | commit_id: a string represent target's specific commit id. |
| 313 | |
| 314 | Returns: |
| 315 | current_commit_id: the current commit id of the target which should be |
| 316 | switched back to. |
bralee | 30fedf3 | 2019-05-20 08:30:28 +0800 | [diff] [blame] | 317 | """ |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 318 | atest_module_info = module_info.ModuleInfo() |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 319 | _, abs_path = common_util.get_related_paths(atest_module_info, target) |
| 320 | current_commit_id = _get_git_current_commit_id(abs_path) |
| 321 | _git_checkout_commit_id(abs_path, commit_id) |
| 322 | return current_commit_id |
| 323 | |
| 324 | |
| 325 | def _checkout_baseline_code_to_spec_commit_id(): |
| 326 | """Get a dict of target, commit id listed in baseline_code_commit_id.json. |
| 327 | |
| 328 | To make sure all samples run on the same environment, we need to keep all |
| 329 | the baseline code in a specific commit id. For example, all samples should |
| 330 | be created in the same specific commit id of the baseline code |
| 331 | 'frameworks/base' for comparison except 'frameworks/base' itself. |
| 332 | |
| 333 | Returns: |
| 334 | A dictionary contains target, specific and current commit id. |
| 335 | """ |
| 336 | spec_and_cur_commit_id_dict = {} |
| 337 | data_id_dict = _get_commit_id_dictionary() |
| 338 | for target in data_id_dict: |
| 339 | commit_id = data_id_dict.get(target, '') |
| 340 | current_commit_id = _git_checkout_target_commit_id(target, commit_id) |
| 341 | spec_and_cur_commit_id_dict[target] = {} |
| 342 | spec_and_cur_commit_id_dict[target]['current'] = current_commit_id |
| 343 | return spec_and_cur_commit_id_dict |
| 344 | |
| 345 | |
| 346 | def _generate_target_real_iml_data(target): |
| 347 | """Generate single target's real iml file content's data. |
| 348 | |
| 349 | Args: |
| 350 | target: Android module name or path to be create iml data. |
| 351 | |
| 352 | Returns: |
| 353 | data: A dictionary contains key: unique file name and value: iml |
| 354 | content. |
| 355 | """ |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 356 | data = {} |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 357 | try: |
| 358 | aidegen_main.main([target, '-s', '-n', '-v']) |
| 359 | except (errors.FakeModuleError, |
| 360 | errors.ProjectOutsideAndroidRootError, |
| 361 | errors.ProjectPathNotExistError, |
| 362 | errors.NoModuleDefinedInModuleInfoError) as err: |
| 363 | logging.error(str(err)) |
| 364 | return data |
| 365 | |
| 366 | atest_module_info = module_info.ModuleInfo() |
| 367 | rel_path, abs_path = common_util.get_related_paths(atest_module_info, |
| 368 | target) |
| 369 | for filename in iter(_get_project_file_names(abs_path)): |
| 370 | real_iml_file = os.path.join(abs_path, filename) |
| 371 | item_name = _get_unique_module_name(rel_path, filename) |
| 372 | data[item_name] = _import_project_file_xml_etree(real_iml_file) |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 373 | return data |
| 374 | |
| 375 | |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 376 | def _generate_sample_json(test_list): |
| 377 | """Generate sample iml data. |
| 378 | |
| 379 | We use all baseline code samples on the version of their own specific commit |
| 380 | id which is kept in _GIT_COMMIT_ID_JSON file. We need to switch back to |
| 381 | their current commit ids after generating golden samples' data. |
| 382 | |
| 383 | Args: |
| 384 | test_list: a list of module name and module path. |
bralee | 50284e3 | 2020-10-26 11:32:32 +0800 | [diff] [blame] | 385 | |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 386 | Returns: |
| 387 | data: a dictionary contains dependent files' data of project file's |
| 388 | contents. |
| 389 | The sample is like: |
| 390 | "frameworks-base.iml": { |
| 391 | "srcs": [ |
| 392 | .... |
| 393 | "file://$PROJECT_DIR$/frameworks/base/cmds/am/src", |
| 394 | "file://$PROJECT_DIR$/frameworks/base/cmds/appwidget/src", |
| 395 | .... |
| 396 | ], |
| 397 | "jars": [ |
| 398 | .... |
| 399 | "jar://$PROJECT_DIR$/out/target/common/**/aapt2.srcjar!/", |
| 400 | .... |
| 401 | ] |
| 402 | } |
| 403 | """ |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 404 | data = {} |
| 405 | spec_and_cur_commit_id_dict = _checkout_baseline_code_to_spec_commit_id() |
| 406 | for target in test_list: |
| 407 | data.update(_generate_target_real_iml_data(target)) |
| 408 | atest_module_info = module_info.ModuleInfo() |
| 409 | for target in spec_and_cur_commit_id_dict: |
| 410 | _, abs_path = common_util.get_related_paths(atest_module_info, target) |
| 411 | _git_checkout_commit_id( |
| 412 | abs_path, spec_and_cur_commit_id_dict[target]['current']) |
| 413 | return data |
| 414 | |
| 415 | |
| 416 | def _create_some_sample_json_file(targets): |
| 417 | """Write some samples' iml data into a json file. |
| 418 | |
| 419 | Args: |
| 420 | targets: Android module name or path to be create iml data. |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 421 | |
| 422 | linked_function: _generate_sample_json() |
| 423 | """ |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 424 | data = _generate_sample_json(targets) |
| 425 | data_sample = {} |
| 426 | with open(_GOLDEN_SAMPLES_JSON, 'r') as infile: |
| 427 | try: |
| 428 | data_sample = json.load(infile) |
morrislin | 23b618e | 2020-10-22 14:36:51 +0800 | [diff] [blame] | 429 | # pylint: disable=maybe-no-member |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 430 | except json.JSONDecodeError as err: |
| 431 | print("Json decode error: {}".format(err)) |
| 432 | data_sample = {} |
| 433 | data_sample.update(data) |
| 434 | with open(_GOLDEN_SAMPLES_JSON, 'w') as outfile: |
| 435 | json.dump(data_sample, outfile, indent=4, sort_keys=False) |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 436 | |
| 437 | |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 438 | def test_samples(func): |
| 439 | """Decorate a function to deal with preparing and verifying staffs of it. |
| 440 | |
| 441 | Args: |
| 442 | func: a function is to be compared its iml data with the json file's |
| 443 | data. |
| 444 | |
| 445 | Returns: |
| 446 | The wrapper function. |
| 447 | """ |
| 448 | |
| 449 | @functools.wraps(func) |
| 450 | def wrapper(*args, **kwargs): |
| 451 | """A wrapper function.""" |
| 452 | |
| 453 | test_successful = True |
| 454 | with open(_GOLDEN_SAMPLES_JSON, 'r') as outfile: |
| 455 | data_sample = json.load(outfile) |
| 456 | |
| 457 | data_real = func(*args, **kwargs) |
| 458 | |
| 459 | for name in data_real: |
| 460 | for item in [_SRCS, _JARS]: |
| 461 | s_items = data_sample[name][item] |
| 462 | r_items = data_real[name][item] |
| 463 | if set(s_items) != set(r_items): |
| 464 | diff_iter = _compare_content(name, item, s_items, r_items) |
| 465 | if diff_iter: |
| 466 | print('\n{} {}'.format( |
| 467 | common_util.COLORED_INFO('Test error:'), |
| 468 | _TEST_ERROR.format(name, item))) |
| 469 | print('{} {} contents are different:'.format( |
| 470 | name, item)) |
| 471 | for diff in diff_iter: |
| 472 | print(diff) |
| 473 | test_successful = False |
| 474 | if test_successful: |
| 475 | print(common_util.COLORED_PASS(_ALL_PASS)) |
| 476 | return test_successful |
| 477 | |
| 478 | return wrapper |
| 479 | |
| 480 | |
| 481 | @test_samples |
| 482 | def _test_some_sample_iml(targets=None): |
| 483 | """Compare with sample iml's data to assure the project's contents is right. |
| 484 | |
| 485 | Args: |
| 486 | targets: Android module name or path to be create iml data. |
| 487 | """ |
| 488 | if targets: |
| 489 | return _generate_sample_json(targets) |
| 490 | return _generate_sample_json(_get_commit_id_dictionary().keys()) |
| 491 | |
| 492 | |
| 493 | @test_samples |
| 494 | def _test_all_samples_iml(): |
| 495 | """Compare all imls' data with all samples' data. |
| 496 | |
| 497 | It's to make sure each iml's contents is right. The function is implemented |
| 498 | but hasn't been used yet. |
| 499 | """ |
| 500 | all_module_list = module_info.ModuleInfo().name_to_module_info.keys() |
| 501 | return _generate_sample_json(all_module_list) |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 502 | |
| 503 | |
| 504 | def _compare_content(module_name, item_type, s_items, r_items): |
| 505 | """Compare src or jar files' data of two dictionaries. |
| 506 | |
| 507 | Args: |
| 508 | module_name: the test module name. |
| 509 | item_type: the type is src or jar. |
| 510 | s_items: sample jars' items. |
| 511 | r_items: real jars' items. |
| 512 | |
| 513 | Returns: |
| 514 | An iterator of not equal sentences after comparison. |
| 515 | """ |
| 516 | if item_type == _SRCS: |
| 517 | cmp_iter1 = _compare_srcs_content(module_name, s_items, r_items, |
| 518 | _MSG_NOT_IN_PROJECT_FILE) |
| 519 | cmp_iter2 = _compare_srcs_content(module_name, r_items, s_items, |
| 520 | _MSG_NOT_IN_SAMPLE_DATA) |
| 521 | else: |
| 522 | cmp_iter1 = _compare_jars_content(module_name, s_items, r_items, |
| 523 | _MSG_NOT_IN_PROJECT_FILE) |
| 524 | cmp_iter2 = _compare_jars_content(module_name, r_items, s_items, |
| 525 | _MSG_NOT_IN_SAMPLE_DATA) |
| 526 | return itertools.chain(cmp_iter1, cmp_iter2) |
| 527 | |
| 528 | |
| 529 | def _compare_srcs_content(module_name, s_items, r_items, msg): |
| 530 | """Compare src or jar files' data of two dictionaries. |
| 531 | |
| 532 | Args: |
| 533 | module_name: the test module name. |
| 534 | s_items: sample jars' items. |
| 535 | r_items: real jars' items. |
| 536 | msg: the message will be written into log file. |
| 537 | |
| 538 | Returns: |
| 539 | An iterator of not equal sentences after comparison. |
| 540 | """ |
| 541 | for sample in s_items: |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 542 | if sample not in r_items: |
| 543 | yield msg.format(sample, module_name) |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 544 | |
| 545 | |
| 546 | def _compare_jars_content(module_name, s_items, r_items, msg): |
| 547 | """Compare src or jar files' data of two dictionaries. |
| 548 | |
bralee | 30fedf3 | 2019-05-20 08:30:28 +0800 | [diff] [blame] | 549 | AIDEGen treats the jars in folder names 'linux_glib_common' and |
| 550 | 'android_common' as the same content. If the paths are different only |
| 551 | because of these two names, we ignore it. |
| 552 | |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 553 | Args: |
| 554 | module_name: the test module name. |
| 555 | s_items: sample jars' items. |
| 556 | r_items: real jars' items. |
| 557 | msg: the message will be written into log file. |
| 558 | |
| 559 | Returns: |
| 560 | An iterator of not equal sentences after comparison. |
| 561 | """ |
| 562 | for sample in s_items: |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 563 | if sample not in r_items: |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 564 | lnew = sample |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 565 | if constant.LINUX_GLIBC_COMMON in sample: |
| 566 | lnew = sample.replace(constant.LINUX_GLIBC_COMMON, |
| 567 | constant.ANDROID_COMMON) |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 568 | else: |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 569 | lnew = sample.replace(constant.ANDROID_COMMON, |
| 570 | constant.LINUX_GLIBC_COMMON) |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 571 | if not lnew in r_items: |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 572 | yield msg.format(sample, module_name) |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 573 | |
| 574 | |
bralee | 7731882 | 2018-11-23 15:56:06 +0800 | [diff] [blame] | 575 | # pylint: disable=broad-except |
| 576 | # pylint: disable=eval-used |
bralee | a65f1e5 | 2019-10-17 15:31:47 +0800 | [diff] [blame] | 577 | @common_util.back_to_cwd |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 578 | @common_util.time_logged |
morrislin | 23b618e | 2020-10-22 14:36:51 +0800 | [diff] [blame] | 579 | def _verify_aidegen(verified_file_path, forced_remove_bp_json, |
| 580 | is_presubmit=False): |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 581 | """Verify various use cases of executing aidegen. |
| 582 | |
| 583 | There are two types of running commands: |
| 584 | 1. Use 'eval' to run the commands for present codes in aidegen_main.py, |
| 585 | such as: |
| 586 | aidegen_main.main(['tradefed', '-n', '-v']) |
| 587 | 2. Use 'subprocess.check_call' to run the commands for the binary codes of |
| 588 | aidegen such as: |
| 589 | aidegen tradefed -n -v |
| 590 | |
| 591 | Remove module_bp_java_deps.json in the beginning of running use cases. If |
| 592 | users need to remove module_bp_java_deps.json between each use case they |
| 593 | can set forced_remove_bp_json true. |
| 594 | |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 595 | Args: |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 596 | verified_file_path: The json file path to be verified. |
| 597 | forced_remove_bp_json: Remove module_bp_java_deps.json for each use case |
| 598 | test. |
| 599 | |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 600 | Raises: |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 601 | There are two type of exceptions: |
| 602 | 1. aidegen.lib.errors for projects' or modules' issues such as, |
| 603 | ProjectPathNotExistError. |
| 604 | 2. Any exceptions other than aidegen.lib.errors such as, |
| 605 | subprocess.CalledProcessError. |
| 606 | """ |
bralee | ec0dd88 | 2019-12-12 21:17:16 +0800 | [diff] [blame] | 607 | bp_json_path = common_util.get_blueprint_json_path( |
| 608 | constant.BLUEPRINT_JAVA_JSONFILE_NAME) |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 609 | use_eval = (verified_file_path == _VERIFY_COMMANDS_JSON) |
| 610 | try: |
| 611 | with open(verified_file_path, 'r') as jsfile: |
| 612 | data = json.load(jsfile) |
| 613 | except IOError as err: |
| 614 | raise errors.JsonFileNotExistError( |
| 615 | '%s does not exist, error: %s.' % (verified_file_path, err)) |
| 616 | |
morrislin | 23b618e | 2020-10-22 14:36:51 +0800 | [diff] [blame] | 617 | if not is_presubmit: |
morrislin | 23b618e | 2020-10-22 14:36:51 +0800 | [diff] [blame] | 618 | _compare_sample_native_content() |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 619 | |
bralee | a65f1e5 | 2019-10-17 15:31:47 +0800 | [diff] [blame] | 620 | os.chdir(common_util.get_android_root_dir()) |
bralee | 7731882 | 2018-11-23 15:56:06 +0800 | [diff] [blame] | 621 | for use_case in data: |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 622 | print('Use case "{}" is running.'.format(use_case)) |
| 623 | if forced_remove_bp_json and os.path.exists(bp_json_path): |
bralee | 30fedf3 | 2019-05-20 08:30:28 +0800 | [diff] [blame] | 624 | os.remove(bp_json_path) |
bralee | 7731882 | 2018-11-23 15:56:06 +0800 | [diff] [blame] | 625 | for cmd in data[use_case]: |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 626 | print('Command "{}" is running.'.format(cmd)) |
bralee | 7731882 | 2018-11-23 15:56:06 +0800 | [diff] [blame] | 627 | try: |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 628 | if use_eval: |
| 629 | eval(cmd) |
| 630 | else: |
| 631 | subprocess.check_call(cmd, shell=True) |
| 632 | except (errors.ProjectOutsideAndroidRootError, |
| 633 | errors.ProjectPathNotExistError, |
| 634 | errors.NoModuleDefinedInModuleInfoError, |
| 635 | errors.IDENotExistError) as err: |
| 636 | print('"{}" raises error: {}.'.format(use_case, err)) |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 637 | continue |
bralee | 30fedf3 | 2019-05-20 08:30:28 +0800 | [diff] [blame] | 638 | except BaseException: |
| 639 | exc_type, _, _ = sys.exc_info() |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 640 | print('"{}.{}" command {}.'.format( |
| 641 | use_case, cmd, common_util.COLORED_FAIL('executes failed'))) |
bralee | 30fedf3 | 2019-05-20 08:30:28 +0800 | [diff] [blame] | 642 | raise BaseException( |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 643 | 'Unexpected command "{}" exception: {}.'.format( |
bralee | 30fedf3 | 2019-05-20 08:30:28 +0800 | [diff] [blame] | 644 | use_case, exc_type)) |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 645 | print('"{}" command {}!'.format( |
| 646 | use_case, common_util.COLORED_PASS('test passed'))) |
| 647 | print(common_util.COLORED_PASS(_ALL_PASS)) |
| 648 | |
bralee | 7731882 | 2018-11-23 15:56:06 +0800 | [diff] [blame] | 649 | |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 650 | @common_util.back_to_cwd |
| 651 | def _make_clean(): |
| 652 | """Make a command to clean out folder for a pure environment to test. |
| 653 | |
| 654 | Raises: |
| 655 | Call subprocess.check_call to execute |
| 656 | 'build/soong/soong_ui.bash --make-mode clean' and cause |
| 657 | subprocess.CalledProcessError. |
| 658 | """ |
| 659 | try: |
| 660 | os.chdir(common_util.get_android_root_dir()) |
| 661 | subprocess.check_call( |
| 662 | ['build/soong/soong_ui.bash --make-mode clean', '-j'], |
| 663 | shell=True) |
| 664 | except subprocess.CalledProcessError: |
| 665 | print('"build/soong/soong_ui.bash --make-mode clean" command failed.') |
| 666 | raise |
| 667 | |
| 668 | |
bralee | c89ed9f | 2020-01-23 22:26:58 +0800 | [diff] [blame] | 669 | def _read_file_content(path): |
| 670 | """Read file's content. |
| 671 | |
| 672 | Args: |
| 673 | path: Path of input file. |
| 674 | |
| 675 | Returns: |
| 676 | A list of content strings. |
| 677 | """ |
| 678 | with open(path, encoding='utf8') as template: |
| 679 | contents = [] |
| 680 | for cnt in template: |
| 681 | if cnt.startswith('#'): |
| 682 | continue |
| 683 | contents.append(cnt.rstrip()) |
| 684 | return contents |
| 685 | |
| 686 | |
| 687 | # pylint: disable=protected-access |
| 688 | def _compare_sample_native_content(): |
| 689 | """Compares 'libui' sample module's project file. |
| 690 | |
| 691 | Compares 'libui' sample module's project file generated by AIDEGen with that |
| 692 | generated by the soong build system. Check if their contents are the same. |
| 693 | There should be only one different: |
| 694 | ${config.X86_64GccRoot} # in the soong build sytem |
| 695 | becomes |
| 696 | prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9 # in AIDEGen |
| 697 | """ |
bralee | c89ed9f | 2020-01-23 22:26:58 +0800 | [diff] [blame] | 698 | target_arch_variant = 'x86_64' |
| 699 | env_on = { |
| 700 | 'TARGET_PRODUCT': 'aosp_x86_64', |
| 701 | 'TARGET_BUILD_VARIANT': 'eng', |
| 702 | 'TARGET_ARCH_VARIANT': target_arch_variant, |
| 703 | 'SOONG_COLLECT_JAVA_DEPS': 'true', |
| 704 | 'SOONG_GEN_CMAKEFILES': '1', |
bralee | c89ed9f | 2020-01-23 22:26:58 +0800 | [diff] [blame] | 705 | 'SOONG_COLLECT_CC_DEPS': '1' |
| 706 | } |
| 707 | |
| 708 | try: |
| 709 | project_config.ProjectConfig( |
| 710 | aidegen_main._parse_args(['-n', '-v'])).init_environment() |
bralee | 20699f0 | 2020-07-13 09:36:45 +0800 | [diff] [blame] | 711 | module_info_util.generate_merged_module_info(env_on) |
bralee | c89ed9f | 2020-01-23 22:26:58 +0800 | [diff] [blame] | 712 | cc_path = os.path.join(common_util.get_soong_out_path(), |
| 713 | constant.BLUEPRINT_CC_JSONFILE_NAME) |
| 714 | mod_name = 'libui' |
| 715 | mod_info = common_util.get_json_dict(cc_path)['modules'][mod_name] |
| 716 | if mod_info: |
| 717 | clion_project_file_gen.CLionProjectFileGenerator( |
| 718 | mod_info).generate_cmakelists_file() |
| 719 | out_dir = os.path.join(common_util.get_android_root_dir(), |
| 720 | common_util.get_android_out_dir(), |
| 721 | constant.RELATIVE_NATIVE_PATH, |
| 722 | mod_info['path'][0]) |
| 723 | content1 = _read_file_content(os.path.join( |
| 724 | out_dir, mod_name, constant.CLION_PROJECT_FILE_NAME)) |
| 725 | cc_file_name = ''.join( |
| 726 | [mod_name, '-', target_arch_variant, '-android']) |
| 727 | cc_file_path = os.path.join( |
| 728 | out_dir, cc_file_name, constant.CLION_PROJECT_FILE_NAME) |
| 729 | content2 = _read_file_content(cc_file_path) |
| 730 | same = True |
| 731 | for lino, (cnt1, cnt2) in enumerate( |
| 732 | zip(content1, content2), start=1): |
| 733 | if _BE_REPLACED in cnt2: |
| 734 | cnt2 = cnt2.replace(_BE_REPLACED, _TO_REPLACE) |
| 735 | if cnt1 != cnt2: |
| 736 | print('Contents {} and {} are different in line:{}.'.format( |
| 737 | cnt1, cnt2, lino)) |
| 738 | same = False |
| 739 | if same: |
| 740 | print('Files {} and {} are the same.'.format( |
| 741 | mod_name, cc_file_name)) |
| 742 | except errors.BuildFailureError: |
| 743 | print('Compare native content failed.') |
| 744 | |
| 745 | |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 746 | def main(argv): |
| 747 | """Main entry. |
| 748 | |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 749 | 1. Create the iml file data of each module in module-info.json and write it |
| 750 | into single_module.json. |
| 751 | 2. Verify every use case of AIDEGen. |
| 752 | 3. Compare all or some iml project files' data to the data recorded in |
| 753 | single_module.json. |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 754 | |
| 755 | Args: |
| 756 | argv: A list of system arguments. |
| 757 | """ |
| 758 | args = _parse_args(argv) |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 759 | common_util.configure_logging(args.verbose) |
bralee | 23789ed | 2020-04-24 19:23:07 +0800 | [diff] [blame] | 760 | os.environ[constant.AIDEGEN_TEST_MODE] = 'true' |
bralee | 50284e3 | 2020-10-26 11:32:32 +0800 | [diff] [blame] | 761 | |
| 762 | if args.make_clean: |
| 763 | _make_clean() |
| 764 | |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 765 | if args.create_sample: |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 766 | _create_some_sample_json_file(args.targets) |
bralee | 1462994 | 2019-07-15 07:02:01 +0800 | [diff] [blame] | 767 | elif args.use_cases_verified: |
| 768 | _verify_aidegen(_VERIFY_COMMANDS_JSON, args.remove_bp_json) |
| 769 | elif args.binary_upload_verified: |
| 770 | _verify_aidegen(_VERIFY_BINARY_JSON, args.remove_bp_json) |
morrislin | 23b618e | 2020-10-22 14:36:51 +0800 | [diff] [blame] | 771 | elif args.binary_presubmit_verified: |
| 772 | _verify_aidegen(_VERIFY_PRESUBMIT_JSON, args.remove_bp_json, True) |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 773 | elif args.test_all_samples: |
| 774 | _test_all_samples_iml() |
bralee | c89ed9f | 2020-01-23 22:26:58 +0800 | [diff] [blame] | 775 | elif args.compare_sample_native: |
| 776 | _compare_sample_native_content() |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 777 | else: |
bralee | 2cb9582 | 2019-05-02 11:33:16 +0800 | [diff] [blame] | 778 | if not args.targets[0]: |
| 779 | _test_some_sample_iml() |
| 780 | else: |
| 781 | _test_some_sample_iml(args.targets) |
bralee | 50284e3 | 2020-10-26 11:32:32 +0800 | [diff] [blame] | 782 | |
bralee | 23789ed | 2020-04-24 19:23:07 +0800 | [diff] [blame] | 783 | del os.environ[constant.AIDEGEN_TEST_MODE] |
bralee | 5b848a7 | 2018-11-09 17:44:56 +0800 | [diff] [blame] | 784 | |
| 785 | |
| 786 | if __name__ == '__main__': |
| 787 | main(sys.argv[1:]) |