From 3d81728dca9bbc7379f298e1edd102bb4921f39d Mon Sep 17 00:00:00 2001 From: Yong Date: Sat, 5 Nov 2016 23:12:21 +0800 Subject: [PATCH] * fix databinding annotation dependencies --- freeline_core/gradle_clean_build.py | 2 +- freeline_core/gradle_inc_build.py | 44 +++++++++++++++++-- freeline_core/gradle_tools.py | 30 ++++++++----- .../freeline/FreelineClassVisitor.groovy | 32 +++++++++++++- .../freeline/FreelineInjector.groovy | 12 ++--- .../antfortune/freeline/FreelinePlugin.groovy | 21 ++++----- .../antfortune/freeline/FreelineUtils.groovy | 12 ++++- 7 files changed, 116 insertions(+), 37 deletions(-) diff --git a/freeline_core/gradle_clean_build.py b/freeline_core/gradle_clean_build.py index 46bf10b..b7047f9 100755 --- a/freeline_core/gradle_clean_build.py +++ b/freeline_core/gradle_clean_build.py @@ -39,7 +39,7 @@ def generate_sorted_build_tasks(self): install_task = InstallApkTask(self._adb, self._config) clean_all_cache_task = CleanAllCacheTask(self._config['build_cache_dir'], ignore=[ 'stat_cache.json', 'apktime', 'jar_dependencies.json', 'resources_dependencies.json', 'public_keeper.xml', - 'assets_dependencies.json']) + 'assets_dependencies.json', 'freeline_annotation_info.json']) build_base_resource_task = BuildBaseResourceTask(self._config, self._project_info) generate_stat_task = GenerateFileStatTask(self._config) append_stat_task = GenerateFileStatTask(self._config, is_append=True) diff --git a/freeline_core/gradle_inc_build.py b/freeline_core/gradle_inc_build.py index 233edcc..5c659b8 100755 --- a/freeline_core/gradle_inc_build.py +++ b/freeline_core/gradle_inc_build.py @@ -11,7 +11,8 @@ GradleCleanCacheTask, GradleMergeDexTask, get_sync_native_file_path, fix_package_name, DataBindingProcessor, \ DatabindingDirectoryLookUp from task import find_root_tasks, find_last_tasks, Task -from utils import get_file_content, write_file_content, is_windows_system, cexec, load_json_cache, get_md5 +from utils import get_file_content, write_file_content, is_windows_system, cexec, load_json_cache, get_md5, \ + write_json_cache from tracing import Tracing from exceptions import FreelineException @@ -536,8 +537,6 @@ def fill_classpaths(self): if os.path.exists(os.path.join(src_dir, java_src)): existence = True break - # if not os.path.exists(os.path.join(src_dir, java_src)): - # android_tools.delete_class(dirpath, fn.replace('.class', '')) if not existence: android_tools.delete_class(dirpath, fn.replace('.class', '')) @@ -649,12 +648,51 @@ def _generate_java_compile_args(self, extra_javac_args_enabled=False): if 'apt' in self._changed_files: for fpath in self._changed_files['apt']: javacargs.append(fpath) + files = self._get_apt_related_files() + for fpath in files: + if fpath and os.path.exists(fpath) and fpath not in self._changed_files['src'] and fpath not in \ + self._changed_files['apt']: + self.debug('add apt related file: {}'.format(fpath)) + javacargs.append(fpath) javacargs.extend(self._extra_javac_args) javacargs.append('-d') javacargs.append(self._finder.get_patch_classes_cache_dir()) return javacargs + def _get_apt_related_files(self): + path = self._get_apt_related_files_cache_path() + if os.path.exists(path): + return load_json_cache(path) + else: + info_path = os.path.join(self._cache_dir, 'freeline_annotation_info.json') + if os.path.exists(info_path): + info_cache = load_json_cache(info_path) + related_files = [] + for anno, files in info_cache.iteritems(): + for info in files: + if 'java_path' in info and info['java_path']: + related_files.append(info['java_path']) + write_json_cache(self._get_apt_related_files_cache_path(), related_files) + return related_files + return [] + + def _append_new_related_files(self): + related_files = self._get_apt_related_files() + + def append_files(file_list): + for fpath in file_list: + if fpath and fpath not in related_files: + self.debug('add new related file: {}'.format(fpath)) + related_files.append(fpath) + + append_files(self._changed_files['src']) + append_files(self._changed_files['apt']) + write_json_cache(self._get_apt_related_files_cache_path(), related_files) + + def _get_apt_related_files_cache_path(self): + return os.path.join(self._cache_dir, 'apt_related_files_cache.json') + def run_retrolambda(self): if self._is_need_javac and self._is_retrolambda_enabled: lambda_config = self._config['retrolambda'][self._name] diff --git a/freeline_core/gradle_tools.py b/freeline_core/gradle_tools.py index ddfadfe..0cf85bb 100755 --- a/freeline_core/gradle_tools.py +++ b/freeline_core/gradle_tools.py @@ -831,19 +831,27 @@ def process_layout_info(self, fpath): classpaths = [] for import_node in imports: - imports_dict[import_node.attrib['name']] = import_node.attrib + if 'name' in import_node.attrib: + imports_dict[import_node.attrib['name']] = import_node.attrib + if 'type' in import_node.attrib: + classpath = import_node.attrib['type'] + if classpath and classpath not in classpaths and not classpath.startswith( + 'android.') and not classpath.startswith('java.'): + classpaths.append(classpath) for variable_node in variables: - variable_type = variable_node.attrib['type'] - if '.' in variable_type: - classpath = variable_type - elif variable_type in imports_dict: - classpath = imports_dict[variable_type]['type'] - else: - classpath = None - - if classpath and not classpath.startswith('android.') and not classpath.startswith('java.'): - classpaths.append(classpath) + if 'type' in variable_node.attrib: + variable_type = variable_node.attrib['type'] + if '.' in variable_type: + classpath = variable_type + elif variable_type in imports_dict: + classpath = imports_dict[variable_type]['type'] + else: + classpath = None + + if classpath and classpath not in classpaths and not classpath.startswith( + 'android.') and not classpath.startswith('java.'): + classpaths.append(classpath) return classpaths return [] diff --git a/gradle/src/main/groovy/com/antfortune/freeline/FreelineClassVisitor.groovy b/gradle/src/main/groovy/com/antfortune/freeline/FreelineClassVisitor.groovy index e2bec33..c3cc2e7 100644 --- a/gradle/src/main/groovy/com/antfortune/freeline/FreelineClassVisitor.groovy +++ b/gradle/src/main/groovy/com/antfortune/freeline/FreelineClassVisitor.groovy @@ -1,5 +1,6 @@ package com.antfortune.freeline +import org.objectweb.asm.AnnotationVisitor import org.objectweb.asm.ClassVisitor import org.objectweb.asm.ClassWriter import org.objectweb.asm.Label @@ -14,14 +15,28 @@ class FreelineClassVisitor extends ClassVisitor implements Opcodes { private static final String SUFFIX_ANDROIDANNOTATION = "_" - public boolean isHack = true; + public boolean isHack = true - public FreelineClassVisitor(int api, ClassWriter cw) { + public String className = null + + public String filePath = null + + public String entry = null + + public boolean isJar = false + + public def foundAnnos = [] + + public FreelineClassVisitor(String path, String entry, boolean isJar, int api, ClassWriter cw) { super(api, cw) + this.filePath = path + this.entry = entry + this.isJar = isJar } @Override void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + className = name; if ("android/app/Application".equals(superName)) { isHack = false; } @@ -68,6 +83,19 @@ class FreelineClassVisitor extends ClassVisitor implements Opcodes { } super.visitMaxs(i, i1) } + + @Override + AnnotationVisitor visitAnnotation(String annoDesc, boolean visible) { + if (annoDesc != null) { + FreelineAnnotationCollector.ANNOTATION_CLASSES.each { anno -> + if (!foundAnnos.contains(anno) && annoDesc.contains(anno)) { + foundAnnos.add(anno) + FreelineAnnotationCollector.addNewAnno(anno, filePath, className, entry, isJar) + } + } + } + return super.visitAnnotation(annoDesc, visible) + } } return mv; } diff --git a/gradle/src/main/groovy/com/antfortune/freeline/FreelineInjector.groovy b/gradle/src/main/groovy/com/antfortune/freeline/FreelineInjector.groovy index e560a82..81daabf 100644 --- a/gradle/src/main/groovy/com/antfortune/freeline/FreelineInjector.groovy +++ b/gradle/src/main/groovy/com/antfortune/freeline/FreelineInjector.groovy @@ -15,7 +15,7 @@ import java.util.zip.ZipEntry */ class FreelineInjector { - public static void inject(List excludeClasses, File file, List modules) { + public static void inject(List excludeClasses, File file, Collection modules) { if (file.path.endsWith(".class") && !isExcluded(file.path, excludeClasses)) { realInject(file) @@ -44,7 +44,7 @@ class FreelineInjector { return false } - private static boolean isProjectModuleJar(String path, List modules) { + private static boolean isProjectModuleJar(String path, Collection modules) { for (String module : modules) { if (path.contains(module)) { return true @@ -61,7 +61,7 @@ class FreelineInjector { FileInputStream fis = new FileInputStream(file) FileOutputStream fos = new FileOutputStream(pending) println "inject: ${file.path}" - byte[] bytes = hackClass(fis); + byte[] bytes = hackClass(file.path, null, false, fis); fos.write(bytes) fis.close() fos.close() @@ -81,7 +81,7 @@ class FreelineInjector { if (entryName.endsWith(".class")) { println "inject jar class: ${entryName}" - jos.write(hackClass(is)) + jos.write(hackClass(file.path, entryName, true, is)) } else { println "skip jar entry: ${entryName}" jos.write(readBytes(is)) @@ -108,10 +108,10 @@ class FreelineInjector { } } - private static byte[] hackClass(InputStream inputStream) { + private static byte[] hackClass(String path, String entry, boolean isJar, InputStream inputStream) { ClassReader cr = new ClassReader(inputStream) ClassWriter cw = new ClassWriter(cr, 0) - ClassVisitor cv = new FreelineClassVisitor(Opcodes.ASM4, cw) + ClassVisitor cv = new FreelineClassVisitor(path, entry, isJar, Opcodes.ASM4, cw) cr.accept(cv, 0) return cw.toByteArray() } diff --git a/gradle/src/main/groovy/com/antfortune/freeline/FreelinePlugin.groovy b/gradle/src/main/groovy/com/antfortune/freeline/FreelinePlugin.groovy index 4141dd2..458384a 100644 --- a/gradle/src/main/groovy/com/antfortune/freeline/FreelinePlugin.groovy +++ b/gradle/src/main/groovy/com/antfortune/freeline/FreelinePlugin.groovy @@ -290,20 +290,21 @@ class FreelinePlugin implements Plugin { classesProcessTask.outputs.upToDateWhen { false } String backUpDirPath = FreelineUtils.getBuildBackupDir(project.buildDir.absolutePath) + def modules = [:] + project.rootProject.allprojects.each { pro -> + //modules.add("exploded-aar" + File.separator + pro.group + File.separator + pro.name + File.separator) + modules[pro.name] = "exploded-aar" + File.separator + pro.group + File.separator + pro.name + File.separator + } if (preDexTask) { preDexTask.outputs.upToDateWhen { false } def hackClassesBeforePreDex = "hackClassesBeforePreDex${variant.name.capitalize()}" project.task(hackClassesBeforePreDex) << { def jarDependencies = [] - def modules = [] - project.rootProject.allprojects.each { pro -> - modules.add("exploded-aar" + File.separator + pro.group + File.separator + pro.name + File.separator) - } preDexTask.inputs.files.files.each { f -> if (f.path.endsWith(".jar")) { - FreelineInjector.inject(excludeHackClasses, f as File, modules) + FreelineInjector.inject(excludeHackClasses, f as File, modules.values()) jarDependencies.add(f.path) } } @@ -321,23 +322,18 @@ class FreelinePlugin implements Plugin { def backupMap = [:] project.task(hackClassesBeforeDex) << { def jarDependencies = [] - def modules = [] - project.rootProject.allprojects.each { pro -> - modules.add("exploded-aar" + File.separator + pro.group + File.separator + pro.name + File.separator) - } - classesProcessTask.inputs.files.files.each { f -> if (f.isDirectory()) { f.eachFileRecurse(FileType.FILES) { file -> backUpClass(backupMap, file as File, backUpDirPath as String) - FreelineInjector.inject(excludeHackClasses, file as File, modules) + FreelineInjector.inject(excludeHackClasses, file as File, modules.values()) if (file.path.endsWith(".jar")) { jarDependencies.add(file.path) } } } else { backUpClass(backupMap, f as File, backUpDirPath as String) - FreelineInjector.inject(excludeHackClasses, f as File, modules) + FreelineInjector.inject(excludeHackClasses, f as File, modules.values()) if (f.path.endsWith(".jar")) { jarDependencies.add(f.path) } @@ -373,6 +369,7 @@ class FreelinePlugin implements Plugin { def assembleTask = project.tasks.findByName("assemble${variant.name.capitalize()}") if (assembleTask) { assembleTask.doLast { + FreelineAnnotationCollector.saveCollections(project, FreelineUtils.getBuildCacheDir(project.buildDir.absolutePath), modules) FreelineUtils.addNewAttribute(project, 'apt', projectAptConfig) FreelineUtils.addNewAttribute(project, 'retrolambda', projectRetrolambdaConfig) FreelineUtils.addNewAttribute(project, 'databinding_compiler_jar', databindingCompilerJarPath) diff --git a/gradle/src/main/groovy/com/antfortune/freeline/FreelineUtils.groovy b/gradle/src/main/groovy/com/antfortune/freeline/FreelineUtils.groovy index f1a3a3b..255d8af 100644 --- a/gradle/src/main/groovy/com/antfortune/freeline/FreelineUtils.groovy +++ b/gradle/src/main/groovy/com/antfortune/freeline/FreelineUtils.groovy @@ -96,12 +96,20 @@ class FreelineUtils { } public static void addNewAttribute(Project project, String key, def value) { + def description = readProjectDescription(project) + if (description != null) { + description[key] = value + saveJson(new JsonBuilder(description).toPrettyString(), joinPath(getFreelineCacheDir(project.rootDir.absolutePath), 'project_description.json'), true) + } + } + + public static def readProjectDescription(Project project) { def descriptionFile = new File(joinPath(getFreelineCacheDir(project.rootDir.absolutePath), 'project_description.json')) if (descriptionFile.exists()) { def description = new JsonSlurper().parseText(descriptionFile.text) - description[key] = value - saveJson(new JsonBuilder(description).toPrettyString(), descriptionFile.absolutePath, true) + return description } + return null } public static String joinPath(String... sep) {