diff options
author | Yigit Boyar <yboyar@google.com> | 2015-06-12 13:13:17 -0700 |
---|---|---|
committer | Yigit Boyar <yboyar@google.com> | 2015-06-12 14:15:07 -0700 |
commit | b6887f1479c3ecec38a7989748ef33de1fbcd973 (patch) | |
tree | 8d8ff47f19e1ce3993d952bcb6e320b61cbe0399 /gradlePlugin | |
parent | 30b1bbbcf006dc6600f86a4e4d1bdf6d8a218351 (diff) | |
download | data-binding-b6887f1479c3ecec38a7989748ef33de1fbcd973.tar.gz |
Export generated class list from javac
Previously, gradle plugin would figure out generated class names
that should be excluded from the packaging. This CL changes that
behavior to export the list from java compiler so that it is
consistent going forward.
This CL also changes exclusion task to always exclude generated
binding info class to not to leak any information about user's
local.
Bug: 21668472
Change-Id: Ibeed24bd854781942b4185f618a5cd1eafe706d3
Diffstat (limited to 'gradlePlugin')
5 files changed, 158 insertions, 64 deletions
diff --git a/gradlePlugin/build.gradle b/gradlePlugin/build.gradle index 2ffab0ca..83aa27cc 100644 --- a/gradlePlugin/build.gradle +++ b/gradlePlugin/build.gradle @@ -46,6 +46,10 @@ dependencies { compile project(":compiler") } +compileJava { + options.compilerArgs = ["-proc:none"] +} + uploadArchives { repositories { mavenDeployer { diff --git a/gradlePlugin/src/main/java/android/databinding/tool/DataBindingExcludeGeneratedTask.java b/gradlePlugin/src/main/java/android/databinding/tool/DataBindingExcludeGeneratedTask.java new file mode 100644 index 00000000..cfc7a98a --- /dev/null +++ b/gradlePlugin/src/main/java/android/databinding/tool/DataBindingExcludeGeneratedTask.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.databinding.tool; + +import com.google.common.base.Preconditions; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.gradle.api.DefaultTask; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.bundling.Jar; + +import android.databinding.tool.util.L; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; + +/** + * Task to exclude generated classes from the Jar task of a library project + */ +public class DataBindingExcludeGeneratedTask extends DefaultTask { + private String appPackage; + private String infoClassQualifiedName; + @Input + private File generatedClassListFile; + private boolean isLibrary; + + private org.gradle.api.tasks.bundling.Jar packageTask; + private final String EXCLUDE_PATTERN = "android/databinding/layouts/*.*"; + + public void setAppPackage(String appPackage) { + this.appPackage = appPackage; + } + + public void setInfoClassQualifiedName(String infoClassQualifiedName) { + this.infoClassQualifiedName = infoClassQualifiedName; + } + + public void setLibrary(boolean isLibrary) { + this.isLibrary = isLibrary; + } + + public void setPackageTask(Jar packageTask) { + this.packageTask = packageTask; + } + + public void setGeneratedClassListFile(File generatedClassListFile) { + this.generatedClassListFile = generatedClassListFile; + } + + public String getAppPackage() { + return appPackage; + } + + public String getInfoClassQualifiedName() { + return infoClassQualifiedName; + } + + public File getGeneratedClassListFile() { + return generatedClassListFile; + } + + @TaskAction + public void excludeGenerated() { + L.d("Excluding generated classes from jar. Is library ? %s", isLibrary); + String appPkgAsClass = appPackage.replace('.', '/'); + String infoClassAsClass = infoClassQualifiedName.replace('.', '/'); + exclude(infoClassAsClass + ".class"); + exclude(EXCLUDE_PATTERN); + if (isLibrary) { + exclude(appPkgAsClass + "/BR.*"); + List<String> generatedClasses = readGeneratedClasses(); + for (String klass : generatedClasses) { + exclude(klass.replace('.', '/') + ".class"); + } + } + L.d("Excluding generated classes from library jar is done."); + } + + private void exclude(String pattern) { + L.d("exclude %s", pattern); + packageTask.exclude(pattern); + } + + private List<String> readGeneratedClasses() { + Preconditions.checkNotNull(generatedClassListFile, "Data binding exclude generated task" + + " is not configured properly"); + Preconditions.checkArgument(generatedClassListFile.exists(), + "Generated class list does not exist %s", generatedClassListFile.getAbsolutePath()); + FileInputStream fis = null; + try { + fis = new FileInputStream(generatedClassListFile); + return IOUtils.readLines(fis); + } catch (FileNotFoundException e) { + L.e(e, "Unable to read generated class list from %s", + generatedClassListFile.getAbsoluteFile()); + } catch (IOException e) { + L.e(e, "Unexpected exception while reading %s", + generatedClassListFile.getAbsoluteFile()); + } finally { + IOUtils.closeQuietly(fis); + } + Preconditions.checkState(false, "Could not read data binding generated class list"); + return null; + } +} diff --git a/gradlePlugin/src/main/kotlin/DataBindingExportInfoTask.kt b/gradlePlugin/src/main/kotlin/DataBindingExportInfoTask.kt index 776e4263..ee99c6b4 100644 --- a/gradlePlugin/src/main/kotlin/DataBindingExportInfoTask.kt +++ b/gradlePlugin/src/main/kotlin/DataBindingExportInfoTask.kt @@ -25,10 +25,11 @@ open class DataBindingExportInfoTask : DefaultTask() { var xmlProcessor: LayoutXmlProcessor by Delegates.notNull() var sdkDir : File by Delegates.notNull() var xmlOutFolder : File by Delegates.notNull() + var exportClassListTo : File? = null var enableDebugLogs = false - [TaskAction] + @TaskAction public fun doIt() { L.d("running process layouts task %s", getName()) - xmlProcessor.writeInfoClass(sdkDir, xmlOutFolder, enableDebugLogs) + xmlProcessor.writeInfoClass(sdkDir, xmlOutFolder, exportClassListTo, enableDebugLogs) } }
\ No newline at end of file diff --git a/gradlePlugin/src/main/kotlin/DataBindingProcessLayoutsTask.kt b/gradlePlugin/src/main/kotlin/DataBindingProcessLayoutsTask.kt index ec8c348c..3bc0e0fb 100644 --- a/gradlePlugin/src/main/kotlin/DataBindingProcessLayoutsTask.kt +++ b/gradlePlugin/src/main/kotlin/DataBindingProcessLayoutsTask.kt @@ -27,7 +27,7 @@ open class DataBindingProcessLayoutsTask : DefaultTask() { var xmlOutFolder : File by Delegates.notNull() var minSdk: kotlin.Int by Delegates.notNull() - [TaskAction] + @TaskAction public fun doIt() { L.d("running process layouts task %s", getName()) xmlProcessor.processResources(minSdk) diff --git a/gradlePlugin/src/main/kotlin/plugin.kt b/gradlePlugin/src/main/kotlin/plugin.kt index a5df389c..e63e32df 100644 --- a/gradlePlugin/src/main/kotlin/plugin.kt +++ b/gradlePlugin/src/main/kotlin/plugin.kt @@ -37,6 +37,7 @@ import com.android.build.gradle.api.TestVariant import com.android.build.gradle.internal.variant.TestVariantData import com.android.build.gradle.internal.api.TestVariantImpl import com.android.ide.common.res2.ResourceSet +import com.google.common.base.Preconditions import org.apache.commons.io.IOUtils import org.gradle.api.artifacts import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency @@ -54,12 +55,11 @@ import org.gradle.api.plugins.ExtraPropertiesExtension open class DataBinderPlugin : Plugin<Project> { - val XPATH_BINDING_CLASS = "/layout/data/@class" var logger : Logger by Delegates.notNull() inner class GradleFileWriter(var outputBase: String) : JavaFileWriter() { override fun writeToFile(canonicalName: String, contents: String) { - val f = File("$outputBase/${canonicalName.replaceAll("\\.", "/")}.java") + val f = File("$outputBase/${canonicalName.replace("\\.".toRegex(), "/")}.java") logD("Asked to write to ${canonicalName}. outputting to:${f.getAbsolutePath()}") f.getParentFile().mkdirs() f.writeText(contents, "utf-8") @@ -189,11 +189,12 @@ open class DataBinderPlugin : Plugin<Project> { minSdkVersion.getApiLevel(), isLibrary) val processResTask = generateRTask val xmlOutDir = File("${project.getBuildDir()}/layout-info/${configuration.getDirName()}") + val generatedClassListOut = if (isLibrary) File(xmlOutDir, "_generated.txt") else null logD("xml output for ${variantData} is ${xmlOutDir}") val layoutTaskName = "dataBindingLayouts${processResTask.getName().capitalize()}" val infoClassTaskName = "dataBindingInfoClass${processResTask.getName().capitalize()}" - var processLayoutsTask : DataBindingProcessLayoutsTask? = null + var processLayoutsTask: DataBindingProcessLayoutsTask? = null project.getTasks().create(layoutTaskName, javaClass<DataBindingProcessLayoutsTask>(), object : Action<DataBindingProcessLayoutsTask> { @@ -217,76 +218,40 @@ open class DataBinderPlugin : Plugin<Project> { }) project.getTasks().create(infoClassTaskName, javaClass<DataBindingExportInfoTask>(), - object : Action<DataBindingExportInfoTask>{ + object : Action<DataBindingExportInfoTask> { override fun execute(task: DataBindingExportInfoTask) { task.dependsOn(processLayoutsTask!!) task.dependsOn(processResTask) task.xmlProcessor = xmlProcessor task.sdkDir = sdkDir task.xmlOutFolder = xmlOutDir + task.exportClassListTo = generatedClassListOut task.enableDebugLogs = logger.isEnabled(LogLevel.DEBUG) variantData.registerJavaGeneratingTask(task, codeGenTargetFolder) } }) + val packageJarTaskName = "package${fullName.capitalize()}Jar" + val packageTask = project.getTasks().findByName(packageJarTaskName) + if (packageTask is org.gradle.api.tasks.bundling.Jar) { + val removeGeneratedTaskName = "dataBindingExcludeGeneratedFrom${packageTask.getName().capitalize()}" + if (project.getTasks().findByName(removeGeneratedTaskName) == null) { + val javaCompileTask = variantData.javaCompileTask + Preconditions.checkNotNull(javaCompileTask) - if (isLibrary) { - val resourceSets = variantData.mergeResourcesTask.getInputResourceSets() - val customBindings = getCustomBindings(resourceSets, packageName) - val packageJarTaskName = "package${fullName.capitalize()}Jar" - val packageTask = project.getTasks().findByName(packageJarTaskName) - if (packageTask !is org.gradle.api.tasks.bundling.Jar) { - throw RuntimeException("cannot find package task in $project $variantData project $packageJarTaskName") - } - val excludePattern = "android/databinding/layouts/*.*" - val appPkgAsClass = packageName.replace('.', '/') - packageTask.exclude(excludePattern) - packageTask.exclude("$appPkgAsClass/databinding/*") - packageTask.exclude("$appPkgAsClass/BR.*") - packageTask.exclude(xmlProcessor.getInfoClassFullName().replace('.', '/') + ".class") - customBindings.forEach { - packageTask.exclude("${it.replace('.', '/')}.class") - } - logD("excludes ${packageTask.getExcludes()}") - } - } - - fun getCustomBindings(resourceSets : List<ResourceSet>, packageName: String) : List<String> { - val xPathFactory = XPathFactory.newInstance() - val xPath = xPathFactory.newXPath() - val expr = xPath.compile(XPATH_BINDING_CLASS); - val customBindings = ArrayList<String>() - - resourceSets.forEach { set -> - set.getSourceFiles().forEach({ res -> - res.listFiles(object : FileFilter { - override fun accept(file: File?): Boolean { - return file != null && file.isDirectory() && - file.getName().toLowerCase().startsWith("layout") - } - })?.forEach { layoutDir -> - - layoutDir.listFiles(object : FileFilter { - override fun accept(file: File?): Boolean { - return file != null && !file.isDirectory() && - file.getName().toLowerCase().endsWith(".xml") - } - })?.forEach { xmlFile: File -> - val document = parseXml(xmlFile) - val bindingClass = expr.evaluate(document) - if (bindingClass != null && !bindingClass.isEmpty()) { - if (bindingClass.startsWith('.')) { - customBindings.add("${packageName}${bindingClass}") - } else if (bindingClass.contains(".")) { - customBindings.add(bindingClass) - } else { - customBindings.add( - "${packageName}.databinding.${bindingClass}") + project.getTasks().create(removeGeneratedTaskName, + javaClass<DataBindingExcludeGeneratedTask>(), + object : Action<DataBindingExcludeGeneratedTask> { + override fun execute(task: DataBindingExcludeGeneratedTask) { + packageTask.dependsOn(task) + task.dependsOn(javaCompileTask) + task.setAppPackage(packageName) + task.setInfoClassQualifiedName(xmlProcessor.getInfoClassFullName()) + task.setPackageTask(packageTask) + task.setLibrary(isLibrary) + task.setGeneratedClassListFile(generatedClassListOut) } - } - } - } - }) + }) + } } - return customBindings } } |