blob: 2d377d42a4ae3a021c4f7c3b17f09c9662f70ebb [file] [log] [blame]
/*
* 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.processing.Scope;
import android.databinding.tool.processing.ScopedException;
import android.databinding.tool.util.L;
import android.databinding.tool.util.Preconditions;
import android.databinding.tool.writer.JavaFileWriter;
import com.google.common.collect.ImmutableList;
import java.util.Arrays;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
* This class is used by Android Gradle plugin.
*/
@SuppressWarnings("unused")
public class DataBindingBuilder {
Versions mVersions;
private static final List<String> EXCLUDE_PATTERNS =
Arrays.asList("android/databinding/layouts/*.*",
"androidx/databinding/layouts/*.*");
public static final String PROCESSOR_NAME =
"android.databinding.annotationprocessor.ProcessDataBinding";
public static final String ARTIFACT_BASE_CLASSES_DIR_FROM_LIBS = "dependent-lib-base-classes";
public static final String INCREMENTAL_BIN_AAR_DIR = "bin-files";
public static final String INCREMENTAL_BINDING_CLASSES_LIST_DIR = "binding-class-list";
public static final String DATA_BINDING_ROOT_FOLDER_IN_AAR = "data-binding";
public static final String DATA_BINDING_CLASS_LOG_ROOT_FOLDER_IN_AAR =
"data-binding-base-class-log";
public static final String BR_FILE_EXT = "-br.bin";
public static final String LAYOUT_INFO_FILE_EXT = "-layoutinfo.bin";
private static final String SETTER_STORE_FILE_EXT = "-setter_store.bin";
private static final String SETTER_STORE_JSON_FILE_EXT = "-setter_store.json";
public static final List<String> RESOURCE_FILE_EXTENSIONS =
ImmutableList.of(BR_FILE_EXT, LAYOUT_INFO_FILE_EXT, SETTER_STORE_FILE_EXT,
SETTER_STORE_JSON_FILE_EXT);
public static final String BINDING_CLASS_LIST_SUFFIX = "-binding_classes.json";
public static final String FEATURE_PACKAGE_LIST_FILE_NAME = "all_features.json";
public static final String FEATURE_BR_OFFSET_FILE_NAME = "feature_data.json";
public String getCompilerVersion() {
return getVersions().compiler;
}
public String getBaseLibraryVersion(String compilerVersion) {
return getVersions().baseLibrary;
}
public String getLibraryVersion(String compilerVersion) {
return getVersions().extensions;
}
public String getBaseAdaptersVersion(String compilerVersion) {
return getVersions().extensions;
}
public void setPrintMachineReadableOutput(boolean machineReadableOutput) {
ScopedException.encodeOutput(machineReadableOutput);
}
public static boolean getPrintMachineReadableOutput() {
return ScopedException.isEncodeOutput();
}
public static void setDebugLogEnabled(boolean enableDebugLogs) {
L.setDebugLog(enableDebugLogs);
}
public boolean isDebugLogEnabled() {
return L.isDebugEnabled();
}
private Versions getVersions() {
if (mVersions != null) {
return mVersions;
}
try {
Properties props = new Properties();
InputStream stream = getClass().getResourceAsStream("/data_binding_version_info.properties");
try {
props.load(stream);
mVersions = new Versions(props);
} finally {
IOUtils.closeQuietly(stream);
}
} catch (IOException exception) {
L.e(exception, "Cannot read data binding version");
}
return mVersions;
}
/**
* Returns the list of classes that should be excluded from the packaging task.
*
* @param packageName The package name
* @param className the name of the trigger class
* @param generatedClassListFile The location of the File into which data binding compiler wrote
* list of generated classes
* @param dataBindingCompilerBuildFolder the build folder for the data binding compiler
* @return The list of classes to exclude. They are already in JNI format.
*/
public static List<String> getJarExcludeList(
String packageName,
String className,
File generatedClassListFile,
File dataBindingCompilerBuildFolder) {
List<String> excludes = new ArrayList<>();
String triggerClassAsFile = (packageName + "." + className).replace('.', '/');
excludes.add(triggerClassAsFile + ".class");
excludes.addAll(EXCLUDE_PATTERNS);
excludes.add(packageName.replace('.', '/') + "/BR.*");
for (String pkg : getBRFilePackages(dataBindingCompilerBuildFolder)) {
excludes.add(pkg.replace('.', '/') + "/BR.*");
}
if (generatedClassListFile != null) {
List<String> generatedClasses = readGeneratedClasses(generatedClassListFile);
for (String klass : generatedClasses) {
excludes.add(klass.replace('.', '/') + ".class");
}
}
Scope.assertNoError();
return excludes;
}
private static List<String> getBRFilePackages(File dependencyArtifactsDir) {
List<String> packages = new ArrayList<>();
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(
dependencyArtifactsDir.toPath())) {
for (Path path : directoryStream) {
String filename = path.getFileName().toString();
if (filename.endsWith("-br.bin")) {
packages.add(filename.substring(0, filename.indexOf('-')));
}
}
} catch (IOException e) {
L.e(e, "Error reading contents of %s directory", dependencyArtifactsDir);
}
return packages;
}
private static List<String> readGeneratedClasses(File generatedClassListFile) {
Preconditions.checkNotNull(generatedClassListFile,
"Data binding exclude generated task is not configured properly");
Preconditions.check(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);
}
L.e("Could not read data binding generated class list");
return null;
}
public JavaFileWriter createJavaFileWriter(File outFolder) {
return new GradleFileWriter(outFolder.getAbsolutePath());
}
public static class GradleFileWriter extends JavaFileWriter {
private final String outputBase;
public GradleFileWriter(String outputBase) {
this.outputBase = outputBase;
}
@Override
public void writeToFile(String canonicalName, String contents) {
File f = toFile(canonicalName);
//noinspection ResultOfMethodCallIgnored
f.getParentFile().mkdirs();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(f);
IOUtils.write(contents, fos);
} catch (IOException e) {
L.e(e, "cannot write file " + f.getAbsolutePath());
} finally {
IOUtils.closeQuietly(fos);
}
}
private File toFile(String canonicalName) {
String asPath = canonicalName.replace('.', File.separatorChar);
return new File(outputBase + File.separatorChar + asPath + ".java");
}
@Override
public void deleteFile(String canonicalName) {
FileUtils.deleteQuietly(toFile(canonicalName));
}
}
private static class Versions {
final String compilerCommon;
final String compiler;
final String baseLibrary;
final String extensions;
public Versions(Properties properties) {
compilerCommon = properties.getProperty("compilerCommon");
compiler = properties.getProperty("compiler");
baseLibrary = properties.getProperty("baseLibrary");
extensions = properties.getProperty("extensions");
Preconditions.checkNotNull(compilerCommon, "cannot read compiler common version");
Preconditions.checkNotNull(compiler, "cannot read compiler version");
Preconditions.checkNotNull(baseLibrary, "cannot read baseLibrary version");
Preconditions.checkNotNull(extensions, "cannot read extensions version");
}
}
}