xref: /aosp_15_r20/external/cronet/build/android/gradle/generate_gradle.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*6777b538SAndroid Build Coastguard Worker# Copyright 2016 The Chromium Authors
3*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
4*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file.
5*6777b538SAndroid Build Coastguard Worker
6*6777b538SAndroid Build Coastguard Worker"""Generates an Android Studio project from a GN target."""
7*6777b538SAndroid Build Coastguard Worker
8*6777b538SAndroid Build Coastguard Workerimport argparse
9*6777b538SAndroid Build Coastguard Workerimport codecs
10*6777b538SAndroid Build Coastguard Workerimport collections
11*6777b538SAndroid Build Coastguard Workerimport glob
12*6777b538SAndroid Build Coastguard Workerimport json
13*6777b538SAndroid Build Coastguard Workerimport logging
14*6777b538SAndroid Build Coastguard Workerimport os
15*6777b538SAndroid Build Coastguard Workerimport pathlib
16*6777b538SAndroid Build Coastguard Workerimport re
17*6777b538SAndroid Build Coastguard Workerimport shlex
18*6777b538SAndroid Build Coastguard Workerimport shutil
19*6777b538SAndroid Build Coastguard Workerimport subprocess
20*6777b538SAndroid Build Coastguard Workerimport sys
21*6777b538SAndroid Build Coastguard Worker
22*6777b538SAndroid Build Coastguard Worker_BUILD_ANDROID = os.path.join(os.path.dirname(__file__), os.pardir)
23*6777b538SAndroid Build Coastguard Workersys.path.append(_BUILD_ANDROID)
24*6777b538SAndroid Build Coastguard Workerimport devil_chromium
25*6777b538SAndroid Build Coastguard Workerfrom devil.utils import run_tests_helper
26*6777b538SAndroid Build Coastguard Workerfrom pylib import constants
27*6777b538SAndroid Build Coastguard Workerfrom pylib.constants import host_paths
28*6777b538SAndroid Build Coastguard Worker
29*6777b538SAndroid Build Coastguard Workersys.path.append(os.path.join(_BUILD_ANDROID, 'gyp'))
30*6777b538SAndroid Build Coastguard Workerimport jinja_template
31*6777b538SAndroid Build Coastguard Workerfrom util import build_utils
32*6777b538SAndroid Build Coastguard Workerfrom util import resource_utils
33*6777b538SAndroid Build Coastguard Worker
34*6777b538SAndroid Build Coastguard Workersys.path.append(os.path.dirname(_BUILD_ANDROID))
35*6777b538SAndroid Build Coastguard Workerimport gn_helpers
36*6777b538SAndroid Build Coastguard Worker
37*6777b538SAndroid Build Coastguard Worker# Typically these should track the versions that works on the slowest release
38*6777b538SAndroid Build Coastguard Worker# channel, i.e. Android Studio stable.
39*6777b538SAndroid Build Coastguard Worker_DEFAULT_ANDROID_GRADLE_PLUGIN_VERSION = '7.3.1'
40*6777b538SAndroid Build Coastguard Worker_DEFAULT_KOTLIN_GRADLE_PLUGIN_VERSION = '1.8.0'
41*6777b538SAndroid Build Coastguard Worker_DEFAULT_GRADLE_WRAPPER_VERSION = '7.4'
42*6777b538SAndroid Build Coastguard Worker
43*6777b538SAndroid Build Coastguard Worker_DEPOT_TOOLS_PATH = os.path.join(host_paths.DIR_SOURCE_ROOT, 'third_party',
44*6777b538SAndroid Build Coastguard Worker                                 'depot_tools')
45*6777b538SAndroid Build Coastguard Worker_DEFAULT_ANDROID_MANIFEST_PATH = os.path.join(
46*6777b538SAndroid Build Coastguard Worker    host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'gradle',
47*6777b538SAndroid Build Coastguard Worker    'AndroidManifest.xml')
48*6777b538SAndroid Build Coastguard Worker_FILE_DIR = os.path.dirname(__file__)
49*6777b538SAndroid Build Coastguard Worker_GENERATED_JAVA_SUBDIR = 'generated_java'
50*6777b538SAndroid Build Coastguard Worker_JNI_LIBS_SUBDIR = 'symlinked-libs'
51*6777b538SAndroid Build Coastguard Worker_ARMEABI_SUBDIR = 'armeabi'
52*6777b538SAndroid Build Coastguard Worker_GRADLE_BUILD_FILE = 'build.gradle'
53*6777b538SAndroid Build Coastguard Worker_CMAKE_FILE = 'CMakeLists.txt'
54*6777b538SAndroid Build Coastguard Worker# This needs to come first alphabetically among all modules.
55*6777b538SAndroid Build Coastguard Worker_MODULE_ALL = '_all'
56*6777b538SAndroid Build Coastguard Worker_INSTRUMENTATION_TARGET_SUFFIX = '_test_apk__test_apk'
57*6777b538SAndroid Build Coastguard Worker
58*6777b538SAndroid Build Coastguard Worker_DEFAULT_TARGETS = [
59*6777b538SAndroid Build Coastguard Worker    '//android_webview/test/embedded_test_server:aw_net_test_support_apk',
60*6777b538SAndroid Build Coastguard Worker    '//android_webview/test:webview_instrumentation_apk',
61*6777b538SAndroid Build Coastguard Worker    '//android_webview/test:webview_instrumentation_test_apk',
62*6777b538SAndroid Build Coastguard Worker    '//base:base_junit_tests',
63*6777b538SAndroid Build Coastguard Worker    '//chrome/android:chrome_junit_tests',
64*6777b538SAndroid Build Coastguard Worker    '//chrome/android:chrome_public_apk',
65*6777b538SAndroid Build Coastguard Worker    '//chrome/android:chrome_public_test_apk',
66*6777b538SAndroid Build Coastguard Worker    '//chrome/android:chrome_public_unit_test_apk',
67*6777b538SAndroid Build Coastguard Worker    '//content/public/android:content_junit_tests',
68*6777b538SAndroid Build Coastguard Worker    '//content/shell/android:content_shell_apk',
69*6777b538SAndroid Build Coastguard Worker    # Below must be included even with --all since they are libraries.
70*6777b538SAndroid Build Coastguard Worker    '//base/android/jni_generator:jni_processor',
71*6777b538SAndroid Build Coastguard Worker    '//tools/android/errorprone_plugin:errorprone_plugin_java',
72*6777b538SAndroid Build Coastguard Worker]
73*6777b538SAndroid Build Coastguard Worker
74*6777b538SAndroid Build Coastguard Worker
75*6777b538SAndroid Build Coastguard Workerdef _TemplatePath(name):
76*6777b538SAndroid Build Coastguard Worker  return os.path.join(_FILE_DIR, '{}.jinja'.format(name))
77*6777b538SAndroid Build Coastguard Worker
78*6777b538SAndroid Build Coastguard Worker
79*6777b538SAndroid Build Coastguard Workerdef _RebasePath(path_or_list, new_cwd=None, old_cwd=None):
80*6777b538SAndroid Build Coastguard Worker  """Makes the given path(s) relative to new_cwd, or absolute if not specified.
81*6777b538SAndroid Build Coastguard Worker
82*6777b538SAndroid Build Coastguard Worker  If new_cwd is not specified, absolute paths are returned.
83*6777b538SAndroid Build Coastguard Worker  If old_cwd is not specified, constants.GetOutDirectory() is assumed.
84*6777b538SAndroid Build Coastguard Worker  """
85*6777b538SAndroid Build Coastguard Worker  if path_or_list is None:
86*6777b538SAndroid Build Coastguard Worker    return []
87*6777b538SAndroid Build Coastguard Worker  if not isinstance(path_or_list, str):
88*6777b538SAndroid Build Coastguard Worker    return [_RebasePath(p, new_cwd, old_cwd) for p in path_or_list]
89*6777b538SAndroid Build Coastguard Worker  if old_cwd is None:
90*6777b538SAndroid Build Coastguard Worker    old_cwd = constants.GetOutDirectory()
91*6777b538SAndroid Build Coastguard Worker  old_cwd = os.path.abspath(old_cwd)
92*6777b538SAndroid Build Coastguard Worker  if new_cwd:
93*6777b538SAndroid Build Coastguard Worker    new_cwd = os.path.abspath(new_cwd)
94*6777b538SAndroid Build Coastguard Worker    return os.path.relpath(os.path.join(old_cwd, path_or_list), new_cwd)
95*6777b538SAndroid Build Coastguard Worker  return os.path.abspath(os.path.join(old_cwd, path_or_list))
96*6777b538SAndroid Build Coastguard Worker
97*6777b538SAndroid Build Coastguard Worker
98*6777b538SAndroid Build Coastguard Workerdef _WriteFile(path, data):
99*6777b538SAndroid Build Coastguard Worker  """Writes |data| to |path|, constucting parent directories if necessary."""
100*6777b538SAndroid Build Coastguard Worker  logging.info('Writing %s', path)
101*6777b538SAndroid Build Coastguard Worker  dirname = os.path.dirname(path)
102*6777b538SAndroid Build Coastguard Worker  if not os.path.exists(dirname):
103*6777b538SAndroid Build Coastguard Worker    os.makedirs(dirname)
104*6777b538SAndroid Build Coastguard Worker  with codecs.open(path, 'w', 'utf-8') as output_file:
105*6777b538SAndroid Build Coastguard Worker    output_file.write(data)
106*6777b538SAndroid Build Coastguard Worker
107*6777b538SAndroid Build Coastguard Worker
108*6777b538SAndroid Build Coastguard Workerdef _RunGnGen(output_dir, args=None):
109*6777b538SAndroid Build Coastguard Worker  cmd = [os.path.join(_DEPOT_TOOLS_PATH, 'gn'), 'gen', output_dir]
110*6777b538SAndroid Build Coastguard Worker  if args:
111*6777b538SAndroid Build Coastguard Worker    cmd.extend(args)
112*6777b538SAndroid Build Coastguard Worker  logging.info('Running: %r', cmd)
113*6777b538SAndroid Build Coastguard Worker  subprocess.check_call(cmd)
114*6777b538SAndroid Build Coastguard Worker
115*6777b538SAndroid Build Coastguard Worker
116*6777b538SAndroid Build Coastguard Workerdef _BuildTargets(output_dir, args):
117*6777b538SAndroid Build Coastguard Worker  cmd = gn_helpers.CreateBuildCommand(output_dir)
118*6777b538SAndroid Build Coastguard Worker  cmd.extend(args)
119*6777b538SAndroid Build Coastguard Worker  logging.info('Running: %s', shlex.join(cmd))
120*6777b538SAndroid Build Coastguard Worker  subprocess.check_call(cmd)
121*6777b538SAndroid Build Coastguard Worker
122*6777b538SAndroid Build Coastguard Worker
123*6777b538SAndroid Build Coastguard Workerdef _QueryForAllGnTargets(output_dir):
124*6777b538SAndroid Build Coastguard Worker  cmd = [
125*6777b538SAndroid Build Coastguard Worker      os.path.join(_BUILD_ANDROID, 'list_java_targets.py'), '--gn-labels',
126*6777b538SAndroid Build Coastguard Worker      '--nested', '--build', '--output-directory', output_dir
127*6777b538SAndroid Build Coastguard Worker  ]
128*6777b538SAndroid Build Coastguard Worker  logging.info('Running: %r', cmd)
129*6777b538SAndroid Build Coastguard Worker  return subprocess.check_output(cmd, encoding='UTF-8').splitlines()
130*6777b538SAndroid Build Coastguard Worker
131*6777b538SAndroid Build Coastguard Worker
132*6777b538SAndroid Build Coastguard Workerclass _ProjectEntry:
133*6777b538SAndroid Build Coastguard Worker  """Helper class for project entries."""
134*6777b538SAndroid Build Coastguard Worker
135*6777b538SAndroid Build Coastguard Worker  _cached_entries = {}
136*6777b538SAndroid Build Coastguard Worker
137*6777b538SAndroid Build Coastguard Worker  def __init__(self, gn_target):
138*6777b538SAndroid Build Coastguard Worker    # Use _ProjectEntry.FromGnTarget instead for caching.
139*6777b538SAndroid Build Coastguard Worker    self._gn_target = gn_target
140*6777b538SAndroid Build Coastguard Worker    self._build_config = None
141*6777b538SAndroid Build Coastguard Worker    self._java_files = None
142*6777b538SAndroid Build Coastguard Worker    self._all_entries = None
143*6777b538SAndroid Build Coastguard Worker    self.android_test_entries = []
144*6777b538SAndroid Build Coastguard Worker
145*6777b538SAndroid Build Coastguard Worker  @classmethod
146*6777b538SAndroid Build Coastguard Worker  def FromGnTarget(cls, gn_target):
147*6777b538SAndroid Build Coastguard Worker    assert gn_target.startswith('//'), gn_target
148*6777b538SAndroid Build Coastguard Worker    if ':' not in gn_target:
149*6777b538SAndroid Build Coastguard Worker      gn_target = '%s:%s' % (gn_target, os.path.basename(gn_target))
150*6777b538SAndroid Build Coastguard Worker    if gn_target not in cls._cached_entries:
151*6777b538SAndroid Build Coastguard Worker      cls._cached_entries[gn_target] = cls(gn_target)
152*6777b538SAndroid Build Coastguard Worker    return cls._cached_entries[gn_target]
153*6777b538SAndroid Build Coastguard Worker
154*6777b538SAndroid Build Coastguard Worker  @classmethod
155*6777b538SAndroid Build Coastguard Worker  def FromBuildConfigPath(cls, path):
156*6777b538SAndroid Build Coastguard Worker    prefix = 'gen/'
157*6777b538SAndroid Build Coastguard Worker    suffix = '.build_config.json'
158*6777b538SAndroid Build Coastguard Worker    assert path.startswith(prefix) and path.endswith(suffix), path
159*6777b538SAndroid Build Coastguard Worker    subdir = path[len(prefix):-len(suffix)]
160*6777b538SAndroid Build Coastguard Worker    gn_target = '//%s:%s' % (os.path.split(subdir))
161*6777b538SAndroid Build Coastguard Worker    return cls.FromGnTarget(gn_target)
162*6777b538SAndroid Build Coastguard Worker
163*6777b538SAndroid Build Coastguard Worker  def __hash__(self):
164*6777b538SAndroid Build Coastguard Worker    return hash(self._gn_target)
165*6777b538SAndroid Build Coastguard Worker
166*6777b538SAndroid Build Coastguard Worker  def __eq__(self, other):
167*6777b538SAndroid Build Coastguard Worker    return self._gn_target == other.GnTarget()
168*6777b538SAndroid Build Coastguard Worker
169*6777b538SAndroid Build Coastguard Worker  def GnTarget(self):
170*6777b538SAndroid Build Coastguard Worker    return self._gn_target
171*6777b538SAndroid Build Coastguard Worker
172*6777b538SAndroid Build Coastguard Worker  def NinjaTarget(self):
173*6777b538SAndroid Build Coastguard Worker    return self._gn_target[2:]
174*6777b538SAndroid Build Coastguard Worker
175*6777b538SAndroid Build Coastguard Worker  def BuildConfigPath(self):
176*6777b538SAndroid Build Coastguard Worker    return os.path.join('gen', self.GradleSubdir() + '.build_config.json')
177*6777b538SAndroid Build Coastguard Worker
178*6777b538SAndroid Build Coastguard Worker  def GradleSubdir(self):
179*6777b538SAndroid Build Coastguard Worker    """Returns the output subdirectory."""
180*6777b538SAndroid Build Coastguard Worker    ninja_target = self.NinjaTarget()
181*6777b538SAndroid Build Coastguard Worker    # Support targets at the root level. e.g. //:foo
182*6777b538SAndroid Build Coastguard Worker    if ninja_target[0] == ':':
183*6777b538SAndroid Build Coastguard Worker      ninja_target = ninja_target[1:]
184*6777b538SAndroid Build Coastguard Worker    return ninja_target.replace(':', os.path.sep)
185*6777b538SAndroid Build Coastguard Worker
186*6777b538SAndroid Build Coastguard Worker  def GeneratedJavaSubdir(self):
187*6777b538SAndroid Build Coastguard Worker    return _RebasePath(
188*6777b538SAndroid Build Coastguard Worker        os.path.join('gen', self.GradleSubdir(), _GENERATED_JAVA_SUBDIR))
189*6777b538SAndroid Build Coastguard Worker
190*6777b538SAndroid Build Coastguard Worker  def ProjectName(self):
191*6777b538SAndroid Build Coastguard Worker    """Returns the Gradle project name."""
192*6777b538SAndroid Build Coastguard Worker    return self.GradleSubdir().replace(os.path.sep, '.')
193*6777b538SAndroid Build Coastguard Worker
194*6777b538SAndroid Build Coastguard Worker  def BuildConfig(self):
195*6777b538SAndroid Build Coastguard Worker    """Reads and returns the project's .build_config.json JSON."""
196*6777b538SAndroid Build Coastguard Worker    if not self._build_config:
197*6777b538SAndroid Build Coastguard Worker      with open(_RebasePath(self.BuildConfigPath())) as jsonfile:
198*6777b538SAndroid Build Coastguard Worker        self._build_config = json.load(jsonfile)
199*6777b538SAndroid Build Coastguard Worker    return self._build_config
200*6777b538SAndroid Build Coastguard Worker
201*6777b538SAndroid Build Coastguard Worker  def DepsInfo(self):
202*6777b538SAndroid Build Coastguard Worker    return self.BuildConfig()['deps_info']
203*6777b538SAndroid Build Coastguard Worker
204*6777b538SAndroid Build Coastguard Worker  def Gradle(self):
205*6777b538SAndroid Build Coastguard Worker    return self.BuildConfig()['gradle']
206*6777b538SAndroid Build Coastguard Worker
207*6777b538SAndroid Build Coastguard Worker  def Javac(self):
208*6777b538SAndroid Build Coastguard Worker    return self.BuildConfig()['javac']
209*6777b538SAndroid Build Coastguard Worker
210*6777b538SAndroid Build Coastguard Worker  def GetType(self):
211*6777b538SAndroid Build Coastguard Worker    """Returns the target type from its .build_config."""
212*6777b538SAndroid Build Coastguard Worker    return self.DepsInfo()['type']
213*6777b538SAndroid Build Coastguard Worker
214*6777b538SAndroid Build Coastguard Worker  def IsValid(self):
215*6777b538SAndroid Build Coastguard Worker    return self.GetType() in (
216*6777b538SAndroid Build Coastguard Worker        'android_apk',
217*6777b538SAndroid Build Coastguard Worker        'android_app_bundle_module',
218*6777b538SAndroid Build Coastguard Worker        'java_library',
219*6777b538SAndroid Build Coastguard Worker        "java_annotation_processor",
220*6777b538SAndroid Build Coastguard Worker        'java_binary',
221*6777b538SAndroid Build Coastguard Worker        'robolectric_binary',
222*6777b538SAndroid Build Coastguard Worker    )
223*6777b538SAndroid Build Coastguard Worker
224*6777b538SAndroid Build Coastguard Worker  def ResSources(self):
225*6777b538SAndroid Build Coastguard Worker    return self.DepsInfo().get('lint_resource_sources', [])
226*6777b538SAndroid Build Coastguard Worker
227*6777b538SAndroid Build Coastguard Worker  def JavaFiles(self):
228*6777b538SAndroid Build Coastguard Worker    if self._java_files is None:
229*6777b538SAndroid Build Coastguard Worker      target_sources_file = self.DepsInfo().get('target_sources_file')
230*6777b538SAndroid Build Coastguard Worker      java_files = []
231*6777b538SAndroid Build Coastguard Worker      if target_sources_file:
232*6777b538SAndroid Build Coastguard Worker        target_sources_file = _RebasePath(target_sources_file)
233*6777b538SAndroid Build Coastguard Worker        java_files = build_utils.ReadSourcesList(target_sources_file)
234*6777b538SAndroid Build Coastguard Worker      self._java_files = java_files
235*6777b538SAndroid Build Coastguard Worker    return self._java_files
236*6777b538SAndroid Build Coastguard Worker
237*6777b538SAndroid Build Coastguard Worker  def PrebuiltJars(self):
238*6777b538SAndroid Build Coastguard Worker    return self.Gradle().get('dependent_prebuilt_jars', [])
239*6777b538SAndroid Build Coastguard Worker
240*6777b538SAndroid Build Coastguard Worker  def AllEntries(self):
241*6777b538SAndroid Build Coastguard Worker    """Returns a list of all entries that the current entry depends on.
242*6777b538SAndroid Build Coastguard Worker
243*6777b538SAndroid Build Coastguard Worker    This includes the entry itself to make iterating simpler."""
244*6777b538SAndroid Build Coastguard Worker    if self._all_entries is None:
245*6777b538SAndroid Build Coastguard Worker      logging.debug('Generating entries for %s', self.GnTarget())
246*6777b538SAndroid Build Coastguard Worker      deps = [_ProjectEntry.FromBuildConfigPath(p)
247*6777b538SAndroid Build Coastguard Worker          for p in self.Gradle()['dependent_android_projects']]
248*6777b538SAndroid Build Coastguard Worker      deps.extend(_ProjectEntry.FromBuildConfigPath(p)
249*6777b538SAndroid Build Coastguard Worker          for p in self.Gradle()['dependent_java_projects'])
250*6777b538SAndroid Build Coastguard Worker      all_entries = set()
251*6777b538SAndroid Build Coastguard Worker      for dep in deps:
252*6777b538SAndroid Build Coastguard Worker        all_entries.update(dep.AllEntries())
253*6777b538SAndroid Build Coastguard Worker      all_entries.add(self)
254*6777b538SAndroid Build Coastguard Worker      self._all_entries = list(all_entries)
255*6777b538SAndroid Build Coastguard Worker    return self._all_entries
256*6777b538SAndroid Build Coastguard Worker
257*6777b538SAndroid Build Coastguard Worker
258*6777b538SAndroid Build Coastguard Workerclass _ProjectContextGenerator:
259*6777b538SAndroid Build Coastguard Worker  """Helper class to generate gradle build files"""
260*6777b538SAndroid Build Coastguard Worker  def __init__(self, project_dir, build_vars, use_gradle_process_resources,
261*6777b538SAndroid Build Coastguard Worker               jinja_processor, split_projects):
262*6777b538SAndroid Build Coastguard Worker    self.project_dir = project_dir
263*6777b538SAndroid Build Coastguard Worker    self.build_vars = build_vars
264*6777b538SAndroid Build Coastguard Worker    self.use_gradle_process_resources = use_gradle_process_resources
265*6777b538SAndroid Build Coastguard Worker    self.jinja_processor = jinja_processor
266*6777b538SAndroid Build Coastguard Worker    self.split_projects = split_projects
267*6777b538SAndroid Build Coastguard Worker    self.processed_java_dirs = set()
268*6777b538SAndroid Build Coastguard Worker    self.processed_prebuilts = set()
269*6777b538SAndroid Build Coastguard Worker    self.processed_res_dirs = set()
270*6777b538SAndroid Build Coastguard Worker
271*6777b538SAndroid Build Coastguard Worker  def _GenJniLibs(self, root_entry):
272*6777b538SAndroid Build Coastguard Worker    libraries = []
273*6777b538SAndroid Build Coastguard Worker    for entry in self._GetEntries(root_entry):
274*6777b538SAndroid Build Coastguard Worker      libraries += entry.BuildConfig().get('native', {}).get('libraries', [])
275*6777b538SAndroid Build Coastguard Worker    if libraries:
276*6777b538SAndroid Build Coastguard Worker      return _CreateJniLibsDir(constants.GetOutDirectory(),
277*6777b538SAndroid Build Coastguard Worker          self.EntryOutputDir(root_entry), libraries)
278*6777b538SAndroid Build Coastguard Worker    return []
279*6777b538SAndroid Build Coastguard Worker
280*6777b538SAndroid Build Coastguard Worker  def _GenJavaDirs(self, root_entry):
281*6777b538SAndroid Build Coastguard Worker    java_files = []
282*6777b538SAndroid Build Coastguard Worker    for entry in self._GetEntries(root_entry):
283*6777b538SAndroid Build Coastguard Worker      java_files += entry.JavaFiles()
284*6777b538SAndroid Build Coastguard Worker    java_dirs, excludes = _ComputeJavaSourceDirsAndExcludes(
285*6777b538SAndroid Build Coastguard Worker        constants.GetOutDirectory(), java_files)
286*6777b538SAndroid Build Coastguard Worker    return java_dirs, excludes
287*6777b538SAndroid Build Coastguard Worker
288*6777b538SAndroid Build Coastguard Worker  def _GenCustomManifest(self, entry):
289*6777b538SAndroid Build Coastguard Worker    """Returns the path to the generated AndroidManifest.xml.
290*6777b538SAndroid Build Coastguard Worker
291*6777b538SAndroid Build Coastguard Worker    Gradle uses package id from manifest when generating R.class. So, we need
292*6777b538SAndroid Build Coastguard Worker    to generate a custom manifest if we let gradle process resources. We cannot
293*6777b538SAndroid Build Coastguard Worker    simply set android.defaultConfig.applicationId because it is not supported
294*6777b538SAndroid Build Coastguard Worker    for library targets."""
295*6777b538SAndroid Build Coastguard Worker    resource_packages = entry.Javac().get('resource_packages')
296*6777b538SAndroid Build Coastguard Worker    if not resource_packages:
297*6777b538SAndroid Build Coastguard Worker      logging.debug(
298*6777b538SAndroid Build Coastguard Worker          'Target %s includes resources from unknown package. '
299*6777b538SAndroid Build Coastguard Worker          'Unable to process with gradle.', entry.GnTarget())
300*6777b538SAndroid Build Coastguard Worker      return _DEFAULT_ANDROID_MANIFEST_PATH
301*6777b538SAndroid Build Coastguard Worker    if len(resource_packages) > 1:
302*6777b538SAndroid Build Coastguard Worker      logging.debug(
303*6777b538SAndroid Build Coastguard Worker          'Target %s includes resources from multiple packages. '
304*6777b538SAndroid Build Coastguard Worker          'Unable to process with gradle.', entry.GnTarget())
305*6777b538SAndroid Build Coastguard Worker      return _DEFAULT_ANDROID_MANIFEST_PATH
306*6777b538SAndroid Build Coastguard Worker
307*6777b538SAndroid Build Coastguard Worker    variables = {'package': resource_packages[0]}
308*6777b538SAndroid Build Coastguard Worker    data = self.jinja_processor.Render(_TemplatePath('manifest'), variables)
309*6777b538SAndroid Build Coastguard Worker    output_file = os.path.join(
310*6777b538SAndroid Build Coastguard Worker        self.EntryOutputDir(entry), 'AndroidManifest.xml')
311*6777b538SAndroid Build Coastguard Worker    _WriteFile(output_file, data)
312*6777b538SAndroid Build Coastguard Worker
313*6777b538SAndroid Build Coastguard Worker    return output_file
314*6777b538SAndroid Build Coastguard Worker
315*6777b538SAndroid Build Coastguard Worker  def _Relativize(self, entry, paths):
316*6777b538SAndroid Build Coastguard Worker    return _RebasePath(paths, self.EntryOutputDir(entry))
317*6777b538SAndroid Build Coastguard Worker
318*6777b538SAndroid Build Coastguard Worker  def _GetEntries(self, entry):
319*6777b538SAndroid Build Coastguard Worker    if self.split_projects:
320*6777b538SAndroid Build Coastguard Worker      return [entry]
321*6777b538SAndroid Build Coastguard Worker    return entry.AllEntries()
322*6777b538SAndroid Build Coastguard Worker
323*6777b538SAndroid Build Coastguard Worker  def EntryOutputDir(self, entry):
324*6777b538SAndroid Build Coastguard Worker    return os.path.join(self.project_dir, entry.GradleSubdir())
325*6777b538SAndroid Build Coastguard Worker
326*6777b538SAndroid Build Coastguard Worker  def GeneratedInputs(self, root_entry):
327*6777b538SAndroid Build Coastguard Worker    generated_inputs = set()
328*6777b538SAndroid Build Coastguard Worker    for entry in self._GetEntries(root_entry):
329*6777b538SAndroid Build Coastguard Worker      generated_inputs.update(entry.PrebuiltJars())
330*6777b538SAndroid Build Coastguard Worker    return generated_inputs
331*6777b538SAndroid Build Coastguard Worker
332*6777b538SAndroid Build Coastguard Worker  def GenerateManifest(self, root_entry):
333*6777b538SAndroid Build Coastguard Worker    android_manifest = root_entry.DepsInfo().get('android_manifest')
334*6777b538SAndroid Build Coastguard Worker    if not android_manifest:
335*6777b538SAndroid Build Coastguard Worker      android_manifest = self._GenCustomManifest(root_entry)
336*6777b538SAndroid Build Coastguard Worker    return self._Relativize(root_entry, android_manifest)
337*6777b538SAndroid Build Coastguard Worker
338*6777b538SAndroid Build Coastguard Worker  def Generate(self, root_entry):
339*6777b538SAndroid Build Coastguard Worker    # TODO(agrieve): Add an option to use interface jars and see if that speeds
340*6777b538SAndroid Build Coastguard Worker    # things up at all.
341*6777b538SAndroid Build Coastguard Worker    variables = {}
342*6777b538SAndroid Build Coastguard Worker    java_dirs, excludes = self._GenJavaDirs(root_entry)
343*6777b538SAndroid Build Coastguard Worker    java_dirs.extend(
344*6777b538SAndroid Build Coastguard Worker        e.GeneratedJavaSubdir() for e in self._GetEntries(root_entry))
345*6777b538SAndroid Build Coastguard Worker    self.processed_java_dirs.update(java_dirs)
346*6777b538SAndroid Build Coastguard Worker    java_dirs.sort()
347*6777b538SAndroid Build Coastguard Worker    variables['java_dirs'] = self._Relativize(root_entry, java_dirs)
348*6777b538SAndroid Build Coastguard Worker    variables['java_excludes'] = excludes
349*6777b538SAndroid Build Coastguard Worker    variables['jni_libs'] = self._Relativize(
350*6777b538SAndroid Build Coastguard Worker        root_entry, set(self._GenJniLibs(root_entry)))
351*6777b538SAndroid Build Coastguard Worker    prebuilts = set(
352*6777b538SAndroid Build Coastguard Worker        p for e in self._GetEntries(root_entry) for p in e.PrebuiltJars())
353*6777b538SAndroid Build Coastguard Worker    self.processed_prebuilts.update(prebuilts)
354*6777b538SAndroid Build Coastguard Worker    variables['prebuilts'] = self._Relativize(root_entry, prebuilts)
355*6777b538SAndroid Build Coastguard Worker    res_sources_files = _RebasePath(
356*6777b538SAndroid Build Coastguard Worker        set(p for e in self._GetEntries(root_entry) for p in e.ResSources()))
357*6777b538SAndroid Build Coastguard Worker    res_sources = []
358*6777b538SAndroid Build Coastguard Worker    for res_sources_file in res_sources_files:
359*6777b538SAndroid Build Coastguard Worker      res_sources.extend(build_utils.ReadSourcesList(res_sources_file))
360*6777b538SAndroid Build Coastguard Worker    res_dirs = resource_utils.DeduceResourceDirsFromFileList(res_sources)
361*6777b538SAndroid Build Coastguard Worker    # Do not add generated resources for the all module since it creates many
362*6777b538SAndroid Build Coastguard Worker    # duplicates, and currently resources are only used for editing.
363*6777b538SAndroid Build Coastguard Worker    self.processed_res_dirs.update(res_dirs)
364*6777b538SAndroid Build Coastguard Worker    variables['res_dirs'] = self._Relativize(root_entry, res_dirs)
365*6777b538SAndroid Build Coastguard Worker    if self.split_projects:
366*6777b538SAndroid Build Coastguard Worker      deps = [_ProjectEntry.FromBuildConfigPath(p)
367*6777b538SAndroid Build Coastguard Worker              for p in root_entry.Gradle()['dependent_android_projects']]
368*6777b538SAndroid Build Coastguard Worker      variables['android_project_deps'] = [d.ProjectName() for d in deps]
369*6777b538SAndroid Build Coastguard Worker      deps = [_ProjectEntry.FromBuildConfigPath(p)
370*6777b538SAndroid Build Coastguard Worker              for p in root_entry.Gradle()['dependent_java_projects']]
371*6777b538SAndroid Build Coastguard Worker      variables['java_project_deps'] = [d.ProjectName() for d in deps]
372*6777b538SAndroid Build Coastguard Worker    return variables
373*6777b538SAndroid Build Coastguard Worker
374*6777b538SAndroid Build Coastguard Worker
375*6777b538SAndroid Build Coastguard Workerdef _ComputeJavaSourceDirs(java_files):
376*6777b538SAndroid Build Coastguard Worker  """Returns a dictionary of source dirs with each given files in one."""
377*6777b538SAndroid Build Coastguard Worker  found_roots = {}
378*6777b538SAndroid Build Coastguard Worker  for path in java_files:
379*6777b538SAndroid Build Coastguard Worker    path_root = path
380*6777b538SAndroid Build Coastguard Worker    # Recognize these tokens as top-level.
381*6777b538SAndroid Build Coastguard Worker    while True:
382*6777b538SAndroid Build Coastguard Worker      path_root = os.path.dirname(path_root)
383*6777b538SAndroid Build Coastguard Worker      basename = os.path.basename(path_root)
384*6777b538SAndroid Build Coastguard Worker      assert basename, 'Failed to find source dir for ' + path
385*6777b538SAndroid Build Coastguard Worker      if basename in ('java', 'src'):
386*6777b538SAndroid Build Coastguard Worker        break
387*6777b538SAndroid Build Coastguard Worker      if basename in ('javax', 'org', 'com'):
388*6777b538SAndroid Build Coastguard Worker        path_root = os.path.dirname(path_root)
389*6777b538SAndroid Build Coastguard Worker        break
390*6777b538SAndroid Build Coastguard Worker    if path_root not in found_roots:
391*6777b538SAndroid Build Coastguard Worker      found_roots[path_root] = []
392*6777b538SAndroid Build Coastguard Worker    found_roots[path_root].append(path)
393*6777b538SAndroid Build Coastguard Worker  return found_roots
394*6777b538SAndroid Build Coastguard Worker
395*6777b538SAndroid Build Coastguard Worker
396*6777b538SAndroid Build Coastguard Workerdef _ComputeExcludeFilters(wanted_files, unwanted_files, parent_dir):
397*6777b538SAndroid Build Coastguard Worker  """Returns exclude patters to exclude unwanted files but keep wanted files.
398*6777b538SAndroid Build Coastguard Worker
399*6777b538SAndroid Build Coastguard Worker  - Shortens exclude list by globbing if possible.
400*6777b538SAndroid Build Coastguard Worker  - Exclude patterns are relative paths from the parent directory.
401*6777b538SAndroid Build Coastguard Worker  """
402*6777b538SAndroid Build Coastguard Worker  excludes = []
403*6777b538SAndroid Build Coastguard Worker  files_to_include = set(wanted_files)
404*6777b538SAndroid Build Coastguard Worker  files_to_exclude = set(unwanted_files)
405*6777b538SAndroid Build Coastguard Worker  while files_to_exclude:
406*6777b538SAndroid Build Coastguard Worker    unwanted_file = files_to_exclude.pop()
407*6777b538SAndroid Build Coastguard Worker    target_exclude = os.path.join(
408*6777b538SAndroid Build Coastguard Worker        os.path.dirname(unwanted_file), '*.java')
409*6777b538SAndroid Build Coastguard Worker    found_files = set(glob.glob(target_exclude))
410*6777b538SAndroid Build Coastguard Worker    valid_files = found_files & files_to_include
411*6777b538SAndroid Build Coastguard Worker    if valid_files:
412*6777b538SAndroid Build Coastguard Worker      excludes.append(os.path.relpath(unwanted_file, parent_dir))
413*6777b538SAndroid Build Coastguard Worker    else:
414*6777b538SAndroid Build Coastguard Worker      excludes.append(os.path.relpath(target_exclude, parent_dir))
415*6777b538SAndroid Build Coastguard Worker      files_to_exclude -= found_files
416*6777b538SAndroid Build Coastguard Worker  return excludes
417*6777b538SAndroid Build Coastguard Worker
418*6777b538SAndroid Build Coastguard Worker
419*6777b538SAndroid Build Coastguard Workerdef _ComputeJavaSourceDirsAndExcludes(output_dir, source_files):
420*6777b538SAndroid Build Coastguard Worker  """Computes the list of java source directories and exclude patterns.
421*6777b538SAndroid Build Coastguard Worker
422*6777b538SAndroid Build Coastguard Worker  This includes both Java and Kotlin files since both are listed in the same
423*6777b538SAndroid Build Coastguard Worker  "java" section for gradle.
424*6777b538SAndroid Build Coastguard Worker
425*6777b538SAndroid Build Coastguard Worker  1. Computes the root source directories from the list of files.
426*6777b538SAndroid Build Coastguard Worker  2. Compute exclude patterns that exclude all extra files only.
427*6777b538SAndroid Build Coastguard Worker  3. Returns the list of source directories and exclude patterns.
428*6777b538SAndroid Build Coastguard Worker  """
429*6777b538SAndroid Build Coastguard Worker  java_dirs = []
430*6777b538SAndroid Build Coastguard Worker  excludes = []
431*6777b538SAndroid Build Coastguard Worker  if source_files:
432*6777b538SAndroid Build Coastguard Worker    source_files = _RebasePath(source_files)
433*6777b538SAndroid Build Coastguard Worker    computed_dirs = _ComputeJavaSourceDirs(source_files)
434*6777b538SAndroid Build Coastguard Worker    java_dirs = list(computed_dirs.keys())
435*6777b538SAndroid Build Coastguard Worker    all_found_source_files = set()
436*6777b538SAndroid Build Coastguard Worker
437*6777b538SAndroid Build Coastguard Worker    for directory, files in computed_dirs.items():
438*6777b538SAndroid Build Coastguard Worker      found_source_files = (build_utils.FindInDirectory(directory, '*.java') +
439*6777b538SAndroid Build Coastguard Worker                            build_utils.FindInDirectory(directory, '*.kt'))
440*6777b538SAndroid Build Coastguard Worker      all_found_source_files.update(found_source_files)
441*6777b538SAndroid Build Coastguard Worker      unwanted_source_files = set(found_source_files) - set(files)
442*6777b538SAndroid Build Coastguard Worker      if unwanted_source_files:
443*6777b538SAndroid Build Coastguard Worker        logging.debug('Directory requires excludes: %s', directory)
444*6777b538SAndroid Build Coastguard Worker        excludes.extend(
445*6777b538SAndroid Build Coastguard Worker            _ComputeExcludeFilters(files, unwanted_source_files, directory))
446*6777b538SAndroid Build Coastguard Worker
447*6777b538SAndroid Build Coastguard Worker    missing_source_files = set(source_files) - all_found_source_files
448*6777b538SAndroid Build Coastguard Worker    # Warn only about non-generated files that are missing.
449*6777b538SAndroid Build Coastguard Worker    missing_source_files = [
450*6777b538SAndroid Build Coastguard Worker        p for p in missing_source_files if not p.startswith(output_dir)
451*6777b538SAndroid Build Coastguard Worker    ]
452*6777b538SAndroid Build Coastguard Worker    if missing_source_files:
453*6777b538SAndroid Build Coastguard Worker      logging.warning('Some source files were not found: %s',
454*6777b538SAndroid Build Coastguard Worker                      missing_source_files)
455*6777b538SAndroid Build Coastguard Worker
456*6777b538SAndroid Build Coastguard Worker  return java_dirs, excludes
457*6777b538SAndroid Build Coastguard Worker
458*6777b538SAndroid Build Coastguard Worker
459*6777b538SAndroid Build Coastguard Workerdef _CreateRelativeSymlink(target_path, link_path):
460*6777b538SAndroid Build Coastguard Worker  link_dir = os.path.dirname(link_path)
461*6777b538SAndroid Build Coastguard Worker  relpath = os.path.relpath(target_path, link_dir)
462*6777b538SAndroid Build Coastguard Worker  logging.debug('Creating symlink %s -> %s', link_path, relpath)
463*6777b538SAndroid Build Coastguard Worker  os.symlink(relpath, link_path)
464*6777b538SAndroid Build Coastguard Worker
465*6777b538SAndroid Build Coastguard Worker
466*6777b538SAndroid Build Coastguard Workerdef _CreateJniLibsDir(output_dir, entry_output_dir, so_files):
467*6777b538SAndroid Build Coastguard Worker  """Creates directory with symlinked .so files if necessary.
468*6777b538SAndroid Build Coastguard Worker
469*6777b538SAndroid Build Coastguard Worker  Returns list of JNI libs directories."""
470*6777b538SAndroid Build Coastguard Worker
471*6777b538SAndroid Build Coastguard Worker  if so_files:
472*6777b538SAndroid Build Coastguard Worker    symlink_dir = os.path.join(entry_output_dir, _JNI_LIBS_SUBDIR)
473*6777b538SAndroid Build Coastguard Worker    shutil.rmtree(symlink_dir, True)
474*6777b538SAndroid Build Coastguard Worker    abi_dir = os.path.join(symlink_dir, _ARMEABI_SUBDIR)
475*6777b538SAndroid Build Coastguard Worker    if not os.path.exists(abi_dir):
476*6777b538SAndroid Build Coastguard Worker      os.makedirs(abi_dir)
477*6777b538SAndroid Build Coastguard Worker    for so_file in so_files:
478*6777b538SAndroid Build Coastguard Worker      target_path = os.path.join(output_dir, so_file)
479*6777b538SAndroid Build Coastguard Worker      symlinked_path = os.path.join(abi_dir, so_file)
480*6777b538SAndroid Build Coastguard Worker      _CreateRelativeSymlink(target_path, symlinked_path)
481*6777b538SAndroid Build Coastguard Worker
482*6777b538SAndroid Build Coastguard Worker    return [symlink_dir]
483*6777b538SAndroid Build Coastguard Worker
484*6777b538SAndroid Build Coastguard Worker  return []
485*6777b538SAndroid Build Coastguard Worker
486*6777b538SAndroid Build Coastguard Worker
487*6777b538SAndroid Build Coastguard Workerdef _ParseVersionFromFile(file_path, version_regex_string, default_version):
488*6777b538SAndroid Build Coastguard Worker  if os.path.exists(file_path):
489*6777b538SAndroid Build Coastguard Worker    content = pathlib.Path(file_path).read_text()
490*6777b538SAndroid Build Coastguard Worker    match = re.search(version_regex_string, content)
491*6777b538SAndroid Build Coastguard Worker    if match:
492*6777b538SAndroid Build Coastguard Worker      version = match.group(1)
493*6777b538SAndroid Build Coastguard Worker      logging.info('Using existing version %s in %s.', version, file_path)
494*6777b538SAndroid Build Coastguard Worker      return version
495*6777b538SAndroid Build Coastguard Worker    logging.warning('Unable to find %s in %s:\n%s', version_regex_string,
496*6777b538SAndroid Build Coastguard Worker                    file_path, content)
497*6777b538SAndroid Build Coastguard Worker  return default_version
498*6777b538SAndroid Build Coastguard Worker
499*6777b538SAndroid Build Coastguard Worker
500*6777b538SAndroid Build Coastguard Workerdef _GenerateLocalProperties(sdk_dir):
501*6777b538SAndroid Build Coastguard Worker  """Returns the data for local.properties as a string."""
502*6777b538SAndroid Build Coastguard Worker  return '\n'.join([
503*6777b538SAndroid Build Coastguard Worker      '# Generated by //build/android/gradle/generate_gradle.py',
504*6777b538SAndroid Build Coastguard Worker      'sdk.dir=%s' % sdk_dir,
505*6777b538SAndroid Build Coastguard Worker      '',
506*6777b538SAndroid Build Coastguard Worker  ])
507*6777b538SAndroid Build Coastguard Worker
508*6777b538SAndroid Build Coastguard Worker
509*6777b538SAndroid Build Coastguard Workerdef _GenerateGradleWrapperProperties(file_path):
510*6777b538SAndroid Build Coastguard Worker  """Returns the data for gradle-wrapper.properties as a string."""
511*6777b538SAndroid Build Coastguard Worker
512*6777b538SAndroid Build Coastguard Worker  version = _ParseVersionFromFile(file_path,
513*6777b538SAndroid Build Coastguard Worker                                  r'/distributions/gradle-([\d.]+)-all.zip',
514*6777b538SAndroid Build Coastguard Worker                                  _DEFAULT_GRADLE_WRAPPER_VERSION)
515*6777b538SAndroid Build Coastguard Worker
516*6777b538SAndroid Build Coastguard Worker  return '\n'.join([
517*6777b538SAndroid Build Coastguard Worker      '# Generated by //build/android/gradle/generate_gradle.py',
518*6777b538SAndroid Build Coastguard Worker      ('distributionUrl=https\\://services.gradle.org'
519*6777b538SAndroid Build Coastguard Worker       f'/distributions/gradle-{version}-all.zip'),
520*6777b538SAndroid Build Coastguard Worker      '',
521*6777b538SAndroid Build Coastguard Worker  ])
522*6777b538SAndroid Build Coastguard Worker
523*6777b538SAndroid Build Coastguard Worker
524*6777b538SAndroid Build Coastguard Workerdef _GenerateGradleProperties():
525*6777b538SAndroid Build Coastguard Worker  """Returns the data for gradle.properties as a string."""
526*6777b538SAndroid Build Coastguard Worker  return '\n'.join([
527*6777b538SAndroid Build Coastguard Worker      '# Generated by //build/android/gradle/generate_gradle.py',
528*6777b538SAndroid Build Coastguard Worker      '',
529*6777b538SAndroid Build Coastguard Worker      '# Tells Gradle to show warnings during project sync.',
530*6777b538SAndroid Build Coastguard Worker      'org.gradle.warning.mode=all',
531*6777b538SAndroid Build Coastguard Worker      '',
532*6777b538SAndroid Build Coastguard Worker  ])
533*6777b538SAndroid Build Coastguard Worker
534*6777b538SAndroid Build Coastguard Worker
535*6777b538SAndroid Build Coastguard Workerdef _GenerateBaseVars(generator, build_vars):
536*6777b538SAndroid Build Coastguard Worker  variables = {}
537*6777b538SAndroid Build Coastguard Worker  # Avoid pre-release SDKs since Studio might not know how to download them.
538*6777b538SAndroid Build Coastguard Worker  variables['compile_sdk_version'] = ('android-%s' %
539*6777b538SAndroid Build Coastguard Worker                                      build_vars['public_android_sdk_version'])
540*6777b538SAndroid Build Coastguard Worker  target_sdk_version = build_vars['public_android_sdk_version']
541*6777b538SAndroid Build Coastguard Worker  if str(target_sdk_version).isalpha():
542*6777b538SAndroid Build Coastguard Worker    target_sdk_version = '"{}"'.format(target_sdk_version)
543*6777b538SAndroid Build Coastguard Worker  variables['target_sdk_version'] = target_sdk_version
544*6777b538SAndroid Build Coastguard Worker  variables['min_sdk_version'] = build_vars['default_min_sdk_version']
545*6777b538SAndroid Build Coastguard Worker  variables['use_gradle_process_resources'] = (
546*6777b538SAndroid Build Coastguard Worker      generator.use_gradle_process_resources)
547*6777b538SAndroid Build Coastguard Worker  return variables
548*6777b538SAndroid Build Coastguard Worker
549*6777b538SAndroid Build Coastguard Worker
550*6777b538SAndroid Build Coastguard Workerdef _GenerateGradleFile(entry, generator, build_vars, jinja_processor):
551*6777b538SAndroid Build Coastguard Worker  """Returns the data for a project's build.gradle."""
552*6777b538SAndroid Build Coastguard Worker  deps_info = entry.DepsInfo()
553*6777b538SAndroid Build Coastguard Worker  variables = _GenerateBaseVars(generator, build_vars)
554*6777b538SAndroid Build Coastguard Worker  sourceSetName = 'main'
555*6777b538SAndroid Build Coastguard Worker
556*6777b538SAndroid Build Coastguard Worker  if deps_info['type'] == 'android_apk':
557*6777b538SAndroid Build Coastguard Worker    target_type = 'android_apk'
558*6777b538SAndroid Build Coastguard Worker  elif deps_info['type'] in ('java_library', 'java_annotation_processor'):
559*6777b538SAndroid Build Coastguard Worker    is_prebuilt = deps_info.get('is_prebuilt', False)
560*6777b538SAndroid Build Coastguard Worker    gradle_treat_as_prebuilt = deps_info.get('gradle_treat_as_prebuilt', False)
561*6777b538SAndroid Build Coastguard Worker    if is_prebuilt or gradle_treat_as_prebuilt:
562*6777b538SAndroid Build Coastguard Worker      return None
563*6777b538SAndroid Build Coastguard Worker    if deps_info['requires_android']:
564*6777b538SAndroid Build Coastguard Worker      target_type = 'android_library'
565*6777b538SAndroid Build Coastguard Worker    else:
566*6777b538SAndroid Build Coastguard Worker      target_type = 'java_library'
567*6777b538SAndroid Build Coastguard Worker  elif deps_info['type'] == 'java_binary':
568*6777b538SAndroid Build Coastguard Worker    target_type = 'java_binary'
569*6777b538SAndroid Build Coastguard Worker    variables['main_class'] = deps_info.get('main_class')
570*6777b538SAndroid Build Coastguard Worker  elif deps_info['type'] == 'robolectric_binary':
571*6777b538SAndroid Build Coastguard Worker    target_type = 'android_junit'
572*6777b538SAndroid Build Coastguard Worker    sourceSetName = 'test'
573*6777b538SAndroid Build Coastguard Worker  else:
574*6777b538SAndroid Build Coastguard Worker    return None
575*6777b538SAndroid Build Coastguard Worker
576*6777b538SAndroid Build Coastguard Worker  variables['target_name'] = os.path.splitext(deps_info['name'])[0]
577*6777b538SAndroid Build Coastguard Worker  variables['template_type'] = target_type
578*6777b538SAndroid Build Coastguard Worker  variables['main'] = {}
579*6777b538SAndroid Build Coastguard Worker  variables[sourceSetName] = generator.Generate(entry)
580*6777b538SAndroid Build Coastguard Worker  variables['main']['android_manifest'] = generator.GenerateManifest(entry)
581*6777b538SAndroid Build Coastguard Worker
582*6777b538SAndroid Build Coastguard Worker  if entry.android_test_entries:
583*6777b538SAndroid Build Coastguard Worker    variables['android_test'] = []
584*6777b538SAndroid Build Coastguard Worker    for e in entry.android_test_entries:
585*6777b538SAndroid Build Coastguard Worker      test_entry = generator.Generate(e)
586*6777b538SAndroid Build Coastguard Worker      test_entry['android_manifest'] = generator.GenerateManifest(e)
587*6777b538SAndroid Build Coastguard Worker      variables['android_test'].append(test_entry)
588*6777b538SAndroid Build Coastguard Worker      for key, value in test_entry.items():
589*6777b538SAndroid Build Coastguard Worker        if isinstance(value, list):
590*6777b538SAndroid Build Coastguard Worker          test_entry[key] = sorted(set(value) - set(variables['main'][key]))
591*6777b538SAndroid Build Coastguard Worker
592*6777b538SAndroid Build Coastguard Worker  return jinja_processor.Render(
593*6777b538SAndroid Build Coastguard Worker      _TemplatePath(target_type.split('_')[0]), variables)
594*6777b538SAndroid Build Coastguard Worker
595*6777b538SAndroid Build Coastguard Worker
596*6777b538SAndroid Build Coastguard Worker# Example: //chrome/android:monochrome
597*6777b538SAndroid Build Coastguard Workerdef _GetNative(relative_func, target_names):
598*6777b538SAndroid Build Coastguard Worker  """Returns an object containing native c++ sources list and its included path
599*6777b538SAndroid Build Coastguard Worker
600*6777b538SAndroid Build Coastguard Worker  Iterate through all target_names and their deps to get the list of included
601*6777b538SAndroid Build Coastguard Worker  paths and sources."""
602*6777b538SAndroid Build Coastguard Worker  out_dir = constants.GetOutDirectory()
603*6777b538SAndroid Build Coastguard Worker  with open(os.path.join(out_dir, 'project.json'), 'r') as project_file:
604*6777b538SAndroid Build Coastguard Worker    projects = json.load(project_file)
605*6777b538SAndroid Build Coastguard Worker  project_targets = projects['targets']
606*6777b538SAndroid Build Coastguard Worker  root_dir = projects['build_settings']['root_path']
607*6777b538SAndroid Build Coastguard Worker  includes = set()
608*6777b538SAndroid Build Coastguard Worker  processed_target = set()
609*6777b538SAndroid Build Coastguard Worker  targets_stack = list(target_names)
610*6777b538SAndroid Build Coastguard Worker  sources = []
611*6777b538SAndroid Build Coastguard Worker
612*6777b538SAndroid Build Coastguard Worker  while targets_stack:
613*6777b538SAndroid Build Coastguard Worker    target_name = targets_stack.pop()
614*6777b538SAndroid Build Coastguard Worker    if target_name in processed_target:
615*6777b538SAndroid Build Coastguard Worker      continue
616*6777b538SAndroid Build Coastguard Worker    processed_target.add(target_name)
617*6777b538SAndroid Build Coastguard Worker    target = project_targets[target_name]
618*6777b538SAndroid Build Coastguard Worker    includes.update(target.get('include_dirs', []))
619*6777b538SAndroid Build Coastguard Worker    targets_stack.extend(target.get('deps', []))
620*6777b538SAndroid Build Coastguard Worker    # Ignore generated files
621*6777b538SAndroid Build Coastguard Worker    sources.extend(f for f in target.get('sources', [])
622*6777b538SAndroid Build Coastguard Worker                   if f.endswith('.cc') and not f.startswith('//out'))
623*6777b538SAndroid Build Coastguard Worker
624*6777b538SAndroid Build Coastguard Worker  def process_paths(paths):
625*6777b538SAndroid Build Coastguard Worker    # Ignores leading //
626*6777b538SAndroid Build Coastguard Worker    return relative_func(
627*6777b538SAndroid Build Coastguard Worker        sorted(os.path.join(root_dir, path[2:]) for path in paths))
628*6777b538SAndroid Build Coastguard Worker
629*6777b538SAndroid Build Coastguard Worker  return {
630*6777b538SAndroid Build Coastguard Worker      'sources': process_paths(sources),
631*6777b538SAndroid Build Coastguard Worker      'includes': process_paths(includes),
632*6777b538SAndroid Build Coastguard Worker  }
633*6777b538SAndroid Build Coastguard Worker
634*6777b538SAndroid Build Coastguard Worker
635*6777b538SAndroid Build Coastguard Workerdef _GenerateModuleAll(gradle_output_dir, generator, build_vars,
636*6777b538SAndroid Build Coastguard Worker                       jinja_processor, native_targets):
637*6777b538SAndroid Build Coastguard Worker  """Returns the data for a pseudo build.gradle of all dirs.
638*6777b538SAndroid Build Coastguard Worker
639*6777b538SAndroid Build Coastguard Worker  See //docs/android_studio.md for more details."""
640*6777b538SAndroid Build Coastguard Worker  variables = _GenerateBaseVars(generator, build_vars)
641*6777b538SAndroid Build Coastguard Worker  target_type = 'android_apk'
642*6777b538SAndroid Build Coastguard Worker  variables['target_name'] = _MODULE_ALL
643*6777b538SAndroid Build Coastguard Worker  variables['template_type'] = target_type
644*6777b538SAndroid Build Coastguard Worker  java_dirs = sorted(generator.processed_java_dirs)
645*6777b538SAndroid Build Coastguard Worker  prebuilts = sorted(generator.processed_prebuilts)
646*6777b538SAndroid Build Coastguard Worker  res_dirs = sorted(generator.processed_res_dirs)
647*6777b538SAndroid Build Coastguard Worker  def Relativize(paths):
648*6777b538SAndroid Build Coastguard Worker    return _RebasePath(paths, os.path.join(gradle_output_dir, _MODULE_ALL))
649*6777b538SAndroid Build Coastguard Worker
650*6777b538SAndroid Build Coastguard Worker  # As after clank modularization, the java and javatests code will live side by
651*6777b538SAndroid Build Coastguard Worker  # side in the same module, we will list both of them in the main target here.
652*6777b538SAndroid Build Coastguard Worker  main_java_dirs = [d for d in java_dirs if 'junit/' not in d]
653*6777b538SAndroid Build Coastguard Worker  junit_test_java_dirs = [d for d in java_dirs if 'junit/' in d]
654*6777b538SAndroid Build Coastguard Worker  variables['main'] = {
655*6777b538SAndroid Build Coastguard Worker      'android_manifest': Relativize(_DEFAULT_ANDROID_MANIFEST_PATH),
656*6777b538SAndroid Build Coastguard Worker      'java_dirs': Relativize(main_java_dirs),
657*6777b538SAndroid Build Coastguard Worker      'prebuilts': Relativize(prebuilts),
658*6777b538SAndroid Build Coastguard Worker      'java_excludes': ['**/*.java', '**/*.kt'],
659*6777b538SAndroid Build Coastguard Worker      'res_dirs': Relativize(res_dirs),
660*6777b538SAndroid Build Coastguard Worker  }
661*6777b538SAndroid Build Coastguard Worker  variables['android_test'] = [{
662*6777b538SAndroid Build Coastguard Worker      'java_dirs': Relativize(junit_test_java_dirs),
663*6777b538SAndroid Build Coastguard Worker      'java_excludes': ['**/*.java', '**/*.kt'],
664*6777b538SAndroid Build Coastguard Worker  }]
665*6777b538SAndroid Build Coastguard Worker  if native_targets:
666*6777b538SAndroid Build Coastguard Worker    variables['native'] = _GetNative(
667*6777b538SAndroid Build Coastguard Worker        relative_func=Relativize, target_names=native_targets)
668*6777b538SAndroid Build Coastguard Worker  data = jinja_processor.Render(
669*6777b538SAndroid Build Coastguard Worker      _TemplatePath(target_type.split('_')[0]), variables)
670*6777b538SAndroid Build Coastguard Worker  _WriteFile(
671*6777b538SAndroid Build Coastguard Worker      os.path.join(gradle_output_dir, _MODULE_ALL, _GRADLE_BUILD_FILE), data)
672*6777b538SAndroid Build Coastguard Worker  if native_targets:
673*6777b538SAndroid Build Coastguard Worker    cmake_data = jinja_processor.Render(_TemplatePath('cmake'), variables)
674*6777b538SAndroid Build Coastguard Worker    _WriteFile(
675*6777b538SAndroid Build Coastguard Worker        os.path.join(gradle_output_dir, _MODULE_ALL, _CMAKE_FILE), cmake_data)
676*6777b538SAndroid Build Coastguard Worker
677*6777b538SAndroid Build Coastguard Worker
678*6777b538SAndroid Build Coastguard Workerdef _GenerateRootGradle(jinja_processor, file_path):
679*6777b538SAndroid Build Coastguard Worker  """Returns the data for the root project's build.gradle."""
680*6777b538SAndroid Build Coastguard Worker  android_gradle_plugin_version = _ParseVersionFromFile(
681*6777b538SAndroid Build Coastguard Worker      file_path, r'com.android.tools.build:gradle:([\d.]+)',
682*6777b538SAndroid Build Coastguard Worker      _DEFAULT_ANDROID_GRADLE_PLUGIN_VERSION)
683*6777b538SAndroid Build Coastguard Worker  kotlin_gradle_plugin_version = _ParseVersionFromFile(
684*6777b538SAndroid Build Coastguard Worker      file_path, r'org.jetbrains.kotlin:kotlin-gradle-plugin:([\d.]+)',
685*6777b538SAndroid Build Coastguard Worker      _DEFAULT_KOTLIN_GRADLE_PLUGIN_VERSION)
686*6777b538SAndroid Build Coastguard Worker
687*6777b538SAndroid Build Coastguard Worker  return jinja_processor.Render(
688*6777b538SAndroid Build Coastguard Worker      _TemplatePath('root'), {
689*6777b538SAndroid Build Coastguard Worker          'android_gradle_plugin_version': android_gradle_plugin_version,
690*6777b538SAndroid Build Coastguard Worker          'kotlin_gradle_plugin_version': kotlin_gradle_plugin_version,
691*6777b538SAndroid Build Coastguard Worker      })
692*6777b538SAndroid Build Coastguard Worker
693*6777b538SAndroid Build Coastguard Worker
694*6777b538SAndroid Build Coastguard Workerdef _GenerateSettingsGradle(project_entries):
695*6777b538SAndroid Build Coastguard Worker  """Returns the data for settings.gradle."""
696*6777b538SAndroid Build Coastguard Worker  project_name = os.path.basename(os.path.dirname(host_paths.DIR_SOURCE_ROOT))
697*6777b538SAndroid Build Coastguard Worker  lines = []
698*6777b538SAndroid Build Coastguard Worker  lines.append('// Generated by //build/android/gradle/generate_gradle.py')
699*6777b538SAndroid Build Coastguard Worker  lines.append('rootProject.name = "%s"' % project_name)
700*6777b538SAndroid Build Coastguard Worker  lines.append('rootProject.projectDir = settingsDir')
701*6777b538SAndroid Build Coastguard Worker  lines.append('')
702*6777b538SAndroid Build Coastguard Worker  for name, subdir in project_entries:
703*6777b538SAndroid Build Coastguard Worker    # Example target:
704*6777b538SAndroid Build Coastguard Worker    # android_webview:android_webview_java__build_config_crbug_908819
705*6777b538SAndroid Build Coastguard Worker    lines.append('include ":%s"' % name)
706*6777b538SAndroid Build Coastguard Worker    lines.append('project(":%s").projectDir = new File(settingsDir, "%s")' %
707*6777b538SAndroid Build Coastguard Worker                 (name, subdir))
708*6777b538SAndroid Build Coastguard Worker  return '\n'.join(lines)
709*6777b538SAndroid Build Coastguard Worker
710*6777b538SAndroid Build Coastguard Worker
711*6777b538SAndroid Build Coastguard Workerdef _FindAllProjectEntries(main_entries):
712*6777b538SAndroid Build Coastguard Worker  """Returns the list of all _ProjectEntry instances given the root project."""
713*6777b538SAndroid Build Coastguard Worker  found = set()
714*6777b538SAndroid Build Coastguard Worker  to_scan = list(main_entries)
715*6777b538SAndroid Build Coastguard Worker  while to_scan:
716*6777b538SAndroid Build Coastguard Worker    cur_entry = to_scan.pop()
717*6777b538SAndroid Build Coastguard Worker    if cur_entry in found:
718*6777b538SAndroid Build Coastguard Worker      continue
719*6777b538SAndroid Build Coastguard Worker    found.add(cur_entry)
720*6777b538SAndroid Build Coastguard Worker    sub_config_paths = cur_entry.DepsInfo()['deps_configs']
721*6777b538SAndroid Build Coastguard Worker    to_scan.extend(
722*6777b538SAndroid Build Coastguard Worker        _ProjectEntry.FromBuildConfigPath(p) for p in sub_config_paths)
723*6777b538SAndroid Build Coastguard Worker  return list(found)
724*6777b538SAndroid Build Coastguard Worker
725*6777b538SAndroid Build Coastguard Worker
726*6777b538SAndroid Build Coastguard Workerdef _CombineTestEntries(entries):
727*6777b538SAndroid Build Coastguard Worker  """Combines test apks into the androidTest source set of their target.
728*6777b538SAndroid Build Coastguard Worker
729*6777b538SAndroid Build Coastguard Worker  - Speeds up android studio
730*6777b538SAndroid Build Coastguard Worker  - Adds proper dependency between test and apk_under_test
731*6777b538SAndroid Build Coastguard Worker  - Doesn't work for junit yet due to resulting circular dependencies
732*6777b538SAndroid Build Coastguard Worker    - e.g. base_junit_tests > base_junit_test_support > base_java
733*6777b538SAndroid Build Coastguard Worker  """
734*6777b538SAndroid Build Coastguard Worker  combined_entries = []
735*6777b538SAndroid Build Coastguard Worker  android_test_entries = collections.defaultdict(list)
736*6777b538SAndroid Build Coastguard Worker  for entry in entries:
737*6777b538SAndroid Build Coastguard Worker    target_name = entry.GnTarget()
738*6777b538SAndroid Build Coastguard Worker    if (target_name.endswith(_INSTRUMENTATION_TARGET_SUFFIX)
739*6777b538SAndroid Build Coastguard Worker        and 'apk_under_test' in entry.Gradle()):
740*6777b538SAndroid Build Coastguard Worker      apk_name = entry.Gradle()['apk_under_test']
741*6777b538SAndroid Build Coastguard Worker      android_test_entries[apk_name].append(entry)
742*6777b538SAndroid Build Coastguard Worker    else:
743*6777b538SAndroid Build Coastguard Worker      combined_entries.append(entry)
744*6777b538SAndroid Build Coastguard Worker  for entry in combined_entries:
745*6777b538SAndroid Build Coastguard Worker    target_name = entry.DepsInfo()['name']
746*6777b538SAndroid Build Coastguard Worker    if target_name in android_test_entries:
747*6777b538SAndroid Build Coastguard Worker      entry.android_test_entries = android_test_entries[target_name]
748*6777b538SAndroid Build Coastguard Worker      del android_test_entries[target_name]
749*6777b538SAndroid Build Coastguard Worker  # Add unmatched test entries as individual targets.
750*6777b538SAndroid Build Coastguard Worker  combined_entries.extend(e for l in android_test_entries.values() for e in l)
751*6777b538SAndroid Build Coastguard Worker  return combined_entries
752*6777b538SAndroid Build Coastguard Worker
753*6777b538SAndroid Build Coastguard Worker
754*6777b538SAndroid Build Coastguard Workerdef main():
755*6777b538SAndroid Build Coastguard Worker  parser = argparse.ArgumentParser()
756*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--output-directory',
757*6777b538SAndroid Build Coastguard Worker                      help='Path to the root build directory.')
758*6777b538SAndroid Build Coastguard Worker  parser.add_argument('-v',
759*6777b538SAndroid Build Coastguard Worker                      '--verbose',
760*6777b538SAndroid Build Coastguard Worker                      dest='verbose_count',
761*6777b538SAndroid Build Coastguard Worker                      default=0,
762*6777b538SAndroid Build Coastguard Worker                      action='count',
763*6777b538SAndroid Build Coastguard Worker                      help='Verbose level')
764*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--target',
765*6777b538SAndroid Build Coastguard Worker                      dest='targets',
766*6777b538SAndroid Build Coastguard Worker                      action='append',
767*6777b538SAndroid Build Coastguard Worker                      help='GN target to generate project for. Replaces set of '
768*6777b538SAndroid Build Coastguard Worker                           'default targets. May be repeated.')
769*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--extra-target',
770*6777b538SAndroid Build Coastguard Worker                      dest='extra_targets',
771*6777b538SAndroid Build Coastguard Worker                      action='append',
772*6777b538SAndroid Build Coastguard Worker                      help='GN target to generate project for, in addition to '
773*6777b538SAndroid Build Coastguard Worker                           'the default ones. May be repeated.')
774*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--project-dir',
775*6777b538SAndroid Build Coastguard Worker                      help='Root of the output project.',
776*6777b538SAndroid Build Coastguard Worker                      default=os.path.join('$CHROMIUM_OUTPUT_DIR', 'gradle'))
777*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--all',
778*6777b538SAndroid Build Coastguard Worker                      action='store_true',
779*6777b538SAndroid Build Coastguard Worker                      help='Include all .java files reachable from any '
780*6777b538SAndroid Build Coastguard Worker                           'apk/test/binary target. On by default unless '
781*6777b538SAndroid Build Coastguard Worker                           '--split-projects is used (--split-projects can '
782*6777b538SAndroid Build Coastguard Worker                           'slow down Studio given too many targets).')
783*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--use-gradle-process-resources',
784*6777b538SAndroid Build Coastguard Worker                      action='store_true',
785*6777b538SAndroid Build Coastguard Worker                      help='Have gradle generate R.java rather than ninja')
786*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--split-projects',
787*6777b538SAndroid Build Coastguard Worker                      action='store_true',
788*6777b538SAndroid Build Coastguard Worker                      help='Split projects by their gn deps rather than '
789*6777b538SAndroid Build Coastguard Worker                           'combining all the dependencies of each target')
790*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--native-target',
791*6777b538SAndroid Build Coastguard Worker                      dest='native_targets',
792*6777b538SAndroid Build Coastguard Worker                      action='append',
793*6777b538SAndroid Build Coastguard Worker                      help='GN native targets to generate for. May be '
794*6777b538SAndroid Build Coastguard Worker                           'repeated.')
795*6777b538SAndroid Build Coastguard Worker  parser.add_argument(
796*6777b538SAndroid Build Coastguard Worker      '--sdk-path',
797*6777b538SAndroid Build Coastguard Worker      default=os.path.expanduser('~/Android/Sdk'),
798*6777b538SAndroid Build Coastguard Worker      help='The path to use as the SDK root, overrides the '
799*6777b538SAndroid Build Coastguard Worker      'default at ~/Android/Sdk.')
800*6777b538SAndroid Build Coastguard Worker  args = parser.parse_args()
801*6777b538SAndroid Build Coastguard Worker  if args.output_directory:
802*6777b538SAndroid Build Coastguard Worker    constants.SetOutputDirectory(args.output_directory)
803*6777b538SAndroid Build Coastguard Worker  constants.CheckOutputDirectory()
804*6777b538SAndroid Build Coastguard Worker  output_dir = constants.GetOutDirectory()
805*6777b538SAndroid Build Coastguard Worker  devil_chromium.Initialize(output_directory=output_dir)
806*6777b538SAndroid Build Coastguard Worker  run_tests_helper.SetLogLevel(args.verbose_count)
807*6777b538SAndroid Build Coastguard Worker
808*6777b538SAndroid Build Coastguard Worker  if args.use_gradle_process_resources:
809*6777b538SAndroid Build Coastguard Worker    assert args.split_projects, (
810*6777b538SAndroid Build Coastguard Worker        'Gradle resources does not work without --split-projects.')
811*6777b538SAndroid Build Coastguard Worker
812*6777b538SAndroid Build Coastguard Worker  _gradle_output_dir = os.path.abspath(
813*6777b538SAndroid Build Coastguard Worker      args.project_dir.replace('$CHROMIUM_OUTPUT_DIR', output_dir))
814*6777b538SAndroid Build Coastguard Worker  logging.warning('Creating project at: %s', _gradle_output_dir)
815*6777b538SAndroid Build Coastguard Worker
816*6777b538SAndroid Build Coastguard Worker  # Generate for "all targets" by default when not using --split-projects (too
817*6777b538SAndroid Build Coastguard Worker  # slow), and when no --target has been explicitly set. "all targets" means all
818*6777b538SAndroid Build Coastguard Worker  # java targets that are depended on by an apk or java_binary (leaf
819*6777b538SAndroid Build Coastguard Worker  # java_library targets will not be included).
820*6777b538SAndroid Build Coastguard Worker  args.all = args.all or (not args.split_projects and not args.targets)
821*6777b538SAndroid Build Coastguard Worker
822*6777b538SAndroid Build Coastguard Worker  targets_from_args = set(args.targets or _DEFAULT_TARGETS)
823*6777b538SAndroid Build Coastguard Worker  if args.extra_targets:
824*6777b538SAndroid Build Coastguard Worker    targets_from_args.update(args.extra_targets)
825*6777b538SAndroid Build Coastguard Worker
826*6777b538SAndroid Build Coastguard Worker  if args.all:
827*6777b538SAndroid Build Coastguard Worker    if args.native_targets:
828*6777b538SAndroid Build Coastguard Worker      _RunGnGen(output_dir, ['--ide=json'])
829*6777b538SAndroid Build Coastguard Worker    elif not os.path.exists(os.path.join(output_dir, 'build.ninja')):
830*6777b538SAndroid Build Coastguard Worker      _RunGnGen(output_dir)
831*6777b538SAndroid Build Coastguard Worker    else:
832*6777b538SAndroid Build Coastguard Worker      # Faster than running "gn gen" in the no-op case.
833*6777b538SAndroid Build Coastguard Worker      _BuildTargets(output_dir, ['build.ninja'])
834*6777b538SAndroid Build Coastguard Worker    # Query ninja for all __build_config_crbug_908819 targets.
835*6777b538SAndroid Build Coastguard Worker    targets = _QueryForAllGnTargets(output_dir)
836*6777b538SAndroid Build Coastguard Worker  else:
837*6777b538SAndroid Build Coastguard Worker    assert not args.native_targets, 'Native editing requires --all.'
838*6777b538SAndroid Build Coastguard Worker    targets = [
839*6777b538SAndroid Build Coastguard Worker        re.sub(r'_test_apk$', _INSTRUMENTATION_TARGET_SUFFIX, t)
840*6777b538SAndroid Build Coastguard Worker        for t in targets_from_args
841*6777b538SAndroid Build Coastguard Worker    ]
842*6777b538SAndroid Build Coastguard Worker    # Necessary after "gn clean"
843*6777b538SAndroid Build Coastguard Worker    if not os.path.exists(
844*6777b538SAndroid Build Coastguard Worker        os.path.join(output_dir, gn_helpers.BUILD_VARS_FILENAME)):
845*6777b538SAndroid Build Coastguard Worker      _RunGnGen(output_dir)
846*6777b538SAndroid Build Coastguard Worker
847*6777b538SAndroid Build Coastguard Worker  main_entries = [_ProjectEntry.FromGnTarget(t) for t in targets]
848*6777b538SAndroid Build Coastguard Worker  if not args.all:
849*6777b538SAndroid Build Coastguard Worker    # list_java_targets.py takes care of building .build_config.json in the
850*6777b538SAndroid Build Coastguard Worker    # --all case.
851*6777b538SAndroid Build Coastguard Worker    _BuildTargets(output_dir, [t.BuildConfigPath() for t in main_entries])
852*6777b538SAndroid Build Coastguard Worker
853*6777b538SAndroid Build Coastguard Worker  build_vars = gn_helpers.ReadBuildVars(output_dir)
854*6777b538SAndroid Build Coastguard Worker  jinja_processor = jinja_template.JinjaProcessor(_FILE_DIR)
855*6777b538SAndroid Build Coastguard Worker  generator = _ProjectContextGenerator(_gradle_output_dir, build_vars,
856*6777b538SAndroid Build Coastguard Worker                                       args.use_gradle_process_resources,
857*6777b538SAndroid Build Coastguard Worker                                       jinja_processor, args.split_projects)
858*6777b538SAndroid Build Coastguard Worker
859*6777b538SAndroid Build Coastguard Worker  if args.all:
860*6777b538SAndroid Build Coastguard Worker    # There are many unused libraries, so restrict to those that are actually
861*6777b538SAndroid Build Coastguard Worker    # used by apks/bundles/binaries/tests or that are explicitly mentioned in
862*6777b538SAndroid Build Coastguard Worker    # --targets.
863*6777b538SAndroid Build Coastguard Worker    BASE_TYPES = ('android_apk', 'android_app_bundle_module', 'java_binary',
864*6777b538SAndroid Build Coastguard Worker                  'robolectric_binary')
865*6777b538SAndroid Build Coastguard Worker    main_entries = [
866*6777b538SAndroid Build Coastguard Worker        e for e in main_entries
867*6777b538SAndroid Build Coastguard Worker        if (e.GetType() in BASE_TYPES or e.GnTarget() in targets_from_args
868*6777b538SAndroid Build Coastguard Worker            or e.GnTarget().endswith(_INSTRUMENTATION_TARGET_SUFFIX))
869*6777b538SAndroid Build Coastguard Worker    ]
870*6777b538SAndroid Build Coastguard Worker
871*6777b538SAndroid Build Coastguard Worker  if args.split_projects:
872*6777b538SAndroid Build Coastguard Worker    main_entries = _FindAllProjectEntries(main_entries)
873*6777b538SAndroid Build Coastguard Worker
874*6777b538SAndroid Build Coastguard Worker  logging.info('Generating for %d targets.', len(main_entries))
875*6777b538SAndroid Build Coastguard Worker
876*6777b538SAndroid Build Coastguard Worker  entries = [e for e in _CombineTestEntries(main_entries) if e.IsValid()]
877*6777b538SAndroid Build Coastguard Worker  logging.info('Creating %d projects for targets.', len(entries))
878*6777b538SAndroid Build Coastguard Worker
879*6777b538SAndroid Build Coastguard Worker  logging.warning('Writing .gradle files...')
880*6777b538SAndroid Build Coastguard Worker  project_entries = []
881*6777b538SAndroid Build Coastguard Worker  # When only one entry will be generated we want it to have a valid
882*6777b538SAndroid Build Coastguard Worker  # build.gradle file with its own AndroidManifest.
883*6777b538SAndroid Build Coastguard Worker  for entry in entries:
884*6777b538SAndroid Build Coastguard Worker    data = _GenerateGradleFile(entry, generator, build_vars, jinja_processor)
885*6777b538SAndroid Build Coastguard Worker    if data and not args.all:
886*6777b538SAndroid Build Coastguard Worker      project_entries.append((entry.ProjectName(), entry.GradleSubdir()))
887*6777b538SAndroid Build Coastguard Worker      _WriteFile(
888*6777b538SAndroid Build Coastguard Worker          os.path.join(generator.EntryOutputDir(entry), _GRADLE_BUILD_FILE),
889*6777b538SAndroid Build Coastguard Worker          data)
890*6777b538SAndroid Build Coastguard Worker  if args.all:
891*6777b538SAndroid Build Coastguard Worker    project_entries.append((_MODULE_ALL, _MODULE_ALL))
892*6777b538SAndroid Build Coastguard Worker    _GenerateModuleAll(_gradle_output_dir, generator, build_vars,
893*6777b538SAndroid Build Coastguard Worker                       jinja_processor, args.native_targets)
894*6777b538SAndroid Build Coastguard Worker
895*6777b538SAndroid Build Coastguard Worker  root_gradle_path = os.path.join(generator.project_dir, _GRADLE_BUILD_FILE)
896*6777b538SAndroid Build Coastguard Worker  _WriteFile(root_gradle_path,
897*6777b538SAndroid Build Coastguard Worker             _GenerateRootGradle(jinja_processor, root_gradle_path))
898*6777b538SAndroid Build Coastguard Worker
899*6777b538SAndroid Build Coastguard Worker  _WriteFile(os.path.join(generator.project_dir, 'settings.gradle'),
900*6777b538SAndroid Build Coastguard Worker             _GenerateSettingsGradle(project_entries))
901*6777b538SAndroid Build Coastguard Worker
902*6777b538SAndroid Build Coastguard Worker  # Ensure the Android Studio sdk is correctly initialized.
903*6777b538SAndroid Build Coastguard Worker  if not os.path.exists(args.sdk_path):
904*6777b538SAndroid Build Coastguard Worker    # Help first-time users avoid Android Studio forcibly changing back to
905*6777b538SAndroid Build Coastguard Worker    # the previous default due to not finding a valid sdk under this dir.
906*6777b538SAndroid Build Coastguard Worker    shutil.copytree(_RebasePath(build_vars['android_sdk_root']), args.sdk_path)
907*6777b538SAndroid Build Coastguard Worker  _WriteFile(
908*6777b538SAndroid Build Coastguard Worker      os.path.join(generator.project_dir, 'local.properties'),
909*6777b538SAndroid Build Coastguard Worker      _GenerateLocalProperties(args.sdk_path))
910*6777b538SAndroid Build Coastguard Worker  _WriteFile(os.path.join(generator.project_dir, 'gradle.properties'),
911*6777b538SAndroid Build Coastguard Worker             _GenerateGradleProperties())
912*6777b538SAndroid Build Coastguard Worker
913*6777b538SAndroid Build Coastguard Worker  wrapper_properties = os.path.join(generator.project_dir, 'gradle', 'wrapper',
914*6777b538SAndroid Build Coastguard Worker                                    'gradle-wrapper.properties')
915*6777b538SAndroid Build Coastguard Worker  _WriteFile(wrapper_properties,
916*6777b538SAndroid Build Coastguard Worker             _GenerateGradleWrapperProperties(wrapper_properties))
917*6777b538SAndroid Build Coastguard Worker
918*6777b538SAndroid Build Coastguard Worker  generated_inputs = set()
919*6777b538SAndroid Build Coastguard Worker  for entry in entries:
920*6777b538SAndroid Build Coastguard Worker    entries_to_gen = [entry]
921*6777b538SAndroid Build Coastguard Worker    entries_to_gen.extend(entry.android_test_entries)
922*6777b538SAndroid Build Coastguard Worker    for entry_to_gen in entries_to_gen:
923*6777b538SAndroid Build Coastguard Worker      # Build all paths references by .gradle that exist within output_dir.
924*6777b538SAndroid Build Coastguard Worker      generated_inputs.update(generator.GeneratedInputs(entry_to_gen))
925*6777b538SAndroid Build Coastguard Worker  if generated_inputs:
926*6777b538SAndroid Build Coastguard Worker    # Skip targets outside the output_dir since those are not generated.
927*6777b538SAndroid Build Coastguard Worker    targets = [
928*6777b538SAndroid Build Coastguard Worker        p for p in _RebasePath(generated_inputs, output_dir)
929*6777b538SAndroid Build Coastguard Worker        if not p.startswith(os.pardir)
930*6777b538SAndroid Build Coastguard Worker    ]
931*6777b538SAndroid Build Coastguard Worker    _BuildTargets(output_dir, targets)
932*6777b538SAndroid Build Coastguard Worker
933*6777b538SAndroid Build Coastguard Worker  print('Generated projects for Android Studio.')
934*6777b538SAndroid Build Coastguard Worker  print('** Building using Android Studio / Gradle does not work.')
935*6777b538SAndroid Build Coastguard Worker  print('** This project is only for IDE editing & tools.')
936*6777b538SAndroid Build Coastguard Worker  print('Note: Generated files will appear only if they have been built')
937*6777b538SAndroid Build Coastguard Worker  print('For more tips: https://chromium.googlesource.com/chromium/src.git/'
938*6777b538SAndroid Build Coastguard Worker        '+/main/docs/android_studio.md')
939*6777b538SAndroid Build Coastguard Worker
940*6777b538SAndroid Build Coastguard Worker
941*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__':
942*6777b538SAndroid Build Coastguard Worker  main()
943