summaryrefslogtreecommitdiff
path: root/gradlePlugin/src/main/java/android/databinding/tool
diff options
context:
space:
mode:
authorYigit Boyar <yboyar@google.com>2015-06-12 15:42:03 -0700
committerYigit Boyar <yboyar@google.com>2015-06-12 23:11:46 +0000
commit40d0967b36f0bd77393719f0442626c838697290 (patch)
treec1ebd7fcb8434a43b4de4c9be21fcab87a1218e9 /gradlePlugin/src/main/java/android/databinding/tool
parentb6887f1479c3ecec38a7989748ef33de1fbcd973 (diff)
downloaddata-binding-40d0967b36f0bd77393719f0442626c838697290.tar.gz
Remove kotlin from gradle plugin
This CL removes dependency on kotlin the gradle plugin. One step closer to integrating w/ Android plugin Bug: 21815393 Change-Id: Ida966e4bb8d92da1b8734b6b40da230fbac5c8d2
Diffstat (limited to 'gradlePlugin/src/main/java/android/databinding/tool')
-rw-r--r--gradlePlugin/src/main/java/android/databinding/tool/DataBinderPlugin.java329
-rw-r--r--gradlePlugin/src/main/java/android/databinding/tool/DataBindingExportInfoTask.java77
-rw-r--r--gradlePlugin/src/main/java/android/databinding/tool/DataBindingProcessLayoutsTask.java87
3 files changed, 493 insertions, 0 deletions
diff --git a/gradlePlugin/src/main/java/android/databinding/tool/DataBinderPlugin.java b/gradlePlugin/src/main/java/android/databinding/tool/DataBinderPlugin.java
new file mode 100644
index 00000000..ad64057e
--- /dev/null
+++ b/gradlePlugin/src/main/java/android/databinding/tool/DataBinderPlugin.java
@@ -0,0 +1,329 @@
+/*
+ * 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 com.android.build.gradle.AppExtension;
+import com.android.build.gradle.BaseExtension;
+import com.android.build.gradle.LibraryExtension;
+import com.android.build.gradle.api.ApplicationVariant;
+import com.android.build.gradle.api.LibraryVariant;
+import com.android.build.gradle.api.TestVariant;
+import com.android.build.gradle.internal.api.ApplicationVariantImpl;
+import com.android.build.gradle.internal.api.LibraryVariantImpl;
+import com.android.build.gradle.internal.api.TestVariantImpl;
+import com.android.build.gradle.internal.core.GradleVariantConfiguration;
+import com.android.build.gradle.internal.variant.ApplicationVariantData;
+import com.android.build.gradle.internal.variant.BaseVariantData;
+import com.android.build.gradle.internal.variant.LibraryVariantData;
+import com.android.build.gradle.internal.variant.TestVariantData;
+import com.android.build.gradle.tasks.ProcessAndroidResources;
+import com.android.builder.model.ApiVersion;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.gradle.api.Action;
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.Task;
+import org.gradle.api.logging.LogLevel;
+import org.gradle.api.logging.Logger;
+import org.gradle.api.plugins.ExtraPropertiesExtension;
+import org.gradle.api.tasks.bundling.Jar;
+import org.gradle.api.tasks.compile.AbstractCompile;
+
+import android.databinding.tool.writer.JavaFileWriter;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.xml.bind.JAXBException;
+
+public class DataBinderPlugin implements Plugin<Project> {
+
+ private Logger logger;
+
+ class GradleFileWriter extends JavaFileWriter {
+
+ private final String outputBase;
+
+ public GradleFileWriter(String outputBase) {
+ this.outputBase = outputBase;
+ }
+
+ @Override
+ public void writeToFile(String canonicalName, String contents) {
+ String asPath = canonicalName.replace('.', '/');
+ File f = new File(outputBase + "/" + asPath + ".java");
+ logD("Asked to write to " + canonicalName + ". outputting to:" +
+ f.getAbsolutePath());
+ //noinspection ResultOfMethodCallIgnored
+ f.getParentFile().mkdirs();
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(f);
+ IOUtils.write(contents, fos);
+ } catch (IOException e) {
+ logE(e, "cannot write file " + f.getAbsolutePath());
+ } finally {
+ IOUtils.closeQuietly(fos);
+ }
+ }
+ }
+
+ @Override
+ public void apply(Project project) {
+ if (project == null) {
+ return;
+ }
+ logger = project.getLogger();
+
+ String myVersion = readMyVersion();
+ logD("data binding plugin version is %s", myVersion);
+ if (StringUtils.isEmpty(myVersion)) {
+ throw new IllegalStateException("cannot read version of the plugin :/");
+ }
+
+ project.getDependencies().add("compile", "com.android.databinding:library:" + myVersion);
+ boolean addAdapters = true;
+ if (project.hasProperty("ext")) {
+ Object ext = project.getProperties().get("ext");
+ if (ext instanceof ExtraPropertiesExtension) {
+ ExtraPropertiesExtension propExt = (ExtraPropertiesExtension) ext;
+ if (propExt.has("addDataBindingAdapters")) {
+ addAdapters = Boolean.valueOf(
+ String.valueOf(propExt.get("addDataBindingAdapters")));
+ }
+ }
+ }
+ if (addAdapters) {
+ project.getDependencies()
+ .add("compile", "com.android.databinding:adapters:" + myVersion);
+ }
+ project.getDependencies().add("provided", "com.android.databinding:compiler:" + myVersion);
+ project.afterEvaluate(new Action<Project>() {
+ @Override
+ public void execute(Project project) {
+ try {
+ createXmlProcessor(project);
+ } catch (Throwable t) {
+ logE(t, "failed to setup data binding");
+ }
+ }
+ });
+ }
+
+ String readMyVersion() {
+ try {
+ InputStream stream = getClass().getResourceAsStream("/data_binding_build_info");
+ try {
+ return IOUtils.toString(stream, "utf-8").trim();
+ } finally {
+ IOUtils.closeQuietly(stream);
+ }
+ } catch (IOException exception) {
+ logE(exception, "Cannot read data binding version");
+ }
+ return null;
+ }
+
+ private void createXmlProcessor(Project project)
+ throws NoSuchFieldException, IllegalAccessException {
+ Object androidExt = project.getExtensions().getByName("android");
+ if (!(androidExt instanceof BaseExtension)) {
+ return;
+ }
+ if (androidExt instanceof AppExtension) {
+ createXmlProcessorForApp(project, (AppExtension) androidExt);
+ } else if (androidExt instanceof LibraryExtension) {
+ createXmlProcessorForLibrary(project, (LibraryExtension) androidExt);
+ } else {
+ logE(new UnsupportedOperationException("cannot understand android ext"),
+ "unsupported android extension. What is it? %s", androidExt);
+ }
+ }
+
+ private void createXmlProcessorForLibrary(Project project, LibraryExtension lib)
+ throws NoSuchFieldException, IllegalAccessException {
+ File sdkDir = lib.getSdkDirectory();
+ for (TestVariant variant : lib.getTestVariants()) {
+ logD("test variant %s. dir name %s", variant, variant.getDirName());
+ BaseVariantData variantData = getVariantData(variant);
+ attachXmlProcessor(project, variantData, sdkDir, false);//tests extend apk variant
+ }
+ for (LibraryVariant variant : lib.getLibraryVariants()) {
+ logD("library variant %s. dir name %s", variant, variant.getDirName());
+ BaseVariantData variantData = getVariantData(variant);
+ attachXmlProcessor(project, variantData, sdkDir, true);
+ }
+ }
+
+ private void createXmlProcessorForApp(Project project, AppExtension appExt)
+ throws NoSuchFieldException, IllegalAccessException {
+ File sdkDir = appExt.getSdkDirectory();
+ for (TestVariant testVariant : appExt.getTestVariants()) {
+ TestVariantData variantData = getVariantData(testVariant);
+ attachXmlProcessor(project, variantData, sdkDir, false);
+ }
+ for (ApplicationVariant appVariant : appExt.getApplicationVariants()) {
+ ApplicationVariantData variantData = getVariantData(appVariant);
+ attachXmlProcessor(project, variantData, sdkDir, false);
+ }
+ }
+
+ private LibraryVariantData getVariantData(LibraryVariant variant)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field = LibraryVariantImpl.class.getDeclaredField("variantData");
+ field.setAccessible(true);
+ return (LibraryVariantData) field.get(variant);
+ }
+
+ private TestVariantData getVariantData(TestVariant variant)
+ throws IllegalAccessException, NoSuchFieldException {
+ Field field = TestVariantImpl.class.getDeclaredField("variantData");
+ field.setAccessible(true);
+ return (TestVariantData) field.get(variant);
+ }
+
+ private ApplicationVariantData getVariantData(ApplicationVariant variant)
+ throws IllegalAccessException, NoSuchFieldException {
+ Field field = ApplicationVariantImpl.class.getDeclaredField("variantData");
+ field.setAccessible(true);
+ return (ApplicationVariantData) field.get(variant);
+ }
+
+ private void attachXmlProcessor(Project project, final BaseVariantData variantData,
+ final File sdkDir,
+ final Boolean isLibrary) {
+ final GradleVariantConfiguration configuration = variantData.getVariantConfiguration();
+ final ApiVersion minSdkVersion = configuration.getMinSdkVersion();
+ ProcessAndroidResources generateRTask = variantData.generateRClassTask;
+ final String packageName = generateRTask.getPackageForR();
+ String fullName = configuration.getFullName();
+ List<File> resourceFolders = Arrays.asList(variantData.mergeResourcesTask.getOutputDir());
+
+ final File codeGenTargetFolder = new File(project.getBuildDir() + "/data-binding-info/" +
+ configuration.getDirName());
+ String writerOutBase = codeGenTargetFolder.getAbsolutePath();
+ JavaFileWriter fileWriter = new GradleFileWriter(writerOutBase);
+ final LayoutXmlProcessor xmlProcessor = new LayoutXmlProcessor(packageName, resourceFolders,
+ fileWriter, minSdkVersion.getApiLevel(), isLibrary);
+ final ProcessAndroidResources processResTask = generateRTask;
+ final File xmlOutDir = new File(project.getBuildDir() + "/layout-info/" +
+ configuration.getDirName());
+ final File generatedClassListOut = isLibrary ? new File(xmlOutDir, "_generated.txt") : null;
+ logD("xml output for %s is %s", variantData, xmlOutDir);
+ String layoutTaskName = "dataBindingLayouts" + StringUtils
+ .capitalize(processResTask.getName());
+ String infoClassTaskName = "dataBindingInfoClass" + StringUtils
+ .capitalize(processResTask.getName());
+
+ final DataBindingProcessLayoutsTask[] processLayoutsTasks
+ = new DataBindingProcessLayoutsTask[1];
+ project.getTasks().create(layoutTaskName,
+ DataBindingProcessLayoutsTask.class,
+ new Action<DataBindingProcessLayoutsTask>() {
+ @Override
+ public void execute(final DataBindingProcessLayoutsTask task) {
+ processLayoutsTasks[0] = task;
+ task.setXmlProcessor(xmlProcessor);
+ task.setSdkDir(sdkDir);
+ task.setXmlOutFolder(xmlOutDir);
+ task.setMinSdk(minSdkVersion.getApiLevel());
+
+ logD("TASK adding dependency on %s for %s", task, processResTask);
+ processResTask.dependsOn(task);
+ for (Object dep : processResTask.getDependsOn()) {
+ if (dep == task) {
+ continue;
+ }
+ logD("adding dependency on %s for %s", dep, task);
+ task.dependsOn(dep);
+ }
+ processResTask.doLast(new Action<Task>() {
+ @Override
+ public void execute(Task unused) {
+ try {
+ task.writeLayoutXmls();
+ } catch (JAXBException e) {
+ logE(e, "cannot write layout xmls");
+ }
+ }
+ });
+ }
+ });
+ final DataBindingProcessLayoutsTask processLayoutsTask = processLayoutsTasks[0];
+ project.getTasks().create(infoClassTaskName,
+ DataBindingExportInfoTask.class,
+ new Action<DataBindingExportInfoTask>() {
+
+ @Override
+ public void execute(DataBindingExportInfoTask task) {
+ task.dependsOn(processLayoutsTask);
+ task.dependsOn(processResTask);
+ task.setXmlProcessor(xmlProcessor);
+ task.setSdkDir(sdkDir);
+ task.setXmlOutFolder(xmlOutDir);
+ task.setExportClassListTo(generatedClassListOut);
+ task.setEnableDebugLogs(logger.isEnabled(LogLevel.DEBUG));
+ variantData.registerJavaGeneratingTask(task, codeGenTargetFolder);
+ }
+ });
+ String packageJarTaskName = "package" + StringUtils.capitalize(fullName) + "Jar";
+ final Task packageTask = project.getTasks().findByName(packageJarTaskName);
+ if (packageTask instanceof Jar) {
+ String removeGeneratedTaskName = "dataBindingExcludeGeneratedFrom" +
+ StringUtils.capitalize(packageTask.getName());
+ if (project.getTasks().findByName(removeGeneratedTaskName) == null) {
+ final AbstractCompile javaCompileTask = variantData.javaCompileTask;
+ Preconditions.checkNotNull(javaCompileTask);
+
+ project.getTasks().create(removeGeneratedTaskName,
+ DataBindingExcludeGeneratedTask.class,
+ new Action<DataBindingExcludeGeneratedTask>() {
+ @Override
+ public void execute(DataBindingExcludeGeneratedTask task) {
+ packageTask.dependsOn(task);
+ task.dependsOn(javaCompileTask);
+ task.setAppPackage(packageName);
+ task.setInfoClassQualifiedName(xmlProcessor.getInfoClassFullName());
+ task.setPackageTask((Jar) packageTask);
+ task.setLibrary(isLibrary);
+ task.setGeneratedClassListFile(generatedClassListOut);
+ }
+ });
+ }
+ }
+ }
+
+ private void logD(String s, Object... args) {
+ logger.info(formatLog(s, args));
+ }
+
+ private void logE(Throwable t, String s, Object... args) {
+ logger.error(formatLog(s, args), t);
+ }
+
+ private String formatLog(String s, Object... args) {
+ return "[data binding plugin]: " + String.format(s, args);
+ }
+}
diff --git a/gradlePlugin/src/main/java/android/databinding/tool/DataBindingExportInfoTask.java b/gradlePlugin/src/main/java/android/databinding/tool/DataBindingExportInfoTask.java
new file mode 100644
index 00000000..54774674
--- /dev/null
+++ b/gradlePlugin/src/main/java/android/databinding/tool/DataBindingExportInfoTask.java
@@ -0,0 +1,77 @@
+/*
+ * 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 android.databinding.tool.util.L;
+import org.gradle.api.DefaultTask;
+import org.gradle.api.tasks.TaskAction;
+import kotlin.properties.Delegates;
+import java.io.File;
+
+/**
+ * Task to pass environment info to javac
+ */
+public class DataBindingExportInfoTask extends DefaultTask {
+ private LayoutXmlProcessor xmlProcessor;
+ private File sdkDir;
+ private File xmlOutFolder;
+ private File exportClassListTo;
+ private boolean enableDebugLogs = false;
+ @TaskAction
+ public void exportInfo() {
+ xmlProcessor.writeInfoClass(sdkDir, xmlOutFolder, exportClassListTo, enableDebugLogs);
+ }
+
+ public LayoutXmlProcessor getXmlProcessor() {
+ return xmlProcessor;
+ }
+
+ public void setXmlProcessor(LayoutXmlProcessor xmlProcessor) {
+ this.xmlProcessor = xmlProcessor;
+ }
+
+ public File getSdkDir() {
+ return sdkDir;
+ }
+
+ public void setSdkDir(File sdkDir) {
+ this.sdkDir = sdkDir;
+ }
+
+ public File getXmlOutFolder() {
+ return xmlOutFolder;
+ }
+
+ public void setXmlOutFolder(File xmlOutFolder) {
+ this.xmlOutFolder = xmlOutFolder;
+ }
+
+ public File getExportClassListTo() {
+ return exportClassListTo;
+ }
+
+ public void setExportClassListTo(File exportClassListTo) {
+ this.exportClassListTo = exportClassListTo;
+ }
+
+ public boolean isEnableDebugLogs() {
+ return enableDebugLogs;
+ }
+
+ public void setEnableDebugLogs(boolean enableDebugLogs) {
+ this.enableDebugLogs = enableDebugLogs;
+ }
+} \ No newline at end of file
diff --git a/gradlePlugin/src/main/java/android/databinding/tool/DataBindingProcessLayoutsTask.java b/gradlePlugin/src/main/java/android/databinding/tool/DataBindingProcessLayoutsTask.java
new file mode 100644
index 00000000..7a6100d2
--- /dev/null
+++ b/gradlePlugin/src/main/java/android/databinding/tool/DataBindingProcessLayoutsTask.java
@@ -0,0 +1,87 @@
+/*
+ * 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 android.databinding.tool.util.L;
+
+import org.gradle.api.DefaultTask;
+import org.gradle.api.tasks.TaskAction;
+import org.xml.sax.SAXException;
+import java.io.File;
+import java.io.IOException;
+
+import javax.xml.bind.JAXBException;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPathExpressionException;
+
+/**
+ * Task that parses xml files and generated metadata.
+ * Will be removed when aapt supports binding tags.
+ */
+public class DataBindingProcessLayoutsTask extends DefaultTask {
+
+ private LayoutXmlProcessor xmlProcessor;
+
+ private File sdkDir;
+
+ private File xmlOutFolder;
+
+ private int minSdk;
+
+ @TaskAction
+ public void processResources()
+ throws ParserConfigurationException, SAXException, XPathExpressionException,
+ IOException {
+ L.d("running process layouts task %s", getName());
+ xmlProcessor.processResources(minSdk);
+ }
+
+ public void writeLayoutXmls() throws JAXBException {
+ xmlProcessor.writeLayoutInfoFiles(xmlOutFolder);
+ }
+
+ public LayoutXmlProcessor getXmlProcessor() {
+ return xmlProcessor;
+ }
+
+ public void setXmlProcessor(LayoutXmlProcessor xmlProcessor) {
+ this.xmlProcessor = xmlProcessor;
+ }
+
+ public File getSdkDir() {
+ return sdkDir;
+ }
+
+ public void setSdkDir(File sdkDir) {
+ this.sdkDir = sdkDir;
+ }
+
+ public File getXmlOutFolder() {
+ return xmlOutFolder;
+ }
+
+ public void setXmlOutFolder(File xmlOutFolder) {
+ this.xmlOutFolder = xmlOutFolder;
+ }
+
+ public int getMinSdk() {
+ return minSdk;
+ }
+
+ public void setMinSdk(int minSdk) {
+ this.minSdk = minSdk;
+ }
+}