Snap for 6573023 from 74afd2054b59e2ed53c4bdd9fd8982b3e300f057 to r-keystone-qcom-release
Change-Id: I513761c671ec9fed134b284e5db88cf973957a4e
diff --git a/aidegen/constant.py b/aidegen/constant.py
index 83a6e39..a52288c 100644
--- a/aidegen/constant.py
+++ b/aidegen/constant.py
@@ -134,6 +134,17 @@
# Constants for default modules.
FRAMEWORK_ALL = 'framework-all'
CORE_ALL = 'core-all'
+FRAMEWORK_SRCJARS = 'framework_srcjars'
+
+# Constants for module's path.
+FRAMEWORK_PATH = 'frameworks/base'
+LIBCORE_PATH = 'libcore'
# Constants for regular expression
RE_INSIDE_PATH_CHECK = r'^{}($|/.+)'
+
+# Constants for Git
+GIT_FOLDER_NAME = '.git'
+
+# Constants for Idea
+IDEA_FOLDER = '.idea'
diff --git a/aidegen/idea/iml_unittest.py b/aidegen/idea/iml_unittest.py
index 0aa64e9..c41ea81 100644
--- a/aidegen/idea/iml_unittest.py
+++ b/aidegen/idea/iml_unittest.py
@@ -25,6 +25,7 @@
from aidegen import templates
from aidegen.lib import common_util
from aidegen.idea import iml
+from atest import module_info
# pylint: disable=protected-access
@@ -163,6 +164,45 @@
self.iml._generate_facet()
self.assertEqual(self.iml._facet, templates.FACET)
+ def test_get_uniq_iml_name(self):
+ """Test the unique name cache mechanism.
+
+ By using the path data in module info json as input, if the count of
+ name data set is the same as sub folder path count, then it means
+ there's no duplicated name, the test PASS.
+ """
+ # Add following test path
+ test_paths = {
+ 'cts/tests/tests/app',
+ 'cts/tests/app',
+ 'cts/tests/app/app1/../app',
+ 'cts/tests/app/app2/../app',
+ 'cts/tests/app/app3/../app',
+ 'frameworks/base/tests/xxxxxxxxxxxx/base',
+ 'frameworks/base',
+ 'external/xxxxx-xxx/robolectric',
+ 'external/robolectric',
+ }
+ mod_info = module_info.ModuleInfo()
+ test_paths.update(mod_info._get_path_to_module_info(
+ mod_info.name_to_module_info).keys())
+ print('\n{} {}.'.format('Test_paths length:', len(test_paths)))
+
+ path_list = []
+ for path in test_paths:
+ path_list.append(path)
+ print('{} {}.'.format('path list with length:', len(path_list)))
+
+ names = [iml.IMLGenerator.get_unique_iml_name(f)
+ for f in path_list]
+ print('{} {}.'.format('Names list with length:', len(names)))
+ self.assertEqual(len(names), len(path_list))
+ dic = {}
+ for i, path in enumerate(path_list):
+ dic[names[i]] = path
+ print('{} {}.'.format('The size of name set is:', len(dic)))
+ self.assertEqual(len(dic), len(path_list))
+
if __name__ == '__main__':
unittest.main()
diff --git a/aidegen/idea/xml_gen.py b/aidegen/idea/xml_gen.py
new file mode 100644
index 0000000..5bb886c
--- /dev/null
+++ b/aidegen/idea/xml_gen.py
@@ -0,0 +1,156 @@
+#!/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.
+
+"""Creates the xml files.
+
+Usage example:
+ vcs = XMLGenerator(module_path, 'vcs.xml')
+ if not vcs.xml_obj:
+ # Create the file directly.
+ common_util.file_generate(vcs.xml_abspath, xml_content)
+ else:
+ # Add/remove elements to vcs.xml_obj by the methods of
+ # ElementTree.Element object.
+ vcs.xml_obj.append()
+ vcs.xml_obj.makeelement()
+ vcs.xml_obj.remove()
+ # Update the XML content.
+ vcs.create_xml()
+"""
+
+from __future__ import absolute_import
+
+import os
+
+from xml.etree import ElementTree
+
+from aidegen import constant
+from aidegen import templates
+from aidegen.lib import aidegen_metrics
+from aidegen.lib import common_util
+from aidegen.lib import xml_util
+
+_GIT_PATH = ' <mapping directory="{GIT_DIR}" vcs="Git" />'
+_IGNORE_PATH = ' <path value="{GIT_DIR}" />'
+
+
+class XMLGenerator:
+ """Creates the xml file.
+
+ Attributes:
+ _xml_abspath: A string of the XML's absolute path.
+ _xml_obj: An ElementTree object.
+ """
+
+ def __init__(self, module_abspath, xml_name):
+ """Initializes XMLGenerator.
+
+ Args:
+ module_abspath: A string of the module's absolute path.
+ xml_name: A string of the xml file name.
+ """
+ self._xml_abspath = os.path.join(module_abspath, constant.IDEA_FOLDER,
+ xml_name)
+ self._xml_obj = None
+ self.parse()
+
+ def parse(self):
+ """Parses the XML file to an ElementTree object."""
+ if os.path.exists(self._xml_abspath):
+ self._xml_obj = xml_util.parse_xml(self._xml_abspath)
+
+ @property
+ def xml_path(self):
+ """Gets the xml absolute path."""
+ return self._xml_abspath
+
+ @property
+ def xml_obj(self):
+ """Gets the xml object."""
+ return self._xml_obj
+
+ def find_elements_by_name(self, element_type, name):
+ """Finds the target elements by name attribute.
+
+ Args:
+ element_type: A string of element's type.
+ name: A string of element's name.
+
+ Return:
+ List: ElementTree's element objects.
+ """
+ return [e for e in self._xml_obj.findall(element_type)
+ if e.get('name') == name]
+
+ @staticmethod
+ def append_node(parent, node_str):
+ """Appends a node string under the parent element.
+
+ Args:
+ parent: An element object, the new node's parent.
+ node_str: A string, the new node's content.
+ """
+ try:
+ parent.append(ElementTree.fromstring(node_str))
+ except ElementTree.ParseError as xml_err:
+ aidegen_metrics.send_exception_metrics(
+ exit_code=constant.XML_PARSING_FAILURE, stack_trace=xml_err,
+ log=node_str, err_msg='')
+
+ def create_xml(self):
+ """Creates the xml file."""
+ common_util.file_generate(self._xml_abspath, common_util.to_pretty_xml(
+ self._xml_obj.getroot()))
+
+
+def gen_vcs_xml(module_path, git_paths):
+ """Writes the git path into the .idea/vcs.xml.
+
+ For main module, the vcs.xml should include all modules' git path.
+ For the whole AOSP case, ignore creating the vcs.xml. Instead, add the
+ ignored Git paths in the workspace.xml.
+
+ Args:
+ module_path: A string, the absolute path of the module.
+ git_paths: A list of git paths.
+ """
+ git_mappings = [_GIT_PATH.format(GIT_DIR=p) for p in git_paths]
+ vcs = XMLGenerator(module_path, 'vcs.xml')
+ if module_path != common_util.get_android_root_dir() or not vcs.xml_obj:
+ common_util.file_generate(vcs.xml_path, templates.XML_VCS.format(
+ GIT_MAPPINGS='\n'.join(git_mappings)))
+
+
+def write_ignore_git_dirs_file(module_path, ignore_paths):
+ """Write the ignored git paths in the .idea/workspace.xml.
+
+ Args:
+ module_path: A string, the absolute path of the module.
+ ignore_paths: A list of git paths.
+ """
+ ignores = [_IGNORE_PATH.format(GIT_DIR=p) for p in ignore_paths]
+ workspace = XMLGenerator(module_path, 'workspace.xml')
+ if not workspace.xml_obj:
+ common_util.file_generate(workspace.xml_path,
+ templates.XML_WORKSPACE.format(
+ GITS=''.join(ignores)))
+ return
+ for conf in workspace.find_elements_by_name('component',
+ 'VcsManagerConfiguration'):
+ workspace.xml_obj.getroot().remove(conf)
+ workspace.append_node(workspace.xml_obj.getroot(),
+ templates.IGNORED_GITS.format(GITS=''.join(ignores)))
+ workspace.create_xml()
diff --git a/aidegen/idea/xml_gen_unittest.py b/aidegen/idea/xml_gen_unittest.py
new file mode 100644
index 0000000..b6a2356
--- /dev/null
+++ b/aidegen/idea/xml_gen_unittest.py
@@ -0,0 +1,124 @@
+#!/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.
+
+"""Unittests for XMLGenerator."""
+
+import os
+import shutil
+import tempfile
+import unittest
+from unittest import mock
+
+from xml.etree import ElementTree
+
+from aidegen.lib import common_util
+from aidegen.idea import xml_gen
+
+
+# pylint: disable=protected-access
+class XMLGenUnittests(unittest.TestCase):
+ """Unit tests for XMLGenerator class."""
+
+ _TEST_DIR = None
+ _XML_NAME = 'test.xml'
+ _DEFAULT_XML = """<?xml version="1.0" encoding="UTF-8"?>
+<project version="4"></project>
+"""
+ _IGNORE_GIT_XML = """<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="VcsManagerConfiguration">
+ <ignored-roots><path value="/b" /></ignored-roots>
+ </component>
+</project>
+"""
+
+ def setUp(self):
+ """Prepare the testdata related path."""
+ XMLGenUnittests._TEST_DIR = tempfile.mkdtemp()
+ self.xml = xml_gen.XMLGenerator(self._TEST_DIR, self._XML_NAME)
+ common_util.file_generate(self.xml.xml_path, self._DEFAULT_XML)
+ self.xml.parse()
+
+ def tearDown(self):
+ """Clear the testdata related path."""
+ shutil.rmtree(self._TEST_DIR)
+
+ def test_find_elements_by_name(self):
+ """Test find_elements_by_name."""
+ node = self.xml.xml_obj.getroot()
+ ElementTree.SubElement(node, 'a', attrib={'name': 'b'})
+ elements = self.xml.find_elements_by_name('a', 'b')
+ self.assertEqual(len(elements), 1)
+
+ def test_append_node(self):
+ """Test append_node."""
+ node = self.xml.xml_obj.getroot()
+ self.xml.append_node(node, '<a />')
+ self.assertEqual(len(node.findall('a')), 1)
+
+ @mock.patch.object(common_util, 'to_pretty_xml')
+ @mock.patch.object(common_util, 'file_generate')
+ def test_create_xml(self, mock_file_gen, mock_pretty_xml):
+ """Test create_xml."""
+ self.xml.create_xml()
+ self.assertTrue(mock_file_gen.called)
+ self.assertTrue(mock_pretty_xml.called)
+
+ @mock.patch.object(common_util, 'file_generate')
+ @mock.patch.object(common_util, 'get_android_root_dir')
+ @mock.patch.object(xml_gen, 'XMLGenerator')
+ def test_gen_vcs_xml(self, mock_xml_gen, mock_root_dir, mock_file_gen):
+ """Test gen_vcs_xml."""
+ mock_gen_xml = mock.Mock()
+ mock_xml_gen.return_value = mock_gen_xml
+ mock_xml_gen.xml_obj = None
+ mock_root_dir.return_value = self._TEST_DIR
+ xml_gen.gen_vcs_xml(self._TEST_DIR, [])
+ self.assertFalse(mock_file_gen.called)
+ mock_root_dir.return_value = '/a'
+ xml_gen.gen_vcs_xml(self._TEST_DIR, ['/a'])
+ self.assertTrue(mock_file_gen.called)
+
+ @mock.patch.object(os.path, 'exists')
+ @mock.patch.object(common_util, 'file_generate')
+ @mock.patch.object(xml_gen.XMLGenerator, 'create_xml')
+ @mock.patch.object(xml_gen, 'XMLGenerator')
+ def test_write_ignore_git_dirs_file(self, mock_xml_gen, mock_create_xml,
+ mock_file_gen, mock_exists):
+ """Test write_ignore_git_dirs_file."""
+ mock_gen_xml = mock.Mock()
+ mock_xml_gen.return_value = mock_gen_xml
+ mock_gen_xml.xml_obj = False
+ mock_exists.return_value = False
+ xml_gen.write_ignore_git_dirs_file(self._TEST_DIR, ['/a'])
+ self.assertTrue(mock_file_gen.called)
+ mock_exists.return_value = True
+ mock_xml_gen.return_value = self.xml
+ xml_gen.write_ignore_git_dirs_file(self._TEST_DIR, ['/a'])
+ ignore_root = self.xml.xml_obj.find('component').find('ignored-roots')
+ self.assertEqual(ignore_root.find('path').attrib['value'], '/a')
+ common_util.file_generate(os.path.join(self._TEST_DIR, 'workspace.xml'),
+ self._IGNORE_GIT_XML)
+ self.xml = xml_gen.XMLGenerator(self._TEST_DIR, 'workspace.xml')
+ mock_xml_gen.return_value = self.xml
+ xml_gen.write_ignore_git_dirs_file(self._TEST_DIR, ['/a/b'])
+ ignore_root = self.xml.xml_obj.find('component').find('ignored-roots')
+ self.assertEqual(ignore_root.find('path').attrib['value'], '/a/b')
+ self.assertTrue(mock_create_xml.called)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/aidegen/lib/common_util.py b/aidegen/lib/common_util.py
index 6c7ba8c..685ca10 100644
--- a/aidegen/lib/common_util.py
+++ b/aidegen/lib/common_util.py
@@ -706,3 +706,23 @@
else False.
"""
return str_bool and str_bool.lower() in ('true', 't', '1')
+
+
+def find_git_root(relpath):
+ """Finds the parent directory which has a .git folder from the relpath.
+
+ Args:
+ relpath: A string of relative path.
+
+ Returns:
+ A string of the absolute path which contains a .git, otherwise, none.
+ """
+ dir_list = relpath.split(os.sep)
+ for i in range(len(dir_list), 0, -1):
+ real_path = os.path.join(get_android_root_dir(),
+ os.sep.join(dir_list[:i]),
+ constant.GIT_FOLDER_NAME)
+ if os.path.exists(real_path):
+ return os.path.dirname(real_path)
+ logging.warning('%s can\'t find its .git folder.', relpath)
+ return None
diff --git a/aidegen/lib/common_util_unittest.py b/aidegen/lib/common_util_unittest.py
index f45261d..dc8d392 100644
--- a/aidegen/lib/common_util_unittest.py
+++ b/aidegen/lib/common_util_unittest.py
@@ -378,6 +378,16 @@
self.assertFalse(common_util.to_boolean('0'))
self.assertFalse(common_util.to_boolean(''))
+ @mock.patch.object(os.path, 'exists')
+ @mock.patch.object(common_util, 'get_android_root_dir')
+ def test_find_git_root(self, mock_get_root, mock_exist):
+ """Test find_git_root."""
+ mock_get_root.return_value = '/a/b'
+ mock_exist.return_value = True
+ self.assertEqual(common_util.find_git_root('c/d'), '/a/b/c/d')
+ mock_exist.return_value = False
+ self.assertEqual(common_util.find_git_root('c/d'), None)
+
# pylint: disable=unused-argument
def parse_rule(self, name, text):
diff --git a/aidegen/lib/project_file_gen.py b/aidegen/lib/project_file_gen.py
index 7d67f0c..62ad140 100644
--- a/aidegen/lib/project_file_gen.py
+++ b/aidegen/lib/project_file_gen.py
@@ -23,51 +23,26 @@
import logging
import os
-import pathlib
import shutil
from aidegen import constant
from aidegen import templates
from aidegen.idea import iml
+from aidegen.idea import xml_gen
from aidegen.lib import common_util
from aidegen.lib import config
from aidegen.lib import project_config
from aidegen.project import source_splitter
# FACET_SECTION is a part of iml, which defines the framework of the project.
-_FACET_SECTION = '''\
- <facet type="android" name="Android">
- <configuration />
- </facet>'''
-_SOURCE_FOLDER = (' <sourceFolder url='
- '"file://%s" isTestSource="%s" />\n')
-_CONTENT_URL = ' <content url="file://%s">\n'
-_END_CONTENT = ' </content>\n'
-_SRCJAR_URL = ('%s<content url="jar://{SRCJAR}!/">\n'
- '%s<sourceFolder url="jar://{SRCJAR}!/" isTestSource="False" />'
- '\n%s</content>') % (' ' * 8, ' ' * 12, ' ' * 8)
-_ORDER_ENTRY = (' <orderEntry type="module-library" exported="">'
- '<library><CLASSES><root url="jar://%s!/" /></CLASSES>'
- '<JAVADOC /><SOURCES /></library></orderEntry>\n')
-_MODULE_ORDER_ENTRY = (' <orderEntry type="module" '
- 'module-name="%s" />')
_MODULE_SECTION = (' <module fileurl="file:///$PROJECT_DIR$/%s.iml"'
' filepath="$PROJECT_DIR$/%s.iml" />')
_SUB_MODULES_SECTION = (' <module fileurl="file:///{IML}" '
'filepath="{IML}" />')
-_VCS_SECTION = ' <mapping directory="%s" vcs="Git" />'
-_FACET_TOKEN = '@FACETS@'
-_SOURCE_TOKEN = '@SOURCES@'
-_SRCJAR_TOKEN = '@SRCJAR@'
-_MODULE_DEP_TOKEN = '@MODULE_DEPENDENCIES@'
_MODULE_TOKEN = '@MODULES@'
_ENABLE_DEBUGGER_MODULE_TOKEN = '@ENABLE_DEBUGGER_MODULE@'
-_VCS_TOKEN = '@VCS@'
-_JAVA_FILE_PATTERN = '%s/*.java'
_IDEA_FOLDER = '.idea'
_MODULES_XML = 'modules.xml'
-_VCS_XML = 'vcs.xml'
-_DEPENDENCIES_IML = 'dependencies.iml'
_COPYRIGHT_FOLDER = 'copyright'
_CODE_STYLE_FOLDER = 'codeStyles'
_APACHE_2_XML = 'Apache_2.xml'
@@ -78,10 +53,6 @@
_COMPILE_XML = 'compiler.xml'
_MISC_XML = 'misc.xml'
_CONFIG_JSON = 'config.json'
-_ANDROID_MANIFEST = 'AndroidManifest.xml'
-_IML_EXTENSION = '.iml'
-_FRAMEWORK_JAR = os.sep + 'framework.jar'
-_HIGH_PRIORITY_JARS = [_FRAMEWORK_JAR]
_GIT_FOLDER_NAME = '.git'
# Support gitignore by symbolic link to aidegen/data/gitignore_template.
_GITIGNORE_FILE_NAME = '.gitignore'
@@ -112,20 +83,6 @@
"""
self.project_info = project_info
- def _generate_source_section(self, sect_name, is_test):
- """Generate specific section of the project file.
-
- Args:
- sect_name: The section name, e.g. source_folder_path is for source
- folder section.
- is_test: A boolean, True if it's the test section else False.
-
- Returns:
- A dict contains the source folder's contents of project file.
- """
- return dict.fromkeys(
- list(self.project_info.source_path[sect_name]), is_test)
-
def generate_intellij_project_file(self, iml_path_list=None):
"""Generates IntelliJ project file.
@@ -135,7 +92,6 @@
iml_path_list: An optional list of submodule's iml paths, the
default value is None.
"""
- self.project_info.git_path = self._get_project_git_path()
if self.project_info.is_main_project:
self._generate_modules_xml(iml_path_list)
self._copy_constant_project_files()
@@ -204,224 +160,6 @@
common_util.file_generate(
os.path.join(idea_dir, _CONFIG_JSON), lunch_target)
- def _handle_facet(self, content):
- """Handle facet part of iml.
-
- If the module is an Android app, which contains AndroidManifest.xml, it
- should have a facet of android, otherwise we don't need facet in iml.
-
- Args:
- content: String content of iml.
-
- Returns:
- String: Content with facet handled.
- """
- facet = ''
- facet_path = self.project_info.project_absolute_path
- if os.path.isfile(os.path.join(facet_path, constant.ANDROID_MANIFEST)):
- facet = _FACET_SECTION
- return content.replace(_FACET_TOKEN, facet)
-
- @staticmethod
- def _handle_module_dependency(content, jar_dependencies):
- """Handle module dependency part of iml.
-
- Args:
- content: String content of iml.
- jar_dependencies: List of the jar path.
-
- Returns:
- String: Content with module dependency handled.
- """
- root_path = common_util.get_android_root_dir()
- module_library = ''
- dependencies = []
- # Reorder deps in the iml generated by IntelliJ by inserting priority
- # jars.
- for jar_path in jar_dependencies:
- if any((jar_path.endswith(high_priority_jar))
- for high_priority_jar in _HIGH_PRIORITY_JARS):
- module_library += _ORDER_ENTRY % os.path.join(
- root_path, jar_path)
- else:
- dependencies.append(jar_path)
-
- # IntelliJ indexes jars as dependencies from iml by the ascending order.
- # Without sorting, the order of jar list changes everytime. Sort the jar
- # list to keep the jar dependencies in consistency. It also can help us
- # to discover potential issues like duplicated classes.
- for jar_path in sorted(dependencies):
- module_library += _ORDER_ENTRY % os.path.join(root_path, jar_path)
- return content.replace(_MODULE_DEP_TOKEN, module_library)
-
- def _is_project_relative_source(self, source):
- """Check if the relative path of a file is a source relative path.
-
- Check if the file path starts with the relative path or the relative is
- an Android source tree root path.
-
- Args:
- source: The file path to be checked.
-
- Returns:
- True if the file is a source relative path, otherwise False.
- """
- relative_path = self.project_info.project_relative_path
- abs_path = common_util.get_abs_path(relative_path)
- if common_util.is_android_root(abs_path):
- return True
- if common_util.is_source_under_relative_path(source, relative_path):
- return True
- return False
-
- def _handle_source_folder(self, content, source_dict, is_module):
- """Handle source folder part of iml.
-
- It would make the source folder group by content.
- e.g.
- <content url="file://$MODULE_DIR$/a">
- <sourceFolder url="file://$MODULE_DIR$/a/b" isTestSource="False"/>
- <sourceFolder url="file://$MODULE_DIR$/a/test" isTestSource="True"/>
- <sourceFolder url="file://$MODULE_DIR$/a/d/e" isTestSource="False"/>
- </content>
-
- Args:
- content: String content of iml.
- source_dict: A dictionary of sources path with a flag to identify
- the path is test or source folder in IntelliJ.
- e.g.
- {'path_a': True, 'path_b': False}
- is_module: True if it is module iml, otherwise it is dependencies
- iml.
-
- Returns:
- String: Content with source folder handled.
- """
- root_path = common_util.get_android_root_dir()
- relative_path = self.project_info.project_relative_path
-
- src_builder = []
- if is_module:
- # Set the content url to module's path since it's the iml of target
- # project which only has it's sub-folders in source_list.
- src_builder.append(
- _CONTENT_URL % os.path.join(root_path, relative_path))
- for path, is_test_flag in sorted(source_dict.items()):
- if self._is_project_relative_source(path):
- src_builder.append(_SOURCE_FOLDER % (os.path.join(
- root_path, path), is_test_flag))
- # If relative_path empty, it is Android root. When handling root
- # module, we add the exclude folders to speed up indexing time.
- if not relative_path:
- src_builder.extend(
- source_splitter.get_exclude_content(root_path))
- excludes = project_config.ProjectConfig.get_instance().exclude_paths
- if excludes:
- src_builder.extend(
- source_splitter.get_exclude_content(root_path, excludes))
- src_builder.append(_END_CONTENT)
- else:
- for path, is_test_flag in sorted(source_dict.items()):
- path = os.path.join(root_path, path)
- src_builder.append(_CONTENT_URL % path)
- src_builder.append(_SOURCE_FOLDER % (path, is_test_flag))
- src_builder.append(_END_CONTENT)
- return content.replace(_SOURCE_TOKEN, ''.join(src_builder))
-
- @staticmethod
- def _handle_srcjar_folder(content, srcjar_paths=None):
- """Handle the aapt2.srcjar and R.jar content for iml.
-
- Example for setting the aapt2.srcjar or R.jar as a source folder in
- IntelliJ.
- e.g.
- <content url="jar://$MODULE_DIR$/aapt2.srcjar!/">
- <sourceFolder url="jar://$MODULE_DIR$/aapt2.srcjar!/"
- isTestSource="False"/>
- </content>
- <content url="jar://$MODULE_DIR$/R.jar!/">
- <sourceFolder url="jar://$MODULE_DIR$/R.jar!/"
- isTestSource="False"/>
- </content>
-
- Args:
- content: String content of iml.
- srcjar_paths: A set of srcjar paths, default value is None.
-
- Returns:
- String: Content with srcjar folder handled.
- """
- srcjar_urls = []
- if srcjar_paths:
- for srcjar_dir in sorted(srcjar_paths):
- srcjar_urls.append(_SRCJAR_URL.format(SRCJAR=os.path.join(
- common_util.get_android_root_dir(), srcjar_dir)))
- if srcjar_urls:
- return content.replace(_SRCJAR_TOKEN, '\n'.join(srcjar_urls))
- return content.replace(_SRCJAR_TOKEN + '\n', '')
-
- # pylint: disable=too-many-locals
- def _generate_iml(self, source_dict):
- """Generate iml file.
-
- #TODO(b/155346505): Removes this method after the project files are
- # created by ProjectSplitter.
-
- Args:
- source_dict: A dictionary of sources path with a flag to distinguish
- the path is test or source folder in IntelliJ.
- e.g.
- {'path_a': True, 'path_b': False}
-
- Returns:
- String: The absolute paths of module iml and dependencies iml.
- """
- module_path = self.project_info.project_absolute_path
- jar_dependencies = list(self.project_info.source_path['jar_path'])
- # Separate module and dependencies source folder
- project_source_dict = {}
- for source in list(source_dict):
- if self._is_project_relative_source(source):
- is_test = source_dict.get(source)
- source_dict.pop(source)
- project_source_dict.update({source: is_test})
-
- # Generate module iml.
- module_content = self._handle_facet(templates.FILE_IML)
- module_content = self._handle_source_folder(module_content,
- project_source_dict, True)
- module_content = self._handle_srcjar_folder(module_content)
- # b/121256503: Prevent duplicated iml names from breaking IDEA.
- module_name = iml.IMLGenerator.get_unique_iml_name(module_path)
-
- module_iml_path = os.path.join(module_path,
- module_name + _IML_EXTENSION)
-
- dep_sect = _MODULE_ORDER_ENTRY % constant.KEY_DEPENDENCIES
- module_content = module_content.replace(_MODULE_DEP_TOKEN, dep_sect)
- common_util.file_generate(module_iml_path, module_content)
-
- # Only generate the dependencies.iml in the main module's folder.
- dependencies_iml_path = None
- if self.project_info.is_main_project:
- dependencies_content = templates.FILE_IML.replace(_FACET_TOKEN, '')
- dependencies_content = self._handle_source_folder(
- dependencies_content, source_dict, False)
- dependencies_content = self._handle_srcjar_folder(
- dependencies_content,
- self.project_info.source_path['srcjar_path'])
- dependencies_content = self._handle_module_dependency(
- dependencies_content, jar_dependencies)
- dependencies_iml_path = os.path.join(
- module_path, constant.KEY_DEPENDENCIES + _IML_EXTENSION)
- common_util.file_generate(dependencies_iml_path,
- dependencies_content)
- logging.debug('Paired iml names are %s, %s', module_iml_path,
- dependencies_iml_path)
- # The dependencies_iml_path is use for removing the file itself in
- # unittest.
- return module_iml_path, dependencies_iml_path
-
def _generate_modules_xml(self, iml_path_list=None):
"""Generate modules.xml file.
@@ -478,64 +216,6 @@
content = content.replace(_ENABLE_DEBUGGER_MODULE_TOKEN, '')
return content
- def _get_project_git_path(self):
- """Get the project's git path.
-
- Return:
- String: A module's git path.
- """
- module_path = self.project_info.project_absolute_path
- # When importing whole Android repo, it shouldn't add vcs.xml,
- # because IntelliJ doesn't handle repo as a version control.
- if module_path == common_util.get_android_root_dir():
- return None
- git_path = module_path
- while not os.path.isdir(os.path.join(git_path, _GIT_FOLDER_NAME)):
- git_path = str(pathlib.Path(git_path).parent)
- if git_path == os.sep:
- logging.warning('%s can\'t find its .git folder', module_path)
- return None
- return git_path
-
-
-def _trim_same_root_source(source_list):
- """Trim the source which has the same root.
-
- The source list may contain lots of duplicate sources.
- For example:
- a/b, a/b/c, a/b/d
- We only need to import a/b in iml, this function is used to trim redundant
- sources.
-
- Args:
- source_list: Sorted list of the sources.
-
- Returns:
- List: The trimmed source list.
- """
- tmp_source_list = [source_list[0]]
- for src_path in source_list:
- if ''.join([tmp_source_list[-1],
- os.sep]) not in ''.join([src_path, os.sep]):
- tmp_source_list.append(src_path)
- return sorted(tmp_source_list)
-
-
-def _write_vcs_xml(module_path, git_paths):
- """Write the git path into vcs.xml.
-
- For main module, the vcs.xml should include all modules' git path.
- For submodules, there is only one git path in vcs.xml.
-
- Args:
- module_path: Path of the module.
- git_paths: A list of git path.
- """
- _vcs_content = '\n'.join([_VCS_SECTION % p for p in git_paths if p])
- content = templates.XML_VCS.replace(_VCS_TOKEN, _vcs_content)
- target_path = os.path.join(module_path, _IDEA_FOLDER, _VCS_XML)
- common_util.file_generate(target_path, content)
-
def _merge_project_vcs_xmls(projects):
"""Merge sub projects' git paths into main project's vcs.xml.
@@ -547,13 +227,14 @@
projects: A list of ProjectInfo instances.
"""
main_project_absolute_path = projects[0].project_absolute_path
- # TODO(b/154436905): Add the necessary git path to vcs.xml.
if main_project_absolute_path != common_util.get_android_root_dir():
- git_paths = [project.git_path for project in projects]
- _write_vcs_xml(main_project_absolute_path, git_paths)
+ git_paths = [common_util.find_git_root(project.project_relative_path)
+ for project in projects if project.project_relative_path]
+ xml_gen.gen_vcs_xml(main_project_absolute_path, git_paths)
else:
- _write_vcs_xml(main_project_absolute_path, [])
-
+ ignore_gits = sorted(_get_all_git_path(main_project_absolute_path))
+ xml_gen.write_ignore_git_dirs_file(main_project_absolute_path,
+ ignore_gits)
def _get_all_git_path(root_path):
"""Traverse all subdirectories to get all git folder's path.
@@ -627,31 +308,6 @@
for y in module_relpaths})}
-def _merge_all_shared_source_paths(projects):
- """Merge all source paths and jar paths into main project.
-
- There should be no duplicate source root path in IntelliJ. The issue doesn't
- happen in single project case. Once users choose multiple projects, there
- could be several same source paths of different projects. In order to
- prevent that, we should remove the source paths in dependencies.iml which
- are duplicate with the paths in [module].iml files.
-
- Args:
- projects: A list of ProjectInfo instances.
- """
- main_project = projects[0]
- # Merge all source paths of sub projects into main project.
- for project in projects[1:]:
- for key, value in project.source_path.items():
- main_project.source_path[key].update(value)
- # Filter duplicate source/test paths from dependencies.iml.
- sub_projects_relpaths = {p.project_relative_path for p in projects[1:]}
- main_project.source_path['source_folder_path'] = _filter_out_source_paths(
- main_project.source_path['source_folder_path'], sub_projects_relpaths)
- main_project.source_path['test_folder_path'] = _filter_out_source_paths(
- main_project.source_path['test_folder_path'], sub_projects_relpaths)
-
-
def update_enable_debugger(module_path, enable_debugger_module_abspath=None):
"""Append the enable_debugger module's info in modules.xml file.
diff --git a/aidegen/lib/project_file_gen_unittest.py b/aidegen/lib/project_file_gen_unittest.py
index 36e2e10..10bedf7 100644
--- a/aidegen/lib/project_file_gen_unittest.py
+++ b/aidegen/lib/project_file_gen_unittest.py
@@ -16,23 +16,20 @@
"""Unittests for project_file_gen."""
-import copy
+import logging
import os
import shutil
import unittest
from unittest import mock
-from aidegen import aidegen_main
-from aidegen import templates
from aidegen import unittest_constants
-from aidegen.idea import iml
+from aidegen.idea import xml_gen
from aidegen.lib import common_util
from aidegen.lib import config
from aidegen.lib import project_config
from aidegen.lib import project_file_gen
from aidegen.lib import project_info
from aidegen.project import source_splitter
-from atest import module_info
# pylint: disable=protected-access
@@ -54,16 +51,13 @@
'modules_only_self_module.xml')
_ENABLE_DEBUGGER_MODULE_SAMPLE = os.path.join(
_TEST_DATA_PATH, 'modules_with_enable_debugger.xml')
- _VCS_XML_SAMPLE = os.path.join(_TEST_DATA_PATH, 'vcs.xml')
_IML_PATH = os.path.join(_ANDROID_PROJECT_PATH, 'android_project.iml')
_DEPENDENCIES_IML_PATH = os.path.join(_ANDROID_PROJECT_PATH,
'dependencies.iml')
_IDEA_PATH = os.path.join(_ANDROID_PROJECT_PATH, '.idea')
_MODULE_PATH = os.path.join(_IDEA_PATH, 'modules.xml')
- _VCS_PATH = os.path.join(_IDEA_PATH, 'vcs.xml')
_SOURCE_SAMPLE = os.path.join(_TEST_DATA_PATH, 'source.iml')
_SRCJAR_SAMPLE = os.path.join(_TEST_DATA_PATH, 'srcjar.iml')
- _LOCAL_PATH_TOKEN = '@LOCAL_PATH@'
_AOSP_FOLDER = '/aosp'
_TEST_SOURCE_LIST = [
'a/b/c/d', 'a/b/c/d/e', 'a/b/c/d/e/f', 'a/b/c/d/f', 'e/f/a', 'e/f/b/c',
@@ -79,170 +73,8 @@
pconfig = project_config.ProjectConfig(args)
pconfig.init_environment()
- @mock.patch('aidegen.lib.project_info.ProjectInfo')
- def test_handle_facet_for_android(self, mock_project):
- """Test _handle_facet with android project."""
- mock_project.project_absolute_path = self._ANDROID_PROJECT_PATH
- android_facet = project_file_gen.ProjectFileGenerator(
- mock_project)._handle_facet(templates.FILE_IML)
- sample_android_facet = common_util.read_file_content(
- self._ANDROID_FACET_SAMPLE)
- self.assertEqual(android_facet, sample_android_facet)
-
- @mock.patch('aidegen.lib.project_info.ProjectInfo')
- def test_handle_facet_for_normal(self, mock_project):
- """Test _handle_facet with normal module."""
- mock_project.project_absolute_path = self._PROJECT_PATH
- project_facet = project_file_gen.ProjectFileGenerator(
- mock_project)._handle_facet(templates.FILE_IML)
- sample_project_facet = common_util.read_file_content(
- self._PROJECT_FACET_SAMPLE)
- self.assertEqual(project_facet, sample_project_facet)
-
- def test_handle_module_dependency(self):
- """Test _module_dependency."""
- module_dependency = templates.FILE_IML.replace(
- project_file_gen._MODULE_DEP_TOKEN, '')
- correct_module_dep = common_util.read_file_content(
- self._MODULE_DEP_SAMPLE)
- self.assertEqual(correct_module_dep, module_dependency)
-
- def test_trim_same_root_source(self):
- """Test _trim_same_root_source."""
- url_list = project_file_gen._trim_same_root_source(
- self._TEST_SOURCE_LIST[:])
- self.assertEqual(url_list, self._SAMPLE_TRIMMED_SOURCE_LIST)
-
- @mock.patch.object(project_config.ProjectConfig, 'init_environment')
- @mock.patch('aidegen.lib.common_util.get_android_root_dir')
- @mock.patch('aidegen.lib.project_info.ProjectInfo')
- def test_handle_source_folder(self, mock_project, mock_get_root, mock_init):
- """Test _handle_source_folder."""
- args = aidegen_main._parse_args([])
- mock_init.return_value = None
- self._init_project_config(args)
- mock_get_root.return_value = self._AOSP_FOLDER
- mock_project.project_relative_path = self._ANDROID_SOURCE_RELATIVE_PATH
- source = project_file_gen.ProjectFileGenerator(
- mock_project)._handle_source_folder(
- templates.FILE_IML, copy.deepcopy(
- unittest_constants.ANDROID_SOURCE_DICT), True)
- sample_source = common_util.read_file_content(self._SOURCE_SAMPLE)
- self.assertEqual(source, sample_source)
-
- @mock.patch.object(project_config.ProjectConfig, 'init_environment')
- @mock.patch('aidegen.lib.common_util.get_android_root_dir')
- @mock.patch('aidegen.lib.project_info.ProjectInfo')
- def test_generate_iml(self, mock_project, mock_get_root, mock_init):
- """Test _generate_iml."""
- args = aidegen_main._parse_args([])
- mock_init.return_value = None
- self._init_project_config(args)
- mock_get_root.return_value = self._AOSP_FOLDER
- mock_project.project_absolute_path = self._ANDROID_PROJECT_PATH
- mock_project.project_relative_path = self._ANDROID_SOURCE_RELATIVE_PATH
- mock_project.source_path['jar_path'] = set(
- unittest_constants.JAR_DEP_LIST)
- pfile_gen = project_file_gen.ProjectFileGenerator(mock_project)
- # Test for main project.
- try:
- iml_path, dependencies_iml_path = pfile_gen._generate_iml(
- copy.deepcopy(unittest_constants.ANDROID_SOURCE_DICT))
- test_iml = common_util.read_file_content(iml_path)
- sample_iml = common_util.read_file_content(self._IML_SAMPLE)
- finally:
- os.remove(iml_path)
- if dependencies_iml_path:
- os.remove(dependencies_iml_path)
- self.assertEqual(test_iml, sample_iml)
-
- # Test for sub projects.
- try:
- iml_path, _ = pfile_gen._generate_iml(
- copy.deepcopy(unittest_constants.ANDROID_SOURCE_DICT))
- test_iml = common_util.read_file_content(iml_path)
- sample_iml = common_util.read_file_content(self._IML_SAMPLE)
- finally:
- os.remove(iml_path)
- self.assertEqual(test_iml, sample_iml)
-
- @mock.patch.object(project_config.ProjectConfig, 'init_environment')
- @mock.patch('aidegen.lib.common_util.get_android_root_dir')
- @mock.patch('aidegen.lib.project_info.ProjectInfo')
- def test_generate_iml_with_excludes(self, mock_project, mock_get_root,
- mock_init):
- """Test _generate_iml with exclusive paths."""
- excludes = '.idea'
- args = aidegen_main._parse_args(['-e', excludes])
- mock_init.return_value = None
- self._init_project_config(args)
- mock_get_root.return_value = self._AOSP_FOLDER
- mock_project.project_absolute_path = self._ANDROID_PROJECT_PATH
- mock_project.project_relative_path = self._ANDROID_SOURCE_RELATIVE_PATH
- mock_project.source_path['jar_path'] = set(
- unittest_constants.JAR_DEP_LIST)
- pfile_gen = project_file_gen.ProjectFileGenerator(mock_project)
- iml_path = None
- dependencies_iml_path = None
- # Test for main project.
- try:
- iml_path, dependencies_iml_path = pfile_gen._generate_iml(
- copy.deepcopy(unittest_constants.ANDROID_SOURCE_DICT))
- test_iml = common_util.read_file_content(iml_path)
- sample_iml = common_util.read_file_content(self._IML_SAMPLE)
- finally:
- if iml_path:
- os.remove(iml_path)
- if dependencies_iml_path:
- os.remove(dependencies_iml_path)
- self.assertEqual(test_iml, sample_iml)
-
- # Test for sub projects.
- try:
- iml_path, _ = pfile_gen._generate_iml(
- copy.deepcopy(unittest_constants.ANDROID_SOURCE_DICT))
- test_iml = common_util.read_file_content(iml_path)
- sample_iml = common_util.read_file_content(self._IML_SAMPLE)
- finally:
- os.remove(iml_path)
- self.assertEqual(test_iml, sample_iml)
-
- @mock.patch.object(common_util, 'file_generate')
- @mock.patch.object(project_file_gen.ProjectFileGenerator,
- '_handle_srcjar_folder')
- @mock.patch.object(project_file_gen.ProjectFileGenerator, '_handle_facet')
- @mock.patch.object(project_file_gen.ProjectFileGenerator,
- '_handle_source_folder')
- @mock.patch('aidegen.lib.common_util.get_android_root_dir')
- @mock.patch('aidegen.lib.project_info.ProjectInfo')
- def test_generate_iml_for_module(self, mock_project, mock_get_root,
- mock_do_src, mock_do_facet,
- mock_do_srcjar, mock_file_gen):
- """Test _generate_iml for generating module's iml."""
- mock_get_root.return_value = self._AOSP_FOLDER
- mock_project.project_absolute_path = self._ANDROID_PROJECT_PATH
- mock_project.project_relative_path = self._ANDROID_SOURCE_RELATIVE_PATH
- mock_project.source_path['jar_path'] = set(
- unittest_constants.JAR_DEP_LIST)
- test_srcjar_for_sub = ('test', 'srcjar', 'path')
- mock_project.source_path['srcjar_path'] = test_srcjar_for_sub
- mock_project.is_main_project = False
- pfile_gen = project_file_gen.ProjectFileGenerator(mock_project)
- mock_do_facet.return_value = 'facet'
- mock_do_src.return_value = 'source'
- mock_do_srcjar.return_value = 'srcjar'
- mock_file_gen.return_value = None
-
- # Test for module iml generation.
- pfile_gen._generate_iml(copy.deepcopy(
- unittest_constants.ANDROID_SOURCE_DICT))
- self.assertTrue(mock_do_facet.called)
- self.assertTrue(mock_do_src.called_with(True))
- self.assertTrue(mock_do_srcjar.called_with(test_srcjar_for_sub))
- self.assertEqual(mock_file_gen.call_count, 1)
-
- @mock.patch('aidegen.lib.project_config.ProjectConfig')
- @mock.patch('aidegen.lib.project_info.ProjectInfo')
+ @mock.patch.object(project_config, 'ProjectConfig')
+ @mock.patch.object(project_info, 'ProjectInfo')
def test_generate_modules_xml(self, mock_project, mock_config):
"""Test _generate_modules_xml."""
mock_config.is_launch_ide = True
@@ -269,78 +101,31 @@
self._MAIN_MODULE_XML_SAMPLE)
self.assertEqual(test_module, sample_module)
- @mock.patch('os.path.isdir')
- @mock.patch('aidegen.lib.project_info.ProjectInfo')
- def test_get_project_git_path(self, mock_project, mock_isdir):
- """Test _get_project_git_path."""
- mock_project.project_absolute_path = '/a/b'
- mock_isdir.return_value = True
- expected_git_path = '/a/b'
- pfile_gen = project_file_gen.ProjectFileGenerator(mock_project)
- test_git_path = pfile_gen._get_project_git_path()
- self.assertEqual(test_git_path, expected_git_path)
-
- @mock.patch('aidegen.lib.common_util.get_android_root_dir')
- @mock.patch('aidegen.lib.project_file_gen._get_all_git_path')
- @mock.patch('aidegen.lib.project_info.ProjectInfo')
- def test_merge_project_vcs_xmls(self, mock_project, mock_get_all_git_path,
- mock_get_root):
+ @mock.patch.object(project_file_gen, '_get_all_git_path')
+ @mock.patch.object(xml_gen, 'write_ignore_git_dirs_file')
+ @mock.patch.object(xml_gen, 'gen_vcs_xml')
+ @mock.patch.object(common_util, 'get_android_root_dir')
+ @mock.patch.object(common_util, 'find_git_root')
+ @mock.patch.object(project_info, 'ProjectInfo')
+ def test_merge_project_vcs_xmls(self, mock_project, mock_get_git_root,
+ mock_get_root, mock_write, mock_ignore_git,
+ mock_all_git_path):
"""Test _merge_project_vcs_xmls."""
- mock_project.project_absolute_path = (
- unittest_constants.ANDROID_PROJECT_PATH)
- mock_project.git_path = unittest_constants.ANDROID_PROJECT_PATH
+ mock_get_root.return_value = '/a/b'
+ mock_project.project_absolute_path = '/a/b/c'
+ mock_project.project_relative_path = 'c'
+ mock_get_git_root.return_value = '/a/b/c'
project_file_gen._merge_project_vcs_xmls([mock_project])
- test_vcs = common_util.read_file_content(self._VCS_PATH)
- sample_vcs = common_util.read_file_content(self._VCS_XML_SAMPLE)
- # The sample must base on the real path.
- sample_vcs = sample_vcs.replace(self._LOCAL_PATH_TOKEN,
- self._ANDROID_PROJECT_PATH)
- self.assertEqual(test_vcs, sample_vcs)
- mock_get_root.return_value = unittest_constants.ANDROID_PROJECT_PATH
+ self.assertTrue(mock_write.called_with('/a/b/c', '/a/b/c'))
+ mock_project.project_absolute_path = '/a/b'
+ mock_project.project_relative_path = None
+ mock_get_git_root.return_value = None
+ mock_all_git_path.return_value = ['/a', '/b']
project_file_gen._merge_project_vcs_xmls([mock_project])
- self.assertFalse(mock_get_all_git_path.called)
+ self.assertTrue(mock_write.called_with('/a/b', [None]))
+ self.assertTrue(mock_ignore_git.called_with('/a/b', ['/a', '/b']))
- def test_get_uniq_iml_name(self):
- """Test the unique name cache mechanism.
-
- By using the path data in module info json as input, if the count of
- name data set is the same as sub folder path count, then it means
- there's no duplicated name, the test PASS.
- """
- # Add following test path
- test_paths = {
- 'cts/tests/tests/app',
- 'cts/tests/app',
- 'cts/tests/app/app1/../app',
- 'cts/tests/app/app2/../app',
- 'cts/tests/app/app3/../app',
- 'frameworks/base/tests/xxxxxxxxxxxx/base',
- 'frameworks/base',
- 'external/xxxxx-xxx/robolectric',
- 'external/robolectric',
- }
- mod_info = module_info.ModuleInfo()
- test_paths.update(mod_info._get_path_to_module_info(
- mod_info.name_to_module_info).keys())
- print('\n{} {}.'.format('Test_paths length:', len(test_paths)))
-
- path_list = []
- for path in test_paths:
- path_list.append(path)
- print('{} {}.'.format('path list with length:', len(path_list)))
-
- names = [iml.IMLGenerator.get_unique_iml_name(f)
- for f in path_list]
- print('{} {}.'.format('Names list with length:', len(names)))
-
- self.assertEqual(len(names), len(path_list))
- dic = {}
- for i, path in enumerate(path_list):
- dic[names[i]] = path
- print('{} {}.'.format('The size of name set is:', len(dic)))
- self.assertEqual(len(dic), len(path_list))
-
- @mock.patch('aidegen.lib.project_info.ProjectInfo')
+ @mock.patch.object(project_info, 'ProjectInfo')
def test_copy_project_files(self, mock_project):
"""Test _copy_constant_project_files."""
mock_project.project_absolute_path = self._ANDROID_PROJECT_PATH
@@ -363,8 +148,8 @@
'profiles_settings.xml')))
shutil.rmtree(self._IDEA_PATH)
- @mock.patch('logging.error')
- @mock.patch('os.symlink')
+ @mock.patch.object(logging, 'error')
+ @mock.patch.object(os, 'symlink')
@mock.patch.object(os.path, 'exists')
def test_generate_git_ignore(self, mock_path_exist, mock_link,
mock_loggin_error):
@@ -390,56 +175,8 @@
module_relpath)
self.assertEqual(result_set, expected_result)
- @mock.patch('aidegen.lib.project_info.ProjectInfo')
- @mock.patch('aidegen.lib.project_info.ProjectInfo')
- def test_merge_all_source_paths(self, mock_main_project, mock_sub_project):
- """Test _merge_all_shared_source_paths."""
- mock_main_project.project_relative_path = 'main'
- mock_main_project.source_path = {
- 'source_folder_path': {
- 'main/java.java',
- 'sub/java.java',
- 'share1/java.java'
- },
- 'test_folder_path': {'main/test.java', 'share1/test.java'},
- 'jar_path': {'main/jar.jar', 'share1/jar.jar'},
- 'r_java_path': {'out/R1.java'},
- 'srcjar_path': {'out/a.srcjar'},
- }
- mock_sub_project.project_relative_path = 'sub'
- mock_sub_project.source_path = {
- 'source_folder_path': {'sub/java.java', 'share2/java.java'},
- 'test_folder_path': {'sub/test.java', 'share2/test.java'},
- 'jar_path': {'sub/jar.jar', 'share2/jar.jar'},
- 'r_java_path': {'out/R2.java'},
- 'srcjar_path': {'out/b.srcjar'},
- }
- expected_result = {
- 'source_folder_path': {
- 'main/java.java',
- 'share1/java.java',
- 'share2/java.java',
- },
- 'test_folder_path': {
- 'main/test.java',
- 'share1/test.java',
- 'share2/test.java',
- },
- 'jar_path': {
- 'main/jar.jar',
- 'sub/jar.jar',
- 'share1/jar.jar',
- 'share2/jar.jar',
- },
- 'r_java_path': {'out/R1.java', 'out/R2.java'},
- 'srcjar_path': {'out/a.srcjar', 'out/b.srcjar'},
- }
- projects = [mock_main_project, mock_sub_project]
- project_file_gen._merge_all_shared_source_paths(projects)
- self.assertEqual(mock_main_project.source_path, expected_result)
-
- @mock.patch('aidegen.lib.project_config.ProjectConfig')
- @mock.patch('aidegen.lib.project_info.ProjectInfo')
+ @mock.patch.object(project_config, 'ProjectConfig')
+ @mock.patch.object(project_info, 'ProjectInfo')
def test_update_enable_debugger(self, mock_project, mock_config):
"""Test update_enable_debugger."""
mock_config.is_launch_ide = True
@@ -457,19 +194,7 @@
finally:
shutil.rmtree(self._IDEA_PATH)
- @mock.patch('aidegen.lib.common_util.get_android_root_dir')
- @mock.patch('aidegen.lib.project_info.ProjectInfo')
- def test_handle_srcjar_folder(self, mock_project, mock_get_root):
- """Test _handle_srcjar_folder."""
- mock_get_root.return_value = self._AOSP_FOLDER
- source = project_file_gen.ProjectFileGenerator(
- mock_project)._handle_srcjar_folder(templates.FILE_IML,
- {'out/aapt2.srcjar'})
- sample_source = common_util.read_file_content(self._SRCJAR_SAMPLE)
- self.assertEqual(source, sample_source)
-
- @mock.patch.object(project_file_gen.ProjectFileGenerator,
- '_get_project_git_path')
+ @mock.patch.object(common_util, 'find_git_root')
@mock.patch.object(project_file_gen.ProjectFileGenerator,
'_generate_modules_xml')
@mock.patch.object(project_info, 'ProjectInfo')
@@ -481,45 +206,12 @@
project_gen = project_file_gen.ProjectFileGenerator(mock_project)
project_gen.project_info.is_main_project = False
project_gen.generate_intellij_project_file()
- self.assertEqual(project_gen.project_info.git_path, 'git/path')
self.assertFalse(mock_gen_xml.called)
project_gen.project_info.is_main_project = True
project_gen.generate_intellij_project_file()
self.assertTrue(mock_gen_xml.called)
- @mock.patch.object(project_info, 'ProjectInfo')
- def test_generate_source_section(self, mock_project):
- """Test _generate_source_section."""
- mock_project.project_absolute_path = self._ANDROID_PROJECT_PATH
- mock_project.source_path = {
- 'source': ['a', 'b']
- }
- project_gen = project_file_gen.ProjectFileGenerator(mock_project)
- expected_result = {'a': False, 'b': False}
- test_result = project_gen._generate_source_section('source', False)
- self.assertEqual(test_result, expected_result)
-
- @mock.patch.object(common_util, 'get_android_root_dir')
- @mock.patch.object(project_info, 'ProjectInfo')
- def test_is_project_relative_source(self, mock_project, mock_get_root):
- """Test _is_project_relative_source."""
- mock_get_root.return_value = '/aosp'
- mock_project.project_absolute_path = '/aosp'
- mock_project.project_relative_path = ''
- project_gen = project_file_gen.ProjectFileGenerator(mock_project)
- self.assertTrue(project_gen._is_project_relative_source('a/b'))
-
- mock_project.project_absolute_path = '/aosp/a/b'
- mock_project.project_relative_path = 'a/b'
- project_gen = project_file_gen.ProjectFileGenerator(mock_project)
- self.assertTrue(project_gen._is_project_relative_source('a/b/c'))
-
- mock_project.project_absolute_path = '/test/a/b'
- mock_project.project_relative_path = 'a/b'
- project_gen = project_file_gen.ProjectFileGenerator(mock_project)
- self.assertFalse(project_gen._is_project_relative_source('d/e'))
-
- @mock.patch('os.walk')
+ @mock.patch.object(os, 'walk')
def test_get_all_git_path(self, mock_os_walk):
"""Test _get_all_git_path."""
# Test .git folder exists.
@@ -535,7 +227,7 @@
self.assertEqual(test_result, expected_result)
@mock.patch.object(common_util, 'file_generate')
- @mock.patch('os.path.isfile')
+ @mock.patch.object(os.path, 'isfile')
def test_generate_test_mapping_schema(self, mock_is_file,
mock_file_generate):
"""Test _generate_test_mapping_schema."""
diff --git a/aidegen/lib/project_info.py b/aidegen/lib/project_info.py
index c84ec92..3bcb18a 100644
--- a/aidegen/lib/project_info.py
+++ b/aidegen/lib/project_info.py
@@ -71,7 +71,6 @@
directory or it's subdirectories.
dep_modules: A dict has recursively dependent modules of
project_module_names.
- git_path: The project's git path.
iml_path: The project's iml file path.
source_path: A dictionary to keep following data:
source_folder_path: A set contains the source folder
@@ -114,7 +113,6 @@
self.modules_info.get_module_names(rel_path))
self.project_relative_path = rel_path
self.project_absolute_path = abs_path
- self.git_path = ''
self.iml_path = ''
self._set_default_modues()
self._init_source_path()
@@ -430,6 +428,35 @@
project.locate_source()
+class MultiProjectsInfo(ProjectInfo):
+ """Multiple projects info.
+
+ Usage example:
+ project = MultiProjectsInfo(['module_name'])
+ project.collect_all_dep_modules()
+ """
+
+ def __init__(self, targets=None):
+ """MultiProjectsInfo initialize.
+
+ Args:
+ targets: A list of module names or project paths from user's input.
+ """
+ super().__init__(targets[0], True)
+ self._targets = targets
+
+ def collect_all_dep_modules(self):
+ """Collects all dependency modules for the projects."""
+ self.project_module_names = set()
+ module_names = set(_CORE_MODULES)
+ for target in self._targets:
+ relpath, _ = common_util.get_related_paths(self.modules_info,
+ target)
+ module_names.update(self._get_modules_under_project_path(relpath))
+ module_names.update(self._get_robolectric_dep_module(module_names))
+ self.dep_modules = self.get_dep_modules(module_names)
+
+
def batch_build_dependencies(rebuild_targets):
"""Batch build the jar or srcjar files of the modules if they don't exist.
diff --git a/aidegen/lib/project_info_unittest.py b/aidegen/lib/project_info_unittest.py
index f2b8940..19f1d8f 100644
--- a/aidegen/lib/project_info_unittest.py
+++ b/aidegen/lib/project_info_unittest.py
@@ -328,5 +328,30 @@
self.assertEqual(mock_build.call_count, 1)
+class MultiProjectsInfoUnittests(unittest.TestCase):
+ """Unit tests for MultiProjectsInfo class."""
+
+ @mock.patch.object(project_info.ProjectInfo, '__init__')
+ @mock.patch.object(project_info.ProjectInfo, 'get_dep_modules')
+ @mock.patch.object(project_info.ProjectInfo,
+ '_get_robolectric_dep_module')
+ @mock.patch.object(project_info.ProjectInfo,
+ '_get_modules_under_project_path')
+ @mock.patch.object(common_util, 'get_related_paths')
+ def test_collect_all_dep_modules(self, mock_relpath, mock_sub_modules_path,
+ mock_robo_module, mock_get_dep_modules,
+ mock_init):
+ """Test _collect_all_dep_modules."""
+ mock_init.return_value = None
+ mock_relpath.return_value = ('path/to/sub/module', '')
+ mock_sub_modules_path.return_value = 'sub_module'
+ mock_robo_module.return_value = 'robo_module'
+ expected = set(project_info._CORE_MODULES)
+ expected.update({'sub_module', 'robo_module'})
+ proj = project_info.MultiProjectsInfo(['a'])
+ proj.collect_all_dep_modules()
+ self.assertTrue(mock_get_dep_modules.called_with(expected))
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/aidegen/lib/source_locator.py b/aidegen/lib/source_locator.py
index 3066b8e..7a8e5a2 100644
--- a/aidegen/lib/source_locator.py
+++ b/aidegen/lib/source_locator.py
@@ -26,6 +26,7 @@
from aidegen import constant
from aidegen.lib import common_util
from aidegen.lib import module_info
+from aidegen.lib import project_config
# Parse package name from the package declaration line of a java.
# Group matches "foo.bar" of line "package foo.bar;" or "package foo.bar"
@@ -50,6 +51,8 @@
]
_ANDROID = 'android'
_REPACKAGES = 'repackaged'
+_FRAMEWORK_SRCJARS_PATH = os.path.join(constant.FRAMEWORK_PATH,
+ constant.FRAMEWORK_SRCJARS)
class ModuleData:
@@ -60,12 +63,13 @@
repo root.
module_path: A string of the relative path to the module.
- src_dirs: A set to keep the unique source folder relative paths.
- test_dirs: A set to keep the unique test folder relative paths.
- jar_files: A set to keep the unique jar file relative paths.
- r_java_paths: A set to keep the R folder paths to use in Eclipse.
- srcjar_paths: A set to keep the srcjar source root paths to use in
+ src_dirs: A list to keep the unique source folder relative paths.
+ test_dirs: A list to keep the unique test folder relative paths.
+ jar_files: A list to keep the unique jar file relative paths.
+ r_java_paths: A list to keep the R folder paths to use in Eclipse.
+ srcjar_paths: A list to keep the srcjar source root paths to use in
IntelliJ.
+ dep_paths: A list to keep the dependency modules' path.
referenced_by_jar: A boolean to check if the module is referenced by a
jar file.
build_targets: A set to keep the unique build target jar or srcjar file
@@ -113,6 +117,7 @@
self.jar_files = []
self.r_java_paths = []
self.srcjar_paths = []
+ self.dep_paths = []
self.referenced_by_jar = False
self.build_targets = set()
self.missing_jars = set()
@@ -565,6 +570,21 @@
if self.referenced_by_jar and self.missing_jars:
self.build_targets |= self.missing_jars
+ def _collect_dep_paths(self):
+ """Collects the path of dependency modules."""
+ config = project_config.ProjectConfig.get_instance()
+ modules_info = config.atest_module_info
+ self.dep_paths = []
+ if self.module_path != constant.FRAMEWORK_PATH:
+ self.dep_paths.append(constant.FRAMEWORK_PATH)
+ self.dep_paths.append(_FRAMEWORK_SRCJARS_PATH)
+ if self.module_path != constant.LIBCORE_PATH:
+ self.dep_paths.append(constant.LIBCORE_PATH)
+ for module in self.module_data.get(constant.KEY_DEPENDENCIES, []):
+ for path in modules_info.get_paths(module):
+ if path not in self.dep_paths and path != self.module_path:
+ self.dep_paths.append(path)
+
def locate_sources_path(self):
"""Locate source folders' paths or jar files."""
# Check if users need to reference source according to source depth.
diff --git a/aidegen/lib/source_locator_unittest.py b/aidegen/lib/source_locator_unittest.py
index ff2865c..b8636a4 100644
--- a/aidegen/lib/source_locator_unittest.py
+++ b/aidegen/lib/source_locator_unittest.py
@@ -24,7 +24,9 @@
from aidegen.lib import common_util
from aidegen.lib import module_info
+from aidegen.lib import project_config
from aidegen.lib import source_locator
+from atest import module_info as amodule_info
# pylint: disable=too-many-arguments
@@ -503,6 +505,52 @@
mod_data._append_classes_jar()
self.assertEqual(mod_data.jar_files, [])
+ @mock.patch.object(amodule_info, 'ModuleInfo')
+ @mock.patch.object(amodule_info.ModuleInfo, 'get_paths')
+ @mock.patch.object(project_config.ProjectConfig, 'get_instance')
+ def test_collect_dep_paths(self, mock_config, mock_get_paths,
+ mock_atest_module_info):
+ """Test _collect_dep_paths."""
+ mod_name = 'test'
+ mod_info = {
+ 'name': 'test',
+ 'path': ['frameworks/base'],
+ 'dependencies': ['test_module']
+ }
+ mod_data = source_locator.ModuleData(mod_name, mod_info, 0)
+ mock_instance = mock_config.return_value
+ mock_instance.atest_module_info = mock_atest_module_info
+ mock_instance.atest_module_info.get_paths = mock_get_paths
+ mock_get_paths.return_value = []
+ expected = [
+ 'frameworks/base/framework_srcjars',
+ 'libcore',
+ ]
+ mod_data._collect_dep_paths()
+ self.assertEqual(mod_data.dep_paths, expected)
+ mod_info['path'] = ['libcore']
+ mod_data = source_locator.ModuleData(mod_name, mod_info, 0)
+ expected = [
+ 'frameworks/base',
+ 'frameworks/base/framework_srcjars',
+ ]
+ mod_data._collect_dep_paths()
+ self.assertEqual(mod_data.dep_paths, expected)
+ mock_get_paths.return_value = ['test']
+ mod_info['path'] = ['test']
+ mod_data = source_locator.ModuleData(mod_name, mod_info, 0)
+ expected = [
+ 'frameworks/base',
+ 'frameworks/base/framework_srcjars',
+ 'libcore',
+ ]
+ mod_data._collect_dep_paths()
+ self.assertEqual(mod_data.dep_paths, expected)
+ mock_get_paths.return_value = ['dep/path']
+ expected.append('dep/path')
+ mod_data._collect_dep_paths()
+ self.assertEqual(mod_data.dep_paths, expected)
+
class EclipseModuleDataUnittests(unittest.TestCase):
"""Unit tests for the EclipseModuleData in module_data.py"""
diff --git a/aidegen/project/source_splitter.py b/aidegen/project/source_splitter.py
index 430bc54..17ca12c 100644
--- a/aidegen/project/source_splitter.py
+++ b/aidegen/project/source_splitter.py
@@ -29,8 +29,6 @@
_KEY_SRCJAR_PATH = 'srcjar_path'
_KEY_R_PATH = 'r_java_path'
_KEY_JAR_PATH = 'jar_path'
-_FRAMEWORK_PATH = 'frameworks/base'
-_FRAMEWORK_SRCJARS = 'framework_srcjars'
_EXCLUDE_ITEM = '\n <excludeFolder url="file://%s" />'
# Temporarily exclude test-dump and src_stub folders to prevent symbols from
# resolving failure by incorrect reference. These two folders should be removed
@@ -88,12 +86,13 @@
self._projects = projects
self._all_srcs = dict(projects[0].source_path)
self._framework_iml = None
- self._framework_exist = any({p.project_relative_path == _FRAMEWORK_PATH
- for p in self._projects})
+ self._framework_exist = any(
+ {p.project_relative_path == constant.FRAMEWORK_PATH
+ for p in self._projects})
if self._framework_exist:
self._framework_iml = iml.IMLGenerator.get_unique_iml_name(
os.path.join(common_util.get_android_root_dir(),
- _FRAMEWORK_PATH))
+ constant.FRAMEWORK_PATH))
self._full_repo = project_config.ProjectConfig.get_instance().full_repo
if self._full_repo:
self._full_repo_iml = os.path.basename(
@@ -169,8 +168,8 @@
for project in sorted(self._projects, key=lambda k: len(
k.project_relative_path)):
proj_path = project.project_relative_path
- project.dependencies = [_FRAMEWORK_SRCJARS]
- if self._framework_exist and proj_path != _FRAMEWORK_PATH:
+ project.dependencies = [constant.FRAMEWORK_SRCJARS]
+ if self._framework_exist and proj_path != constant.FRAMEWORK_PATH:
project.dependencies.append(self._framework_iml)
if self._full_repo and proj_path:
project.dependencies.append(self._full_repo_iml)
@@ -204,7 +203,7 @@
"""
mod = dict(self._projects[0].dep_modules[constant.FRAMEWORK_ALL])
mod[constant.KEY_DEPENDENCIES] = []
- mod[constant.KEY_IML_NAME] = _FRAMEWORK_SRCJARS
+ mod[constant.KEY_IML_NAME] = constant.FRAMEWORK_SRCJARS
if self._framework_exist:
mod[constant.KEY_DEPENDENCIES].append(self._framework_iml)
if self._full_repo:
@@ -224,7 +223,7 @@
constant.KEY_JARS: self._all_srcs[_KEY_JAR_PATH],
constant.KEY_SRCJARS: (self._all_srcs[_KEY_R_PATH]
| self._all_srcs[_KEY_SRCJAR_PATH]),
- constant.KEY_DEPENDENCIES: [_FRAMEWORK_SRCJARS],
+ constant.KEY_DEPENDENCIES: [constant.FRAMEWORK_SRCJARS],
constant.KEY_PATH: [self._projects[0].project_relative_path],
constant.KEY_MODULE_NAME: constant.KEY_DEPENDENCIES,
constant.KEY_IML_NAME: constant.KEY_DEPENDENCIES
diff --git a/aidegen/templates.py b/aidegen/templates.py
index 47ef644..d7e2657 100644
--- a/aidegen/templates.py
+++ b/aidegen/templates.py
@@ -85,7 +85,7 @@
XML_VCS = """<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
-@VCS@
+{GIT_MAPPINGS}
</component>
</project>
"""
@@ -430,3 +430,18 @@
</component>
</application>
"""
+
+XML_WORKSPACE = """<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="VcsManagerConfiguration">
+ <ignored-roots>
+{GITS}
+ </ignored-roots>
+ </component>
+</project>
+"""
+
+IGNORED_GITS = """<component name="VcsManagerConfiguration">
+ <ignored-roots>{GITS}</ignored-roots>
+ </component>
+"""
\ No newline at end of file
diff --git a/aidegen/test_data/vcs.xml b/aidegen/test_data/vcs.xml
deleted file mode 100644
index 81a97f3..0000000
--- a/aidegen/test_data/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
- <component name="VcsDirectoryMappings">
- <mapping directory="@LOCAL_PATH@" vcs="Git" />
- </component>
-</project>
diff --git a/atest/Android.bp b/atest/Android.bp
index 37a043f..6d69af9 100644
--- a/atest/Android.bp
+++ b/atest/Android.bp
@@ -41,7 +41,7 @@
}
python_binary_host {
- name: "atest-py3",
+ name: "atest",
main: "atest.py",
srcs: [
"**/*.py",
@@ -61,7 +61,7 @@
":asuite_version",
],
// Make atest's built name to atest-dev
- stem: "atest-py3-dev",
+ stem: "atest-dev",
defaults: ["atest_py3_default"],
dist: {
targets: ["droidcore"],
@@ -82,7 +82,7 @@
// Exclude atest_updatedb_unittest due to it's a test for ATest's wrapper
// of updatedb, but there's no updatedb binary on test server.
python_test_host {
- name: "atest-py3_unittests",
+ name: "atest_unittests",
main: "atest_run_unittests.py",
pkg_path: "atest",
srcs: [
@@ -108,7 +108,7 @@
}
python_test_host {
- name: "atest-py3_integration_tests",
+ name: "atest_integration_tests",
main: "atest_integration_tests.py",
pkg_path: "atest",
srcs: [
diff --git a/atest/atest.py b/atest/atest.py
index 0c8fdd9..d90cd67 100755
--- a/atest/atest.py
+++ b/atest/atest.py
@@ -518,7 +518,7 @@
# List failed tests at the end as a reminder.
if failed_tests:
atest_utils.colorful_print(
- '\n==============================', constants.YELLOW)
+ atest_utils.delimiter('=', 30, prenl=1), constants.YELLOW)
atest_utils.colorful_print(
'\nFollowing tests failed:', constants.MAGENTA)
for failure in failed_tests:
@@ -558,7 +558,7 @@
testable_modules = mod_info.get_testable_modules(suite)
print('\n%s' % atest_utils.colorize('%s Testable %s modules' % (
len(testable_modules), suite), constants.CYAN))
- print('-------')
+ print(atest_utils.delimiter('-'))
for module in sorted(testable_modules):
print('\t%s' % module)
diff --git a/atest/atest_execution_info.py b/atest/atest_execution_info.py
index 5e8707f..013f308 100644
--- a/atest/atest_execution_info.py
+++ b/atest/atest_execution_info.py
@@ -131,7 +131,7 @@
with open(path) as json_file:
result = json.load(json_file)
print("\natest {}".format(result.get(_ARGS_KEY, '')))
- print('\nTotal Summary:\n--------------')
+ print('\nTotal Summary:\n{}'.format(au.delimiter('-')))
total_summary = result.get(_TOTAL_SUMMARY_KEY, {})
print(', '.join([(k+':'+str(v))
for k, v in total_summary.items()]))
diff --git a/atest/atest_unittests.xml b/atest/atest_unittests.xml
index 689d21d..2f8b3af 100644
--- a/atest/atest_unittests.xml
+++ b/atest/atest_unittests.xml
@@ -14,7 +14,7 @@
<option name="test-suite-tag" value="atest_unittests" />
<test class="com.android.tradefed.testtype.python.PythonBinaryHostTest" >
- <option name="par-file-name" value="atest-py3_unittests" />
+ <option name="par-file-name" value="atest_unittests" />
<option name="test-timeout" value="2m" />
</test>
</configuration>
diff --git a/atest/atest_utils.py b/atest/atest_utils.py
index 9f649a1..d145a14 100644
--- a/atest/atest_utils.py
+++ b/atest/atest_utils.py
@@ -350,7 +350,8 @@
# Determine the width of the terminal. We'll need to clear this many
# characters when carriage returning. Set default value as 80.
columns, rows = shutil.get_terminal_size(
- fallback=(_DEFAULT_TERMINAL_WIDTH, _DEFAULT_TERMINAL_HEIGHT))
+ fallback=(_DEFAULT_TERMINAL_WIDTH,
+ _DEFAULT_TERMINAL_HEIGHT))
return columns, rows
@@ -386,10 +387,10 @@
constants.PRIVACY_POLICY_URL,
constants.TERMS_SERVICE_URL
)
- print('\n==================')
+ print(delimiter('=', 18, prenl=1))
colorful_print("Notice:", constants.RED)
colorful_print("%s" % notice, constants.GREEN)
- print('==================\n')
+ print(delimiter('=', 18, postnl=1))
def handle_test_runner_cmd(input_test, test_cmds, do_verification=False,
@@ -624,3 +625,17 @@
except (OSError, subprocess.CalledProcessError) as err:
logging.debug('Exception raised: %s', err)
return modified_files
+
+def delimiter(char, length=_DEFAULT_TERMINAL_WIDTH, prenl=0, postnl=0):
+ """A handy delimiter printer.
+
+ Args:
+ char: A string used for delimiter.
+ length: An integer for the replication.
+ prenl: An integer that insert '\n' before delimiter.
+ postnl: An integer that insert '\n' after delimiter.
+
+ Returns:
+ A string of delimiter.
+ """
+ return prenl * '\n' + char * length + postnl * '\n'
diff --git a/atest/atest_utils_unittest.py b/atest/atest_utils_unittest.py
index 516e5bb..cfbcad6 100755
--- a/atest/atest_utils_unittest.py
+++ b/atest/atest_utils_unittest.py
@@ -407,5 +407,9 @@
self.assertEqual({'/a/b/test_fp4', '/a/b/test_fp3.java'},
atest_utils.get_modified_files(''))
+ def test_delimiter(self):
+ """Test method delimiter"""
+ self.assertEqual('\n===\n\n', atest_utils.delimiter('=', 3, 1, 2))
+
if __name__ == "__main__":
unittest.main()
diff --git a/atest/constants_default.py b/atest/constants_default.py
index ad9d849..ac902f8 100644
--- a/atest/constants_default.py
+++ b/atest/constants_default.py
@@ -198,9 +198,11 @@
ATEST_TF_MODULE = 'atest-tradefed'
# Build environment variable for each build on ATest
+# With RECORD_ALL_DEPS enabled, ${ANDROID_PRODUCT_OUT}/module-info.json will
+# generate modules' dependencies info when make.
# With SOONG_COLLECT_JAVA_DEPS enabled, out/soong/module_bp_java_deps.json will
# be generated when make.
-ATEST_BUILD_ENV = {'SOONG_COLLECT_JAVA_DEPS':'true'}
+ATEST_BUILD_ENV = {'RECORD_ALL_DEPS':'true', 'SOONG_COLLECT_JAVA_DEPS':'true'}
# Atest index path and relative dirs/caches.
INDEX_DIR = os.path.join(os.getenv(ANDROID_HOST_OUT, ''), 'indexes')
@@ -239,5 +241,11 @@
'vts_linux_kselftest_arm_32',
'vts_linux_kselftest_arm_64',
'vts_linux_kselftest_x86_32',
- 'vts_linux_kselftest_x86_64'
+ 'vts_linux_kselftest_x86_64',
+ 'vts_ltp_test_arm_64_lowmem',
+ 'vts_ltp_test_arm_64_hwasan',
+ 'vts_ltp_test_arm_64_lowmem_hwasan',
+ 'vts_ltp_test_arm_lowmem',
+ 'vts_ltp_test_x86_64',
+ 'vts_ltp_test_x86'
]
diff --git a/atest/result_reporter.py b/atest/result_reporter.py
index 7cc5a5e..2d433a4 100644
--- a/atest/result_reporter.py
+++ b/atest/result_reporter.py
@@ -333,18 +333,23 @@
"""Print starting text for running tests."""
print(au.colorize('\nRunning Tests...', constants.CYAN))
- def print_summary(self):
+ def print_summary(self, is_collect_tests_only=False):
"""Print summary of all test runs.
+ Args:
+ is_collect_tests_only: A boolean of collect_tests_only.
+
Returns:
0 if all tests pass, non-zero otherwise.
"""
+ if is_collect_tests_only:
+ return self.print_collect_tests()
tests_ret = constants.EXIT_CODE_SUCCESS
if not self.runners:
return tests_ret
- print('\n%s' % au.colorize('Summary', constants.CYAN))
- print('-------')
+ print('\n{}'.format(au.colorize('Summary', constants.CYAN)))
+ print(au.delimiter('-', 7))
if self.rerun_options:
print(self.rerun_options)
failed_sum = len(self.failed_tests)
@@ -380,6 +385,28 @@
print('Test Logs have saved in %s' % self.log_path)
return tests_ret
+ def print_collect_tests(self):
+ """Print summary of collect tests only.
+
+ Returns:
+ 0 if all tests collection done.
+
+ """
+ tests_ret = constants.EXIT_CODE_SUCCESS
+ if not self.runners:
+ return tests_ret
+ print('\n{}'.format(au.colorize('Summary:' + constants.COLLECT_TESTS_ONLY,
+ constants.CYAN)))
+ print(au.delimiter('-', 26))
+ for runner_name, groups in self.runners.items():
+ for group_name, _ in groups.items():
+ name = group_name if group_name else runner_name
+ print(name)
+ print()
+ if self.log_path:
+ print('Test Logs have saved in %s' % self.log_path)
+ return constants.EXIT_CODE_SUCCESS
+
def print_failed_tests(self):
"""Print the failed tests if existed."""
if self.failed_tests:
diff --git a/atest/test_runner_handler.py b/atest/test_runner_handler.py
index ee660bf..5229c88 100644
--- a/atest/test_runner_handler.py
+++ b/atest/test_runner_handler.py
@@ -144,4 +144,5 @@
'stacktrace': stacktrace}])
if delay_print_summary:
return tests_ret_code, reporter
- return reporter.print_summary() or tests_ret_code, reporter
+ return (reporter.print_summary(extra_args.get(constants.COLLECT_TESTS_ONLY))
+ or tests_ret_code, reporter)
diff --git a/atest/test_runner_handler_unittest.py b/atest/test_runner_handler_unittest.py
index 87c6caa..ca94405 100755
--- a/atest/test_runner_handler_unittest.py
+++ b/atest/test_runner_handler_unittest.py
@@ -123,7 +123,7 @@
def test_run_all_tests(self, _mock_runner_finish):
"""Test that the return value as we expected."""
results_dir = ""
- extra_args = []
+ extra_args = {}
# Tests both run_tests return 0
test_infos = [MODULE_INFO_A, MODULE_INFO_A_AGAIN]
self.assertEqual(