Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(921)

Unified Diff: build/android/gradle/generate_gradle.py

Issue 2697313004: Android: Cache android studio project entries (Closed)
Patch Set: Rebase and avoid error logs Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « build/android/gradle/android.jinja ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: build/android/gradle/generate_gradle.py
diff --git a/build/android/gradle/generate_gradle.py b/build/android/gradle/generate_gradle.py
index 2b529f0b6e30206e53bff013ffc1ac2b97945b84..8b6577839a005a3370b6d93cbdee63568aa1c730 100755
--- a/build/android/gradle/generate_gradle.py
+++ b/build/android/gradle/generate_gradle.py
@@ -117,39 +117,67 @@ def _QueryForAllGnTargets(output_dir):
return ret
+def _Dedup(entries):
agrieve 2017/02/17 03:07:01 nit: this doesn't save any lines over just calling
Peter Wen 2017/02/17 16:37:26 Done.
+ """Return unique entries in iterable in the same order."""
+ return _DedupAgainst(entries, [])
+
+
+def _DedupAgainst(entries, existing_entries):
+ """Return unique entries in iterable given existing entries."""
agrieve 2017/02/17 03:07:01 You return a list, so I'd say that rather than ite
Peter Wen 2017/02/17 16:37:26 Done.
+ seen = set(existing_entries)
+ unique_entries = []
+ for entry in entries:
+ if entry not in seen:
+ unique_entries.append(entry)
+ seen.add(entry)
+ return unique_entries
+
+
class _ProjectEntry(object):
"""Helper class for project entries."""
+
+ _cached_entries = {}
+
def __init__(self, gn_target):
- assert gn_target.startswith('//'), gn_target
- if ':' not in gn_target:
- gn_target = '%s:%s' % (gn_target, os.path.basename(gn_target))
+ # Use _ProjectEntry.FromGnTarget instead for caching.
self._gn_target = gn_target
self._build_config = None
self._java_files = None
+ self._all_entries = None
self.android_test_entry = None
@classmethod
+ def FromGnTarget(cls, gn_target):
+ assert gn_target.startswith('//'), gn_target
+ if ':' not in gn_target:
+ gn_target = '%s:%s' % (gn_target, os.path.basename(gn_target))
+ if gn_target not in cls._cached_entries:
+ cls._cached_entries[gn_target] = cls(gn_target)
+ return cls._cached_entries[gn_target]
+
+ @classmethod
def FromBuildConfigPath(cls, path):
prefix = 'gen/'
suffix = '.build_config'
assert path.startswith(prefix) and path.endswith(suffix), path
subdir = path[len(prefix):-len(suffix)]
- return cls('//%s:%s' % (os.path.split(subdir)))
+ gn_target = '//%s:%s' % (os.path.split(subdir))
+ return cls.FromGnTarget(gn_target)
def __hash__(self):
- return hash(self._gn_target)
+ return hash(self.GnTarget())
agrieve 2017/02/17 03:07:01 nit: I think it's generally better to leave these
Peter Wen 2017/02/17 16:37:25 Done. We don't do any checks/calculations in the
def __eq__(self, other):
- return self._gn_target == other.GnTarget()
+ return self.GnTarget() == other.GnTarget()
def GnTarget(self):
return self._gn_target
def NinjaTarget(self):
- return self._gn_target[2:]
+ return self.GnTarget()[2:]
def GnBuildConfigTarget(self):
- return '%s__build_config' % self._gn_target
+ return '%s__build_config' % self.GnTarget()
def NinjaBuildConfigTarget(self):
return '%s__build_config' % self.NinjaTarget()
@@ -195,6 +223,26 @@ class _ProjectEntry(object):
self._java_files = java_files
return self._java_files
+ def SubdirJavaFiles(self):
agrieve 2017/02/17 03:07:01 Is this the same as saying generated java files? I
Peter Wen 2017/02/17 16:37:25 Done.
+ return [p for p in self.JavaFiles() if not p.startswith('..')]
+
+ def PrebuiltJars(self):
+ return self.Gradle()['dependent_prebuilt_jars']
+
+ def AllEntries(self):
agrieve 2017/02/17 03:07:01 This is worth adding pydoc for.
Peter Wen 2017/02/17 16:37:26 Done.
+ if self._all_entries is None:
+ logging.debug('Generating entries for %s', self.GnTarget())
+ deps = [_ProjectEntry.FromBuildConfigPath(p)
+ for p in self.Gradle()['dependent_android_projects']]
+ deps.extend([_ProjectEntry.FromBuildConfigPath(p)
agrieve 2017/02/17 03:07:01 nit: shouldn't need the [].
Peter Wen 2017/02/17 16:37:26 Done.
+ for p in self.Gradle()['dependent_java_projects']])
+ all_entries = []
+ for dep in deps:
+ all_entries += dep.AllEntries()
agrieve 2017/02/17 03:07:01 I think it might be easier to follow if you de-dup
Peter Wen 2017/02/17 16:37:25 Switched to using sets instead, it's better to sor
+ all_entries.append(self)
+ self._all_entries = _Dedup(all_entries)
+ return self._all_entries
+
class _ProjectContextGenerator(object):
"""Helper class to generate gradle build files"""
@@ -216,7 +264,7 @@ class _ProjectContextGenerator(object):
return jni_libs
def _GenJavaDirs(self, entry):
- java_dirs, excludes = _CreateJavaSourceDir(
+ java_dirs, excludes = _ComputeJavaSourceDirsAndExcludes(
constants.GetOutDirectory(), entry.JavaFiles())
if self.Srcjars(entry):
java_dirs.append(
@@ -230,18 +278,19 @@ class _ProjectContextGenerator(object):
return res_dirs
def _GenCustomManifest(self, entry):
- """Returns the path to the generated AndroidManifest.xml."""
- javac = entry.Javac()
- resource_packages = javac['resource_packages']
- output_file = os.path.join(
- self.EntryOutputDir(entry), 'AndroidManifest.xml')
+ """Returns the path to the generated AndroidManifest.xml.
+ Gradle uses package id from manifest when generating R.class. So, we need
+ to generate a custom manifest if we let gradle process resources. We cannot
+ simply set android.defaultConfig.applicationId because it is not supported
+ for library targets."""
+ resource_packages = entry.Javac().get('resource_packages')
if not resource_packages:
- logging.error('Target ' + entry.GnTarget() + ' includes resources from '
+ logging.debug('Target ' + entry.GnTarget() + ' includes resources from '
'unknown package. Unable to process with gradle.')
return _DEFAULT_ANDROID_MANIFEST_PATH
elif len(resource_packages) > 1:
- logging.error('Target ' + entry.GnTarget() + ' includes resources from '
+ logging.debug('Target ' + entry.GnTarget() + ' includes resources from '
'multiple packages. Unable to process with gradle.')
return _DEFAULT_ANDROID_MANIFEST_PATH
@@ -249,6 +298,8 @@ class _ProjectContextGenerator(object):
variables['compile_sdk_version'] = self.build_vars['android_sdk_version']
variables['package'] = resource_packages[0]
+ output_file = os.path.join(
+ self.EntryOutputDir(entry), 'AndroidManifest.xml')
data = self.jinja_processor.Render(_TemplatePath('manifest'), variables)
_WriteFile(output_file, data)
@@ -270,9 +321,8 @@ class _ProjectContextGenerator(object):
generated_inputs = []
generated_inputs.extend(self.Srcjars(entry))
generated_inputs.extend(_RebasePath(entry.ResZips()))
- generated_inputs.extend(
- p for p in entry.JavaFiles() if not p.startswith('..'))
- generated_inputs.extend(entry.Gradle()['dependent_prebuilt_jars'])
+ generated_inputs.extend(entry.SubdirJavaFiles())
+ generated_inputs.extend(entry.PrebuiltJars())
return generated_inputs
def Generate(self, entry):
@@ -284,22 +334,14 @@ class _ProjectContextGenerator(object):
variables['res_dirs'] = self._Relativize(entry, self._GenResDirs(entry))
android_manifest = entry.Gradle().get('android_manifest')
if not android_manifest:
- # Gradle uses package id from manifest when generating R.class. So, we
- # need to generate a custom manifest if we let gradle process resources.
- # We cannot simply set android.defaultConfig.applicationId because it is
- # not supported for library targets.
- if variables['res_dirs']:
- android_manifest = self._GenCustomManifest(entry)
- else:
- android_manifest = _DEFAULT_ANDROID_MANIFEST_PATH
+ android_manifest = self._GenCustomManifest(entry)
variables['android_manifest'] = self._Relativize(entry, android_manifest)
+ # TODO(agrieve): Add an option to use interface jars and see if that speeds
+ # things up at all.
+ variables['prebuilts'] = self._Relativize(entry, entry.PrebuiltJars())
deps = [_ProjectEntry.FromBuildConfigPath(p)
for p in entry.Gradle()['dependent_android_projects']]
variables['android_project_deps'] = [d.ProjectName() for d in deps]
- # TODO(agrieve): Add an option to use interface jars and see if that speeds
- # things up at all.
- variables['prebuilts'] = self._Relativize(
- entry, entry.Gradle()['dependent_prebuilt_jars'])
deps = [_ProjectEntry.FromBuildConfigPath(p)
for p in entry.Gradle()['dependent_java_projects']]
variables['java_project_deps'] = [d.ProjectName() for d in deps]
@@ -350,7 +392,7 @@ def _ComputeExcludeFilters(wanted_files, unwanted_files, parent_dir):
return excludes
-def _CreateJavaSourceDir(output_dir, java_files):
+def _ComputeJavaSourceDirsAndExcludes(output_dir, java_files):
"""Computes the list of java source directories and exclude patterns.
1. Computes the root java source directories from the list of files.
@@ -461,6 +503,10 @@ def _GenerateGradleFile(entry, generator, build_vars, jinja_processor):
if entry.android_test_entry:
variables['android_test'] = generator.Generate(
entry.android_test_entry)
+ for key, value in variables['android_test'].iteritems():
+ if isinstance(value, list):
+ variables['android_test'][key] = _DedupAgainst(
+ value, variables['main'][key])
return jinja_processor.Render(
_TemplatePath(target_type.split('_')[0]), variables)
@@ -600,7 +646,7 @@ def main():
targets = [re.sub(r'_junit_tests$', '_junit_tests__java_binary', t)
for t in targets]
- main_entries = [_ProjectEntry(t) for t in targets]
+ main_entries = [_ProjectEntry.FromGnTarget(t) for t in targets]
logging.warning('Building .build_config files...')
_RunNinja(output_dir, [e.NinjaBuildConfigTarget() for e in main_entries])
« no previous file with comments | « build/android/gradle/android.jinja ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698