Merge "AIDEGen: Refactor project_info.py for using in class MainProjectInfo."
diff --git a/aidegen/aidegen_main.py b/aidegen/aidegen_main.py
index 0eb4530..168b787 100644
--- a/aidegen/aidegen_main.py
+++ b/aidegen/aidegen_main.py
@@ -352,6 +352,30 @@
@common_util.back_to_cwd
+def _adjust_cwd_for_whole_tree_project(args, mod_info):
+ """The wrapper to handle the directory change for whole tree case.
+
+ Args:
+ args: A list of system arguments.
+ mod_info: A instance of atest module_info.
+
+ Returns:
+ A list of ProjectInfo instance
+
+ """
+ targets = _check_whole_android_tree(
+ mod_info, args.targets, args.android_tree)
+ project_info.ProjectInfo.modules_info = module_info.AidegenModuleInfo(
+ force_build=False,
+ module_file=None,
+ atest_module_info=mod_info,
+ projects=targets,
+ verbose=args.verbose,
+ skip_build=args.skip_build)
+
+ return project_info.ProjectInfo.generate_projects(targets)
+
+
def aidegen_main(args):
"""AIDEGen main entry.
@@ -364,16 +388,7 @@
ide_util_obj = _get_ide_util_instance(args)
project_info.ProjectInfo.config = project_config.ProjectConfig(args)
atest_module_info = common_util.get_atest_module_info(args.targets)
- targets = _check_whole_android_tree(
- atest_module_info, args.targets, args.android_tree)
- project_info.ProjectInfo.modules_info = module_info.AidegenModuleInfo(
- force_build=False,
- module_file=None,
- atest_module_info=atest_module_info,
- projects=targets,
- verbose=args.verbose,
- skip_build=args.skip_build)
- projects = project_info.ProjectInfo.generate_projects(targets)
+ projects = _adjust_cwd_for_whole_tree_project(args, atest_module_info)
source_locator.multi_projects_locate_source(projects, args.verbose)
_generate_project_files(projects)
if ide_util_obj:
diff --git a/aidegen/aidegen_main_unittest.py b/aidegen/aidegen_main_unittest.py
index fc6923c..eff2869 100644
--- a/aidegen/aidegen_main_unittest.py
+++ b/aidegen/aidegen_main_unittest.py
@@ -69,13 +69,15 @@
args = aidegen_main._parse_args(['-s'])
self.assertEqual(args.skip_build, True)
+ @mock.patch.object(ide_util.IdeIntelliJ, '_get_preferred_version')
@mock.patch.object(ide_util.IdeUtil, 'is_ide_installed')
- def test_get_ide_util_instance(self, mock_installed):
+ def test_get_ide_util_instance(self, mock_installed, mock_preference):
"""Test _get_ide_util_instance with different conditions."""
target = 'tradefed'
args = aidegen_main._parse_args([target, '-n'])
self.assertEqual(aidegen_main._get_ide_util_instance(args), None)
args = aidegen_main._parse_args([target])
+ mock_preference.return_value = None
self.assertIsInstance(
aidegen_main._get_ide_util_instance(args), ide_util.IdeUtil)
mock_installed.return_value = False
diff --git a/aidegen/lib/aidegen_metrics_unittest.py b/aidegen/lib/aidegen_metrics_unittest.py
index d228956..b4c037a 100644
--- a/aidegen/lib/aidegen_metrics_unittest.py
+++ b/aidegen/lib/aidegen_metrics_unittest.py
@@ -35,28 +35,28 @@
class AidegenMetricsUnittests(unittest.TestCase):
"""Unit tests for aidegen_metrics.py."""
- @mock.patch.object(metrics, 'AtestStartEvent')
- @mock.patch.object(metrics_utils, 'get_start_time')
@mock.patch.object(atest_utils, 'print_data_collection_notice')
- def test_starts_asuite_metrics(self, mock_print_data, mock_get_start_time,
- mock_start_event):
+ def test_starts_asuite_metrics(self, mock_print_data):
"""Test starts_asuite_metrics."""
references = ['nothing']
- aidegen_metrics.starts_asuite_metrics(references)
if not metrics:
+ aidegen_metrics.starts_asuite_metrics(references)
self.assertFalse(mock_print_data.called)
else:
- self.assertTrue(mock_print_data.called)
- self.assertTrue(mock_get_start_time.called)
- self.assertTrue(mock_start_event.called)
+ with mock.patch.object(metrics_utils, 'get_start_time') as mk_get:
+ with mock.patch.object(metrics, 'AtestStartEvent') as mk_start:
+ aidegen_metrics.starts_asuite_metrics(references)
+ self.assertTrue(mock_print_data.called)
+ self.assertTrue(mk_get.called)
+ self.assertTrue(mk_start.called)
- @mock.patch.object(metrics_utils, 'send_exit_event')
- def test_ends_asuite_metrics(self, mock_send_exit_event):
+ def test_ends_asuite_metrics(self):
"""Test ends_asuite_metrics."""
exit_code = constant.EXIT_CODE_NORMAL
- aidegen_metrics.ends_asuite_metrics(exit_code)
if metrics_utils:
- self.assertTrue(mock_send_exit_event.called)
+ with mock.patch.object(metrics_utils, 'send_exit_event') as mk_send:
+ aidegen_metrics.ends_asuite_metrics(exit_code)
+ self.assertTrue(mk_send.called)
if __name__ == '__main__':
diff --git a/aidegen/lib/common_util.py b/aidegen/lib/common_util.py
index 87a7c6c..a3de970 100644
--- a/aidegen/lib/common_util.py
+++ b/aidegen/lib/common_util.py
@@ -287,9 +287,11 @@
"""Determine if the given project path is relative to the module.
The rules:
- 1. If project_relative_path is empty, it's under Android root, return
+ 1. If constant.KEY_PATH not in data, we can't tell if it's a module
+ return False.
+ 2. If project_relative_path is empty, it's under Android root, return
True.
- 2. If module's path equals or starts with project_relative_path return
+ 3. If module's path equals or starts with project_relative_path return
True, otherwise return False.
Args:
@@ -300,12 +302,12 @@
True if it's the given project path is relative to the module, otherwise
False.
"""
- if 'path' not in data:
+ if constant.KEY_PATH not in data:
return False
- path = data['path'][0]
+ path = data[constant.KEY_PATH][0]
if project_relative_path == '':
return True
- if ('class' in data
+ if (constant.KEY_CLASS in data
and (path == project_relative_path
or path.startswith(project_relative_path + os.sep))):
return True
@@ -415,7 +417,7 @@
Android out directory path.
"""
android_root_path = get_android_root_dir()
- android_out_dir = os.environ.get(constants.ANDROID_OUT_DIR)
+ android_out_dir = os.getenv(constants.ANDROID_OUT_DIR)
out_dir_common_base = os.getenv(constant.OUT_DIR_COMMON_BASE_ENV_VAR)
android_out_dir_common_base = (os.path.join(
out_dir_common_base, os.path.basename(android_root_path))
diff --git a/aidegen/lib/common_util_unittest.py b/aidegen/lib/common_util_unittest.py
index 01df761..d59ff34 100644
--- a/aidegen/lib/common_util_unittest.py
+++ b/aidegen/lib/common_util_unittest.py
@@ -164,6 +164,65 @@
mock_log_config.called_with(
level=level, format=log_format, datefmt=datefmt))
+ def test_is_project_path_relative_module(self):
+ """Test is_project_path_relative_module handling."""
+ data = {'class':['APPS']}
+ self.assertFalse(common_util.is_project_path_relative_module(data, ''))
+ data = {'class':['APPS'], 'path':['path_to_a']}
+ self.assertTrue(common_util.is_project_path_relative_module(data, ''))
+ self.assertFalse(
+ common_util.is_project_path_relative_module(data, 'test'))
+ data = {'path':['path_to_a']}
+ self.assertFalse(
+ common_util.is_project_path_relative_module(data, 'test'))
+ self.assertFalse(
+ common_util.is_project_path_relative_module(data, 'path_to_a'))
+ data = {'class':['APPS'], 'path':['test/path_to_a']}
+ self.assertTrue(
+ common_util.is_project_path_relative_module(data, 'test'))
+ self.assertFalse(
+ common_util.is_project_path_relative_module(data, 'tes'))
+
+ @mock.patch.object(common_util, '_check_modules')
+ @mock.patch.object(module_info, 'ModuleInfo')
+ def test_get_atest_module_info(self, mock_modinfo, mock_check_modules):
+ """Test get_atest_module_info handling."""
+ common_util.get_atest_module_info()
+ self.assertEqual(mock_modinfo.call_count, 1)
+ mock_modinfo.reset_mock()
+ mock_check_modules.return_value = False
+ common_util.get_atest_module_info(['nothing'])
+ self.assertEqual(mock_modinfo.call_count, 2)
+
+ @mock.patch('builtins.open', create=True)
+ def test_read_file_content(self, mock_open):
+ """Test read_file_content handling."""
+ expacted_data1 = 'Data1'
+ fileA = 'fileA'
+ mock_open.side_effect = [
+ mock.mock_open(read_data=expacted_data1).return_value
+ ]
+ self.assertEqual(expacted_data1, common_util.read_file_content(fileA))
+ mock_open.assert_called_once_with(fileA)
+
+ @mock.patch('os.getenv')
+ @mock.patch.object(common_util, 'get_android_root_dir')
+ def test_get_android_out_dir(self, mock_get_android_root_dir, mock_getenv):
+ """Test get_android_out_dir handling."""
+ root = 'my/path-to-root/master'
+ default_root = 'out'
+ android_out_root = 'eng_out'
+ mock_get_android_root_dir.return_value = root
+ mock_getenv.side_effect = ['', '']
+ self.assertEqual(default_root, common_util.get_android_out_dir())
+ mock_getenv.side_effect = [android_out_root, '']
+ self.assertEqual(android_out_root, common_util.get_android_out_dir())
+ mock_getenv.side_effect = ['', default_root]
+ self.assertEqual(os.path.join(default_root, os.path.basename(root)),
+ common_util.get_android_out_dir())
+ mock_getenv.side_effect = [android_out_root, default_root]
+ self.assertEqual(android_out_root, common_util.get_android_out_dir())
+
if __name__ == '__main__':
unittest.main()
diff --git a/aidegen/lib/ide_util_unittest.py b/aidegen/lib/ide_util_unittest.py
index 597aab0..ff0f073 100644
--- a/aidegen/lib/ide_util_unittest.py
+++ b/aidegen/lib/ide_util_unittest.py
@@ -32,6 +32,7 @@
# pylint: disable=protected-access
+# pylint: disable-msg=too-many-arguments
class IdeUtilUnittests(unittest.TestCase):
"""Unit tests for ide_util.py."""
@@ -118,8 +119,10 @@
ide_util._get_ide(None, 'j', False, is_mac=False)
self.assertTrue(mock_linux.called)
- def test_get_mac_and_linux_ide(self):
+ @mock.patch.object(ide_util.IdeIntelliJ, '_get_preferred_version')
+ def test_get_mac_and_linux_ide(self, mock_preference):
"""Test if _get_mac_ide and _get_linux_ide return correct IDE class."""
+ mock_preference.return_value = None
self.assertIsInstance(ide_util._get_mac_ide(), ide_util.IdeMacIntelliJ)
self.assertIsInstance(ide_util._get_mac_ide(None, 's'),
ide_util.IdeMacStudio)
@@ -145,13 +148,16 @@
ide_util.IdeMacIntelliJ('some_path')
self.assertTrue(mock_input.called)
+ @mock.patch.object(ide_util.IdeIntelliJ, '_get_preferred_version')
@mock.patch.object(sdk_config.SDKConfig, '_android_sdk_exists')
@mock.patch.object(sdk_config.SDKConfig, '_target_jdk_exists')
@mock.patch.object(ide_util.IdeIntelliJ, '_get_config_root_paths')
@mock.patch.object(ide_util.IdeBase, 'apply_optional_config')
- def test_config_ide(self, mock_config, mock_paths, mock_jdk, mock_sdk):
+ def test_config_ide(self, mock_config, mock_paths, mock_jdk, mock_sdk,
+ mock_preference):
"""Test IDEA, IdeUtil.config_ide won't call base none implement api."""
# Mock SDkConfig flow to not to generate real jdk config file.
+ mock_preference.return_value = None
mock_jdk.return_value = True
mock_sdk.return_value = True
test_path = os.path.join(tempfile.mkdtemp())
@@ -173,9 +179,9 @@
"""Test to get unique config path for linux IDEA case."""
if (not android_dev_os.AndroidDevOS.MAC ==
android_dev_os.AndroidDevOS.get_os_type()):
- mock_path.return_value = '/opt/intelliJ-ce-2018.3/bin/idea.sh'
- mock_path_2.return_value = '/opt/intelliJ-ce-2018.3/bin/idea.sh'
- ide_obj = ide_util.IdeLinuxIntelliJ()
+ mock_path.return_value = '/opt/intellij-ce-2018.3/bin/idea.sh'
+ mock_path_2.return_value = '/opt/intellij-ce-2018.3/bin/idea.sh'
+ ide_obj = ide_util.IdeLinuxIntelliJ('default_path')
self.assertEqual(1, len(ide_obj._get_config_root_paths()))
else:
self.assertTrue((android_dev_os.AndroidDevOS.MAC ==
@@ -244,7 +250,7 @@
original_path = 'intellij-ce-2019.1/bin/idea.sh'
mock_isfile.return_value = True
mock_realpath.return_value = original_path
- ide_obj = ide_util.IdeLinuxIntelliJ()
+ ide_obj = ide_util.IdeLinuxIntelliJ('default_path')
merged_version = ide_obj._merge_symbolic_version(
[symbolic_path, original_path])
self.assertEqual(
diff --git a/aidegen/lib/module_info_util.py b/aidegen/lib/module_info_util.py
index 794afa7..47fd8fd 100644
--- a/aidegen/lib/module_info_util.py
+++ b/aidegen/lib/module_info_util.py
@@ -29,13 +29,15 @@
import json
import logging
import os
-import subprocess
import sys
from aidegen import constant
from aidegen.lib import common_util
from aidegen.lib import errors
+from atest import atest_utils
+from atest import constants
+
_BLUEPRINT_JSONFILE_NAME = 'module_bp_java_deps.json'
_MERGE_NEEDED_ITEMS = [
constant.KEY_CLASS,
@@ -55,8 +57,9 @@
_LAUNCH_PROJECT_QUERY = (
'There exists an IntelliJ project file: %s. Do you want '
'to launch it (yes/No)?')
-_GENERATE_JSON_COMMAND = ('SOONG_COLLECT_JAVA_DEPS=false make nothing -C {DIR};'
- 'SOONG_COLLECT_JAVA_DEPS=true make nothing -C {DIR}')
+
+_BUILD_BP_JSON_ENV_OFF = {'SOONG_COLLECT_JAVA_DEPS': 'false'}
+_BUILD_BP_JSON_ENV_ON = constants.ATEST_BUILD_ENV
@common_util.time_logged
@@ -84,32 +87,29 @@
Returns:
A merged dictionary from module-info.json and module_bp_java_deps.json.
"""
- main_project = projects[0] if projects else None
- cmd = [_GENERATE_JSON_COMMAND.format(
- DIR=common_util.get_android_root_dir())]
- _build_target(module_info, cmd, main_project, verbose, skip_build)
+ json_path = common_util.get_blueprint_json_path()
+ if not os.path.isfile(json_path):
+ main_project = projects[0] if projects else None
+ _build_bp_info(module_info, main_project, verbose, skip_build)
bp_dict = _get_soong_build_json_dict()
return _merge_dict(module_info.name_to_module_info, bp_dict)
-def _build_target(module_info, cmd, main_project=None, verbose=False,
- skip_build=False):
+def _build_bp_info(module_info, main_project=None, verbose=False,
+ skip_build=False):
"""Make nothing to generate module_bp_java_deps.json.
- We build without environment setting SOONG_COLLECT_JAVA_DEPS and then build
- with environment setting SOONG_COLLECT_JAVA_DEPS. In this way we can trigger
- the process of collecting dependencies and generating
- module_bp_java_deps.json.
+ Using atest build method with set env config SOONG_COLLECT_JAVA_DEPS=true to
+ build the target nothing. By this way to trigger the process of collecting
+ dependencies and generating module_bp_java_deps.json.
Args:
module_info: A ModuleInfo instance contains data of module-info.json.
- cmd: A string list, build command.
main_project: The main project name.
verbose: A boolean, if true displays full build output.
skip_build: A boolean, if true, skip building if
get_blueprint_json_path() file exists, otherwise
build it.
-
Build results:
1. Build successfully return.
2. Build failed:
@@ -127,15 +127,18 @@
common_util.get_blueprint_json_path())
return
original_json_mtime = os.path.getmtime(json_path)
- try:
- if verbose:
- full_env_vars = os.environ.copy()
- subprocess.check_call(
- cmd, stderr=subprocess.STDOUT, env=full_env_vars, shell=True)
- else:
- subprocess.check_call(cmd, shell=True)
- logging.info('Build successfully: %s.', cmd)
- except subprocess.CalledProcessError:
+
+ logging.warning('\nUse atest build method to generate blueprint json.')
+ # Force build system to always generate the blueprint json file by setting
+ # SOONG_COLLECT_JAVA_DEPS to false, then true.
+ build_with_off_cmd = atest_utils.build(['nothing'], verbose,
+ _BUILD_BP_JSON_ENV_OFF)
+ build_with_on_cmd = atest_utils.build(['nothing'], verbose,
+ _BUILD_BP_JSON_ENV_ON)
+
+ if build_with_off_cmd and build_with_on_cmd:
+ logging.info('\nGenerate blueprint json successfully.')
+ else:
if not _is_new_json_file_generated(json_path, original_json_mtime):
if os.path.isfile(json_path):
message = ('Generate new {0} failed, AIDEGen will proceed and '
@@ -180,7 +183,7 @@
project_file = glob.glob(
os.path.join(main_project_path, _INTELLIJ_PROJECT_FILE_EXT))
if project_file:
- query = (_LAUNCH_PROJECT_QUERY) % project_file[0]
+ query = _LAUNCH_PROJECT_QUERY % project_file[0]
input_data = input(query)
if not input_data.lower() in ['yes', 'y']:
sys.exit(1)
@@ -251,7 +254,7 @@
"""
merged_dict = _copy_needed_items_from(mk_dict)
for module in bp_dict.keys():
- if not module in merged_dict.keys():
+ if module not in merged_dict.keys():
merged_dict[module] = dict()
_merge_module_keys(merged_dict[module], bp_dict[module])
return merged_dict
diff --git a/aidegen/lib/module_info_util_unittest.py b/aidegen/lib/module_info_util_unittest.py
index c604968..24260e1 100644
--- a/aidegen/lib/module_info_util_unittest.py
+++ b/aidegen/lib/module_info_util_unittest.py
@@ -17,16 +17,17 @@
"""Unittests for module_info_utils."""
import copy
-import os
-import subprocess
+import os.path
import unittest
from unittest import mock
from aidegen import unittest_constants
+from aidegen.lib import common_util
from aidegen.lib import errors
from aidegen.lib import module_info_util
-from atest import module_info
+from atest import atest_utils
+from atest import module_info
_TEST_CLASS_DICT = {'class': ['JAVA_LIBRARIES']}
_TEST_SRCS_BAR_DICT = {'srcs': ['Bar']}
@@ -130,26 +131,24 @@
module_info_util._copy_needed_items_from(
_TEST_MODULE_A_DICT_HAS_NONEED_ITEMS))
- @mock.patch('subprocess.check_call')
- @mock.patch('os.environ.copy')
- def test_build_target_normal(self, mock_copy, mock_check_call):
+ @mock.patch.object(os.path, 'getmtime')
+ @mock.patch.object(atest_utils, 'build')
+ @mock.patch('os.path.isfile')
+ def test_build_bp_info_normal(self, mock_isfile, mock_build, mock_time):
"""Test _build_target with verbose true and false."""
- mock_copy.return_value = ''
+ mock_isfile.return_value = True
amodule_info = module_info.ModuleInfo()
- cmd = [module_info_util._GENERATE_JSON_COMMAND]
- module_info_util._build_target(amodule_info, cmd,
- unittest_constants.TEST_MODULE, True)
- self.assertTrue(mock_copy.called)
- self.assertTrue(mock_check_call.called)
- mock_check_call.assert_called_with(
- cmd,
- stderr=subprocess.STDOUT,
- env=mock_copy.return_value,
- shell=True)
- module_info_util._build_target(amodule_info, cmd,
- unittest_constants.TEST_MODULE, False)
- self.assertTrue(mock_check_call.called)
- mock_check_call.assert_called_with(cmd, shell=True)
+ skip = True
+ mock_build.return_value = True
+ module_info_util._build_bp_info(amodule_info, unittest_constants.
+ TEST_MODULE, False, skip)
+ self.assertFalse(mock_build.called)
+ skip = False
+ mock_time.return_value = float()
+ module_info_util._build_bp_info(amodule_info, unittest_constants.
+ TEST_MODULE, False, skip)
+ self.assertTrue(mock_time.called)
+ self.assertEqual(mock_build.call_count, 2)
@mock.patch('os.path.getmtime')
@mock.patch('os.path.isfile')
@@ -199,30 +198,24 @@
module_info_util._get_soong_build_json_dict()
@mock.patch('aidegen.lib.module_info_util._build_failed_handle')
+ @mock.patch.object(common_util, 'get_related_paths')
@mock.patch('aidegen.lib.module_info_util._is_new_json_file_generated')
- @mock.patch('subprocess.check_call')
- def test_build_target(self, mock_call, mock_new, mock_handle):
- """Test _build_target with different arguments."""
- cmd = [module_info_util._GENERATE_JSON_COMMAND]
- main_project = ''
+ @mock.patch.object(atest_utils, 'build')
+ def test_build_bp_info(self, mock_build, mock_new, mock_path, mock_handle):
+ """Test _build_bp_info with different arguments."""
+ main_project = 'Settings'
amodule_info = {}
verbose = False
- module_info_util._build_target(amodule_info, cmd, main_project, verbose)
- mock_call.assert_called_with(cmd, shell=True)
- verbose = True
- full_env_vars = os.environ.copy()
- module_info_util._build_target(amodule_info, cmd, main_project, verbose)
- mock_call.assert_called_with(cmd, stderr=subprocess.STDOUT,
- env=full_env_vars, shell=True)
- mock_call.side_effect = subprocess.CalledProcessError(1, '')
+ mock_build.return_value = False
mock_new.return_value = False
- module_info_util._build_target(amodule_info, cmd, main_project, verbose)
+ module_info_util._build_bp_info(amodule_info, main_project, verbose)
self.assertTrue(mock_new.called)
self.assertFalse(mock_handle.called)
mock_new.return_value = True
- module_info_util._build_target(amodule_info, cmd, main_project, verbose)
+ mock_path.return_value = None, 'packages/apps/Settings'
+ module_info_util._build_bp_info(amodule_info, main_project, verbose)
self.assertTrue(mock_new.called)
- self.assertFalse(mock_handle.called)
+ self.assertTrue(mock_handle.called)
if __name__ == '__main__':