diff options
Diffstat (limited to 'src/tools/android/java/com/google')
7 files changed, 244 insertions, 40 deletions
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceParsingAction.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceParsingAction.java new file mode 100644 index 0000000000..e48440db48 --- /dev/null +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceParsingAction.java @@ -0,0 +1,81 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// 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 com.google.devtools.build.android; + +import com.google.common.base.Preconditions; +import com.google.common.base.Stopwatch; +import com.google.common.collect.ImmutableList; +import com.google.devtools.build.android.Converters.PathConverter; +import com.google.devtools.build.android.Converters.UnvalidatedAndroidDirectoriesConverter; +import com.google.devtools.common.options.Option; +import com.google.devtools.common.options.OptionsBase; +import com.google.devtools.common.options.OptionsParser; +import java.nio.file.Path; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +/** + * Parses android resource XML files from a directory and serializes the results to a protobuf. + * Other actions that depend on the same resource directory can then load the data from a single + * protobuf instead of reparsing multiple tiny XML files from source (proto loading is faster). + */ +public class AndroidResourceParsingAction { + + private static final Logger logger = + Logger.getLogger(AndroidResourceParsingAction.class.getName()); + + /** + * Flag specifications for this action. + */ + public static final class Options extends OptionsBase { + + @Option(name = "primaryData", + defaultValue = "null", + converter = UnvalidatedAndroidDirectoriesConverter.class, + category = "input", + help = "The resource and asset directories to parse and summarize in a symbols file." + + " The expected format is resources[#resources]:assets[#assets]") + public UnvalidatedAndroidDirectories primaryData; + + @Option(name = "output", + defaultValue = "null", + converter = PathConverter.class, + category = "output", + help = "Path to write the output protobuf.") + public Path output; + } + + public static void main(String[] args) throws Exception { + OptionsParser optionsParser = OptionsParser.newOptionsParser(Options.class); + optionsParser.parseAndExitUponError(args); + Options options = optionsParser.getOptions(Options.class); + + Preconditions.checkNotNull(options.primaryData); + Preconditions.checkNotNull(options.output); + + final Stopwatch timer = Stopwatch.createStarted(); + ParsedAndroidData parsedPrimary = ParsedAndroidData.from(options.primaryData); + logger.fine(String.format("Walked XML tree at %dms", timer.elapsed(TimeUnit.MILLISECONDS))); + UnwrittenMergedAndroidData unwrittenData = UnwrittenMergedAndroidData.of( + null, + parsedPrimary, + ParsedAndroidData.from(ImmutableList.<DependencyAndroidData>of())); + AndroidDataSerializer serializer = AndroidDataSerializer.create(); + unwrittenData.serializeTo(serializer); + serializer.flushTo(options.output); + logger.fine(String.format( + "Finished parse + serialize in %dms", timer.elapsed(TimeUnit.MILLISECONDS))); + } + +} diff --git a/src/tools/android/java/com/google/devtools/build/android/BUILD b/src/tools/android/java/com/google/devtools/build/android/BUILD index 9a4d1369fd..ac29480278 100644 --- a/src/tools/android/java/com/google/devtools/build/android/BUILD +++ b/src/tools/android/java/com/google/devtools/build/android/BUILD @@ -26,6 +26,14 @@ java_binary( ) java_binary( + name = "AndroidResourceParsingAction", + main_class = "com.google.devtools.build.android.AndroidResourceParsingAction", + runtime_deps = [ + ":android_builder_lib", + ], +) + +java_binary( name = "AndroidResourceProcessingAction", main_class = "com.google.devtools.build.android.AndroidResourceProcessingAction", runtime_deps = [ diff --git a/src/tools/android/java/com/google/devtools/build/android/BUILD.tools b/src/tools/android/java/com/google/devtools/build/android/BUILD.tools index abbe55f3fc..612936fd71 100644 --- a/src/tools/android/java/com/google/devtools/build/android/BUILD.tools +++ b/src/tools/android/java/com/google/devtools/build/android/BUILD.tools @@ -14,6 +14,14 @@ java_binary( ) java_binary( + name = "AndroidResourceParsingAction", + main_class = "com.google.devtools.build.android.AndroidResourceParsingAction", + runtime_deps = [ + ":classes", + ], +) + +java_binary( name = "AndroidResourceProcessingAction", main_class = "com.google.devtools.build.android.AndroidResourceProcessingAction", runtime_deps = [ diff --git a/src/tools/android/java/com/google/devtools/build/android/Converters.java b/src/tools/android/java/com/google/devtools/build/android/Converters.java index bcbfa97785..464e793872 100644 --- a/src/tools/android/java/com/google/devtools/build/android/Converters.java +++ b/src/tools/android/java/com/google/devtools/build/android/Converters.java @@ -67,8 +67,30 @@ public final class Converters { @Override public String getTypeDescription() { - return "unvalidated android data in the format " - + "resources[#resources]:assets[#assets]:manifest"; + return "unvalidated android data in the format " + UnvalidatedAndroidData.expectedFormat(); + } + } + + /** + * Converter for {@link UnvalidatedAndroidDirectories}. + */ + public static class UnvalidatedAndroidDirectoriesConverter + implements Converter<UnvalidatedAndroidDirectories> { + + @Override + public UnvalidatedAndroidDirectories convert(String input) throws OptionsParsingException { + try { + return UnvalidatedAndroidDirectories.valueOf(input); + } catch (IllegalArgumentException e) { + throw new OptionsParsingException( + String.format("invalid UnvalidatedAndroidDirectories: %s", e.getMessage()), e); + } + } + + @Override + public String getTypeDescription() { + return "unvalidated android directories in the format " + + UnvalidatedAndroidDirectories.expectedFormat(); } } diff --git a/src/tools/android/java/com/google/devtools/build/android/ParsedAndroidData.java b/src/tools/android/java/com/google/devtools/build/android/ParsedAndroidData.java index 47d3d30af5..6a06ca33b2 100644 --- a/src/tools/android/java/com/google/devtools/build/android/ParsedAndroidData.java +++ b/src/tools/android/java/com/google/devtools/build/android/ParsedAndroidData.java @@ -352,7 +352,7 @@ public class ParsedAndroidData { * @throws IOException when there are issues with reading files. * @throws MergingException when there is invalid resource information. */ - public static ParsedAndroidData from(UnvalidatedAndroidData primary) + public static ParsedAndroidData from(UnvalidatedAndroidDirectories primary) throws IOException, MergingException { final ParsedAndroidDataBuildingPathWalker pathWalker = ParsedAndroidDataBuildingPathWalker.create(Builder.newBuilder()); @@ -384,10 +384,10 @@ public class ParsedAndroidData { /** * Parses resource symbols including "@+id/resourceName" (optional for now). * - * @see ParsedAndroidData#from(UnvalidatedAndroidData) + * @see ParsedAndroidData#from(UnvalidatedAndroidDirectories) */ @VisibleForTesting - static ParsedAndroidData parseWithIds(UnvalidatedAndroidData primary) + static ParsedAndroidData parseWithIds(UnvalidatedAndroidDirectories primary) throws IOException, MergingException { Builder builder = Builder.newBuilder().enableIdParsing(); final ParsedAndroidDataBuildingPathWalker pathWalker = diff --git a/src/tools/android/java/com/google/devtools/build/android/UnvalidatedAndroidData.java b/src/tools/android/java/com/google/devtools/build/android/UnvalidatedAndroidData.java index 9f43441692..beeeba7e37 100644 --- a/src/tools/android/java/com/google/devtools/build/android/UnvalidatedAndroidData.java +++ b/src/tools/android/java/com/google/devtools/build/android/UnvalidatedAndroidData.java @@ -15,10 +15,8 @@ package com.google.devtools.build.android; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; -import java.io.IOException; import java.nio.file.FileSystem; import java.nio.file.FileSystems; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; import java.util.regex.Pattern; @@ -30,8 +28,12 @@ import java.util.regex.Pattern; * {@link UnvalidatedAndroidData} -> {@link MergedAndroidData} -> {@link DensityFilteredAndroidData} * -> {@link DependencyAndroidData} */ -class UnvalidatedAndroidData { - static final Pattern VALID_REGEX = Pattern.compile(".*:.*:.+"); +class UnvalidatedAndroidData extends UnvalidatedAndroidDirectories { + private static final Pattern VALID_REGEX = Pattern.compile(".*:.*:.+"); + + static String expectedFormat() { + return "resources[#resources]:assets[#assets]:manifest"; + } public static UnvalidatedAndroidData valueOf(String text) { return valueOf(text, FileSystems.getDefault()); @@ -41,7 +43,7 @@ class UnvalidatedAndroidData { static UnvalidatedAndroidData valueOf(String text, FileSystem fileSystem) { if (!VALID_REGEX.matcher(text).find()) { throw new IllegalArgumentException( - text + " is not in the format 'resources[#resources]:assets[#assets]:manifest'"); + text + " is not in the format '" + expectedFormat() + "'"); } String[] parts = text.split(":"); return new UnvalidatedAndroidData( @@ -50,32 +52,11 @@ class UnvalidatedAndroidData { exists(fileSystem.getPath(parts[2]))); } - private static ImmutableList<Path> splitPaths(String pathsString, FileSystem fileSystem) { - if (pathsString.length() == 0) { - return ImmutableList.of(); - } - ImmutableList.Builder<Path> paths = new ImmutableList.Builder<>(); - for (String pathString : pathsString.split("#")) { - paths.add(exists(fileSystem.getPath(pathString))); - } - return paths.build(); - } - - private static Path exists(Path path) { - if (!Files.exists(path)) { - throw new IllegalArgumentException(path + " does not exist"); - } - return path; - } - private final Path manifest; - private final ImmutableList<Path> assetDirs; - private final ImmutableList<Path> resourceDirs; public UnvalidatedAndroidData( ImmutableList<Path> resourceDirs, ImmutableList<Path> assetDirs, Path manifest) { - this.resourceDirs = resourceDirs; - this.assetDirs = assetDirs; + super(resourceDirs, assetDirs); this.manifest = manifest; } @@ -107,12 +88,4 @@ class UnvalidatedAndroidData { && Objects.equals(other.manifest, manifest); } - public void walk(final AndroidDataPathWalker pathWalker) throws IOException { - for (Path path : resourceDirs) { - pathWalker.walkResources(path); - } - for (Path path : assetDirs) { - pathWalker.walkAssets(path); - } - } } diff --git a/src/tools/android/java/com/google/devtools/build/android/UnvalidatedAndroidDirectories.java b/src/tools/android/java/com/google/devtools/build/android/UnvalidatedAndroidDirectories.java new file mode 100644 index 0000000000..f87da7fbf0 --- /dev/null +++ b/src/tools/android/java/com/google/devtools/build/android/UnvalidatedAndroidDirectories.java @@ -0,0 +1,112 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// 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 com.google.devtools.build.android; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.regex.Pattern; + +/** + * Android resource and asset directories that can be parsed. + */ +public class UnvalidatedAndroidDirectories { + + private static final Pattern VALID_REGEX = Pattern.compile(".*:.*"); + + static String expectedFormat() { + return "resources[#resources]:assets[#assets]"; + } + + public static UnvalidatedAndroidDirectories valueOf(String text) { + return valueOf(text, FileSystems.getDefault()); + } + + @VisibleForTesting + static UnvalidatedAndroidDirectories valueOf(String text, FileSystem fileSystem) { + if (!VALID_REGEX.matcher(text).find()) { + throw new IllegalArgumentException( + text + " is not in the format '" + expectedFormat() + "'"); + } + String[] parts = text.split(":"); + return new UnvalidatedAndroidDirectories( + parts.length > 0 ? splitPaths(parts[0], fileSystem) : ImmutableList.<Path>of(), + parts.length > 1 ? splitPaths(parts[1], fileSystem) : ImmutableList.<Path>of()); + } + + protected static ImmutableList<Path> splitPaths(String pathsString, FileSystem fileSystem) { + if (pathsString.length() == 0) { + return ImmutableList.of(); + } + ImmutableList.Builder<Path> paths = new ImmutableList.Builder<>(); + for (String pathString : pathsString.split("#")) { + paths.add(exists(fileSystem.getPath(pathString))); + } + return paths.build(); + } + + protected static Path exists(Path path) { + if (!Files.exists(path)) { + throw new IllegalArgumentException(path + " does not exist"); + } + return path; + } + + protected final ImmutableList<Path> assetDirs; + protected final ImmutableList<Path> resourceDirs; + + public UnvalidatedAndroidDirectories( + ImmutableList<Path> resourceDirs, ImmutableList<Path> assetDirs) { + this.resourceDirs = resourceDirs; + this.assetDirs = assetDirs; + } + + void walk(final AndroidDataPathWalker pathWalker) throws IOException { + for (Path path : resourceDirs) { + pathWalker.walkResources(path); + } + for (Path path : assetDirs) { + pathWalker.walkAssets(path); + } + } + + @Override + public String toString() { + return String.format("UnvalidatedAndroidDirectories(%s, %s)", resourceDirs, assetDirs); + } + + @Override + public int hashCode() { + return Objects.hash(resourceDirs, assetDirs); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof UnvalidatedAndroidDirectories)) { + return false; + } + UnvalidatedAndroidDirectories other = (UnvalidatedAndroidDirectories) obj; + return Objects.equals(other.resourceDirs, resourceDirs) + && Objects.equals(other.assetDirs, assetDirs); + } + +} |