diff options
author | 2017-05-03 19:36:38 +0200 | |
---|---|---|
committer | 2017-05-04 13:13:25 +0200 | |
commit | 3c87960ba24397f0e155691bfae2e4cea1d03cfb (patch) | |
tree | 19b23e3c1429f117b1d8ad9d3a3cd9f341e48e7a /src/tools/android/java/com/google/devtools/build/android/resources | |
parent | a6ad2d5564ad8ce7c7ebd0ba093db578cf5ae3cf (diff) |
* Fork the deprecated SymbolLoader/SymbolWriter code from com.android.builder.internal
* Fixed formatting.
RELNOTES: None
PiperOrigin-RevId: 154973113
Diffstat (limited to 'src/tools/android/java/com/google/devtools/build/android/resources')
2 files changed, 151 insertions, 80 deletions
diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java b/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java index 5d414bf11f..a95c0bea7c 100644 --- a/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java +++ b/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java @@ -14,11 +14,11 @@ package com.google.devtools.build.android.resources; import com.android.SdkConstants; -import com.android.builder.internal.SymbolLoader.SymbolEntry; import com.android.resources.ResourceType; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.collect.Table; +import com.google.devtools.build.android.resources.ResourceSymbols.RTxtSymbolEntry; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -57,11 +57,8 @@ public class RClassGenerator { * @param finalFields true if the fields should be marked final */ public static RClassGenerator fromSymbols( - Path outFolder, - ResourceSymbols values, - boolean finalFields) - throws IOException { - Table<String, String, SymbolEntry> valuesTable = values.asTable(); + Path outFolder, ResourceSymbols values, boolean finalFields) { + Table<String, String, RTxtSymbolEntry> valuesTable = values.asTable(); Map<ResourceType, List<FieldInitializer>> initializers = getInitializers(valuesTable); return new RClassGenerator(outFolder, initializers, finalFields); @@ -84,7 +81,7 @@ public class RClassGenerator { } /** Convert the {@link ResourceSymbols} data, to a map of {@link FieldInitializer}. */ private static Map<ResourceType, List<FieldInitializer>> getInitializers( - Table<String, String, SymbolEntry> values) { + Table<String, String, RTxtSymbolEntry> values) { Map<ResourceType, List<FieldInitializer>> initializers = new EnumMap<>(ResourceType.class); for (String typeName : values.rowKeySet()) { ResourceType resourceType = ResourceType.getEnum(typeName); @@ -95,14 +92,13 @@ public class RClassGenerator { } private static List<FieldInitializer> getInitializers( - String typeName, - Table<String, String, SymbolEntry> symbols) { - Map<String, SymbolEntry> rowMap = symbols.row(typeName); + String typeName, Table<String, String, RTxtSymbolEntry> symbols) { + Map<String, RTxtSymbolEntry> rowMap = symbols.row(typeName); List<String> symbolList = new ArrayList<>(rowMap.keySet()); Collections.sort(symbolList); List<FieldInitializer> initializers = new ArrayList<>(); for (String symbolName : symbolList) { - SymbolEntry value = symbols.get(typeName, symbolName); + RTxtSymbolEntry value = symbols.get(typeName, symbolName); if (value.getType().equals("int")) { initializers.add(IntFieldInitializer.of(value.getName(), value.getValue())); } else { diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java b/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java index 051bd58de3..8151a9d06d 100644 --- a/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java +++ b/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java @@ -13,11 +13,9 @@ // limitations under the License. package com.google.devtools.build.android.resources; +import com.android.SdkConstants; import com.android.builder.core.VariantConfiguration; import com.android.builder.dependency.SymbolFileProvider; -import com.android.builder.internal.SymbolLoader; -import com.android.builder.internal.SymbolLoader.SymbolEntry; -import com.android.builder.internal.SymbolWriter; import com.android.resources.ResourceType; import com.android.utils.ILogger; import com.google.common.collect.HashBasedTable; @@ -26,41 +24,100 @@ import com.google.common.collect.Multimap; import com.google.common.collect.Table; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; +import java.io.BufferedWriter; import java.io.File; import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; +import java.util.logging.Logger; import javax.annotation.Nullable; -/** - * Wraps the {@link SymbolLoader} and {@link SymbolWriter} classes. - * This provides a unified interface for working with R.txts. - */ +/** This provides a unified interface for working with R.txt symbols files. */ public class ResourceSymbols { + private static final Logger logger = Logger.getLogger(ResourceSymbols.class.getCanonicalName()); + + /** Represents a resource symbol with a value. */ + // Forked from com.android.builder.internal.SymbolLoader.SymbolEntry. + static class RTxtSymbolEntry { + private final String name; + private final String type; + private final String value; + + public RTxtSymbolEntry(String name, String type, String value) { + this.name = name; + this.type = type; + this.value = value; + } + + public String getValue() { + return value; + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + } + /** Task to load and parse R.txt symbols */ private static final class SymbolLoadingTask implements Callable<ResourceSymbols> { - private final SymbolLoader symbolLoader; + private final Path rTxtSymbols; - SymbolLoadingTask(SymbolLoader symbolLoader) { - this.symbolLoader = symbolLoader; + SymbolLoadingTask(Path symbolFile) { + this.rTxtSymbols = symbolFile; } @Override public ResourceSymbols call() throws Exception { - symbolLoader.load(); - return ResourceSymbols.wrap(symbolLoader); + List<String> lines = Files.readAllLines(rTxtSymbols, StandardCharsets.UTF_8); + + Table<String, String, RTxtSymbolEntry> mSymbols = HashBasedTable.create(); + + for (int lineIndex = 1; lineIndex <= lines.size(); lineIndex++) { + String line = null; + try { + line = lines.get(lineIndex - 1); + + // format is "<type> <class> <name> <value>" + // don't want to split on space as value could contain spaces. + int pos = line.indexOf(' '); + String type = line.substring(0, pos); + int pos2 = line.indexOf(' ', pos + 1); + String className = line.substring(pos + 1, pos2); + int pos3 = line.indexOf(' ', pos2 + 1); + String name = line.substring(pos2 + 1, pos3); + String value = line.substring(pos3 + 1); + + mSymbols.put(className, name, new RTxtSymbolEntry(name, type, value)); + } catch (IndexOutOfBoundsException e) { + String s = + String.format( + "File format error reading %s\tline %d: '%s'", + rTxtSymbols.toString(), lineIndex, line); + logger.severe(s); + throw new IOException(s, e); + } + } + return ResourceSymbols.from(mSymbols); } } @@ -104,72 +161,38 @@ public class ResourceSymbols { for (Entry<SymbolFileProvider, ListenableFuture<String>> entry : providerToPackage.entrySet()) { File symbolFile = entry.getKey().getSymbolFile(); if (!Objects.equals(entry.getValue().get(), packageToExclude)) { - packageToTable.put(entry.getValue().get(), load(executor, iLogger, symbolFile)); + packageToTable.put(entry.getValue().get(), load(symbolFile.toPath(), executor)); } } return packageToTable; } - public static ResourceSymbols merge(Collection<ResourceSymbols> symbolTables) throws IOException { - final Table<String, String, SymbolEntry> mergedTable = HashBasedTable.create(); + public static ResourceSymbols from(Table<String, String, RTxtSymbolEntry> table) { + return new ResourceSymbols(table); + } + + public static ResourceSymbols merge(Collection<ResourceSymbols> symbolTables) { + final Table<String, String, RTxtSymbolEntry> mergedTable = HashBasedTable.create(); for (ResourceSymbols symbolTableProvider : symbolTables) { mergedTable.putAll(symbolTableProvider.asTable()); } - try { - SymbolLoader nullLoader = new SymbolLoader(null, null); - Field declaredField = SymbolLoader.class.getDeclaredField("mSymbols"); - declaredField.setAccessible(true); - declaredField.set(nullLoader, mergedTable); - return wrap(nullLoader); - } catch (NoSuchFieldException - | SecurityException - | IllegalArgumentException - | IllegalAccessException e) { - throw new IOException(e); - } + return from(mergedTable); } /** Read the symbols from the provided symbol file. */ public static ListenableFuture<ResourceSymbols> load( - Path primaryRTxt, ListeningExecutorService executorService, ILogger iLogger) { - return load(executorService, iLogger, primaryRTxt.toFile()); + Path primaryRTxt, ListeningExecutorService executorService) { + return executorService.submit(new SymbolLoadingTask(primaryRTxt)); } - public static ListenableFuture<ResourceSymbols> load( - ListeningExecutorService executor, ILogger iLogger, File symbolFile) { - return executor.submit(new SymbolLoadingTask(new SymbolLoader(symbolFile, iLogger))); - } + private final Table<String, String, RTxtSymbolEntry> values; - static ResourceSymbols of(Path rTxt, ILogger logger) { - return of(rTxt.toFile(), logger); + private ResourceSymbols(Table<String, String, RTxtSymbolEntry> values) { + this.values = values; } - public static ResourceSymbols of(File rTxt, ILogger logger) { - return wrap(new SymbolLoader(rTxt, logger)); - } - - private static ResourceSymbols wrap(SymbolLoader input) { - return new ResourceSymbols(input); - } - - private final SymbolLoader symbolLoader; - - private ResourceSymbols(SymbolLoader symbolLoader) { - this.symbolLoader = symbolLoader; - } - - public Table<String, String, SymbolEntry> asTable() throws IOException { - // TODO(bazel-team): remove when we update android_ide_common to a version w/ public visibility - try { - Method getSymbols = SymbolLoader.class.getDeclaredMethod("getSymbols"); - getSymbols.setAccessible(true); - @SuppressWarnings("unchecked") - Table<String, String, SymbolEntry> result = - (Table<String, String, SymbolEntry>) getSymbols.invoke(symbolLoader); - return result; - } catch (ReflectiveOperationException e) { - throw new IOException(e); - } + public Table<String, String, RTxtSymbolEntry> asTable() { + return values; } /** @@ -183,19 +206,71 @@ public class ResourceSymbols { public void writeTo( Path sourceOut, String packageName, Collection<ResourceSymbols> packageSymbols) throws IOException { - SymbolWriter writer = new SymbolWriter(sourceOut.toString(), packageName, symbolLoader); + + Table<String, String, RTxtSymbolEntry> symbols = HashBasedTable.create(); for (ResourceSymbols packageSymbol : packageSymbols) { - writer.addSymbolsToWrite(packageSymbol.symbolLoader); + symbols.putAll(packageSymbol.asTable()); + } + + Path packageOut = sourceOut.resolve(packageName.replace('.', File.separatorChar)); + Files.createDirectories(packageOut); + + Path file = packageOut.resolve(SdkConstants.FN_RESOURCE_CLASS); + + try (BufferedWriter writer = Files.newBufferedWriter(file, StandardOpenOption.CREATE_NEW)) { + + writer.write("/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"); + writer.write(" *\n"); + writer.write(" * This class was automatically generated by the\n"); + writer.write(" * aapt tool from the resource data it found. It\n"); + writer.write(" * should not be modified by hand.\n"); + writer.write(" */\n"); + + writer.write("package "); + writer.write(packageName); + writer.write(";\n\npublic final class R {\n"); + + Set<String> rowSet = symbols.rowKeySet(); + List<String> rowList = new ArrayList<>(rowSet); + Collections.sort(rowList); + + for (String row : rowList) { + writer.write("\tpublic static final class "); + writer.write(row); + writer.write(" {\n"); + + Map<String, RTxtSymbolEntry> rowMap = symbols.row(row); + Set<String> symbolSet = rowMap.keySet(); + List<String> symbolList = new ArrayList<>(symbolSet); + Collections.sort(symbolList); + + for (String symbolName : symbolList) { + // get the matching SymbolEntry from the values Table. + RTxtSymbolEntry value = values.get(row, symbolName); + if (value != null) { + writer.write("\t\tpublic static final "); + writer.write(value.getType()); + writer.write(" "); + writer.write(value.getName()); + writer.write(" = "); + writer.write(value.getValue()); + writer.write(";\n"); + } + } + + writer.write("\t}\n"); + } + + writer.write("}\n"); } - writer.write(); } - public Map<ResourceType, Set<String>> asFilterMap() throws IOException { + public Map<ResourceType, Set<String>> asFilterMap() { Map<ResourceType, Set<String>> filter = new EnumMap<>(ResourceType.class); - Table<String, String, SymbolEntry> symbolTable = asTable(); + Table<String, String, RTxtSymbolEntry> symbolTable = asTable(); for (String typeName : symbolTable.rowKeySet()) { Set<String> fields = new HashSet<>(); - for (SymbolEntry symbolEntry : symbolTable.row(typeName).values()) { + for (RTxtSymbolEntry symbolEntry : symbolTable.row(typeName).values()) { fields.add(symbolEntry.getName()); } if (!fields.isEmpty()) { |