diff options
author | Liam Miller-Cushon <cushon@google.com> | 2017-02-11 03:06:31 +0000 |
---|---|---|
committer | Dmitry Lomov <dslomov@google.com> | 2017-02-13 11:34:16 +0000 |
commit | 19cdec0dbd900c534df35d8da47843521c96f64d (patch) | |
tree | 9b0693d78f0cf5ee928043b11773abfbe313bd09 /src/java_tools/buildjar | |
parent | 3a6f6297917b9d97d83d8384e346e2c725819c3d (diff) |
Create a 'vanilla' JavaBuilder
that is portable across JDK versions, and doesn't depend on the javac
distributed with Bazel.
There is no support for Error Prone, strict Java deps, header compilation,
Android desugaring, or any other features that depend on the Bazel javac.
--
PiperOrigin-RevId: 147224490
MOS_MIGRATED_REVID=147224490
Diffstat (limited to 'src/java_tools/buildjar')
9 files changed, 579 insertions, 8 deletions
diff --git a/src/java_tools/buildjar/BUILD b/src/java_tools/buildjar/BUILD index b47b17ccc3..80d70e957f 100644 --- a/src/java_tools/buildjar/BUILD +++ b/src/java_tools/buildjar/BUILD @@ -7,10 +7,17 @@ java_binary( runtime_deps = ["//src/java_tools/buildjar/java/com/google/devtools/build/buildjar"], ) +java_binary( + name = "VanillaJavaBuilder", + main_class = "com.google.devtools.build.buildjar.VanillaJavaBuilder", + visibility = ["//visibility:public"], + runtime_deps = ["//src/java_tools/buildjar/java/com/google/devtools/build/buildjar:vanilla_java_builder"], +) + filegroup( name = "JavaBuilderDeploy", srcs = select({ - "//tools/jdk:jdk7": ["//third_party/java/jdk/javabuilder:JavaBuilder_0.1.0"], + "//tools/jdk:jdk7": [":VanillaJavaBuilder_deploy.jar"], "//conditions:default": [":JavaBuilder_deploy.jar"], }), ) @@ -22,6 +29,12 @@ filegroup( ) filegroup( + name = "bootstrap_VanillaJavaBuilder_deploy.jar", + srcs = ["//src/java_tools/buildjar/java/com/google/devtools/build/buildjar:bootstrap_VanillaJavaBuilder_deploy.jar"], + visibility = ["//visibility:public"], +) + +filegroup( name = "bootstrap_genclass_deploy.jar", srcs = ["//src/java_tools/buildjar/java/com/google/devtools/build/buildjar/genclass:bootstrap_genclass_deploy.jar"], visibility = ["//visibility:public"], @@ -43,7 +56,7 @@ filegroup( "//src/java_tools/buildjar/java/com/google/devtools/build/java/turbine:srcs", "//src/java_tools/buildjar/javatests/com/google/devtools/build/java/bazel:srcs", "//src/java_tools/buildjar/javatests/com/google/devtools/build/java/turbine:srcs", - "//src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar/resourcejar:srcs", + "//src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar:srcs", ], visibility = ["//src:__pkg__"], ) @@ -74,7 +87,7 @@ java_toolchain( extclasspath = ["//tools/jdk:extdir"], genclass = ["bootstrap_genclass_deploy.jar"], ijar = ["//third_party/ijar"], - javabuilder = ["//third_party/java/jdk/javabuilder:JavaBuilder_0.1.0"], + javabuilder = [":bootstrap_VanillaJavaBuilder_deploy.jar"], javac = ["//third_party/java/jdk/langtools:javac7_jar"], jvm_opts = [ "-XX:+TieredCompilation", diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/BUILD b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/BUILD index d05bdeec40..961904114f 100644 --- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/BUILD +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/BUILD @@ -55,6 +55,7 @@ java_library( exclude = [ "InvalidCommandLineException.java", "JarOwner.java", + "VanillaJavaBuilder.java", ], ), deps = [ @@ -154,6 +155,7 @@ bootstrap_java_binary( exclude = [ "java/com/google/devtools/build/buildjar/javac/testing/**", "JarOwner.java", + "VanillaJavaBuilder.java", ], ), main_class = "com.google.devtools.build.buildjar.BazelJavaBuilder", @@ -174,6 +176,42 @@ bootstrap_java_library( ], ) +bootstrap_java_binary( + name = "bootstrap_VanillaJavaBuilder", + srcs = [ + "InvalidCommandLineException.java", + "JarOwner.java", + "OptionsParser.java", + "VanillaJavaBuilder.java", + ], + main_class = "com.google.devtools.build.buildjar.VanillaJavaBuilder", + deps = [ + ":skylark-deps", + "//src/java_tools/buildjar/java/com/google/devtools/build/buildjar/jarhelper:bootstrap_jarhelper", + "//src/java_tools/buildjar/java/com/google/devtools/build/buildjar/resourcejar:bootstrap_resourcejar", + ], +) + +java_binary( + name = "VanillaJavaBuilder", + main_class = "com.google.devtools.build.buildjar.VanillaJavaBuilder", + runtime_deps = [":vanilla_java_builder"], +) + +java_library( + name = "vanilla_java_builder", + srcs = ["VanillaJavaBuilder.java"], + deps = [ + ":optionsparser", + "//src/java_tools/buildjar/java/com/google/devtools/build/buildjar/jarhelper", + "//src/java_tools/buildjar/java/com/google/devtools/build/buildjar/resourcejar", + "//src/main/protobuf:deps_java_proto", + "//src/main/protobuf:java_compilation_java_proto", + "//src/main/protobuf:worker_protocol_java_proto", + "//third_party:guava", + ], +) + filegroup( name = "srcs", srcs = glob(["**"]) + [ diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/VanillaJavaBuilder.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/VanillaJavaBuilder.java new file mode 100644 index 0000000000..77620674a7 --- /dev/null +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/VanillaJavaBuilder.java @@ -0,0 +1,340 @@ +// Copyright 2017 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.buildjar; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.Locale.ENGLISH; + +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.Iterables; +import com.google.devtools.build.buildjar.jarhelper.JarCreator; +import com.google.devtools.build.buildjar.proto.JavaCompilation.Manifest; +import com.google.devtools.build.buildjar.resourcejar.ResourceJarBuilder; +import com.google.devtools.build.buildjar.resourcejar.ResourceJarOptions; +import com.google.devtools.build.lib.view.proto.Deps; +import com.google.devtools.build.lib.worker.WorkerProtocol.WorkRequest; +import com.google.devtools.build.lib.worker.WorkerProtocol.WorkResponse; +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.processing.Processor; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaCompiler; +import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; + +/** + * A JavaBuilder that supports non-standard JDKs and unmodified javac's. + * + * <p>Does not support: + * + * <ul> + * <li>Error Prone + * <li>strict Java deps + * <li>header compilation + * <li>Android desugaring + * <li>coverage instrumentation + * <li>genclass handling for IDEs + * </ul> + */ +public class VanillaJavaBuilder implements Closeable { + + /** Cache of opened zip filesystems. */ + private final Map<Path, FileSystem> filesystems = new HashMap<>(); + + private FileSystem getJarFileSystem(Path sourceJar) throws IOException { + FileSystem fs = filesystems.get(sourceJar); + if (fs == null) { + filesystems.put(sourceJar, fs = FileSystems.newFileSystem(sourceJar, null)); + } + return fs; + } + + public static void main(String[] args) throws IOException { + if (args.length == 1 && args[0].equals("--persistent_worker")) { + System.exit(runPersistentWorker()); + } else { + try (VanillaJavaBuilder builder = new VanillaJavaBuilder()) { + VanillaJavaBuilderResult result = builder.run(ImmutableList.copyOf(args)); + System.err.print(result.output()); + System.exit(result.ok() ? 0 : 1); + } + } + } + + private static int runPersistentWorker() { + while (true) { + try { + WorkRequest request = WorkRequest.parseDelimitedFrom(System.in); + if (request == null) { + break; + } + try (VanillaJavaBuilder builder = new VanillaJavaBuilder()) { + VanillaJavaBuilderResult result = builder.run(request.getArgumentsList()); + WorkResponse response = + WorkResponse.newBuilder() + .setOutput(result.output()) + .setExitCode(result.ok() ? 0 : 1) + .build(); + response.writeDelimitedTo(System.out); + } + System.out.flush(); + } catch (IOException e) { + e.printStackTrace(); + return 1; + } + } + return 0; + } + + /** Return result of a {@link VanillaJavaBuilder} build. */ + public static class VanillaJavaBuilderResult { + private final boolean ok; + private final String output; + + public VanillaJavaBuilderResult(boolean ok, String output) { + this.ok = ok; + this.output = output; + } + + /** True if the compilation was succesfull. */ + public boolean ok() { + return ok; + } + + /** Log output from the compilation. */ + public String output() { + return output; + } + } + + public VanillaJavaBuilderResult run(List<String> args) throws IOException { + OptionsParser optionsParser; + try { + optionsParser = new OptionsParser(args); + } catch (InvalidCommandLineException e) { + return new VanillaJavaBuilderResult(false, e.getMessage()); + } + DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<>(); + StringWriter output = new StringWriter(); + JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fileManager = + javaCompiler.getStandardFileManager(diagnosticCollector, ENGLISH, UTF_8); + setLocations(optionsParser, fileManager); + ImmutableList<JavaFileObject> sources = getSources(optionsParser, fileManager); + boolean ok; + if (sources.isEmpty()) { + ok = true; + } else { + CompilationTask task = + javaCompiler.getTask( + new PrintWriter(output, true), + fileManager, + diagnosticCollector, + optionsParser.getJavacOpts(), + ImmutableList.<String>of() /*classes*/, + sources); + setProcessors(optionsParser, fileManager, task); + ok = task.call(); + } + if (ok) { + writeOutput(optionsParser); + } + writeGeneratedSourceOutput(optionsParser); + // the jdeps output doesn't include any information about dependencies, but Bazel still expects + // the file to be created + if (optionsParser.getOutputDepsProtoFile() != null) { + try (OutputStream os = + Files.newOutputStream(Paths.get(optionsParser.getOutputDepsProtoFile()))) { + Deps.Dependencies.newBuilder() + .setRuleLabel(optionsParser.getTargetLabel()) + .setSuccess(ok) + .build() + .writeTo(os); + } + } + // TODO(cushon): support manifest protos & genjar + if (optionsParser.getManifestProtoPath() != null) { + try (OutputStream os = + Files.newOutputStream(Paths.get(optionsParser.getManifestProtoPath()))) { + Manifest.getDefaultInstance().writeTo(os); + } + } + + for (Diagnostic<? extends JavaFileObject> diagnostic : diagnosticCollector.getDiagnostics()) { + StringBuilder message = new StringBuilder(diagnostic.getSource().getName()); + if (diagnostic.getLineNumber() != -1) { + message.append(':').append(diagnostic.getLineNumber()); + } + message.append(": ").append(diagnostic.getKind().toString().toLowerCase(ENGLISH)); + message.append(": ").append(diagnostic.getMessage(ENGLISH)).append(System.lineSeparator()); + output.write(message.toString()); + } + return new VanillaJavaBuilderResult(ok, output.toString()); + } + + /** Returns the sources to compile, including any source jar entries. */ + private ImmutableList<JavaFileObject> getSources( + OptionsParser optionsParser, StandardJavaFileManager fileManager) throws IOException { + final ImmutableList.Builder<JavaFileObject> sources = ImmutableList.builder(); + sources.addAll(fileManager.getJavaFileObjectsFromStrings(optionsParser.getSourceFiles())); + for (String sourceJar : optionsParser.getSourceJars()) { + for (final Path root : getJarFileSystem(Paths.get(sourceJar)).getRootDirectories()) { + Files.walkFileTree( + root, + new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) + throws IOException { + if (path.getFileName().toString().endsWith(".java")) { + sources.add(new SourceJarFileObject(root, path)); + } + return FileVisitResult.CONTINUE; + } + }); + } + } + return sources.build(); + } + + /** Sets the compilation search paths and output directories. */ + private static void setLocations(OptionsParser optionsParser, StandardJavaFileManager fileManager) + throws IOException { + fileManager.setLocation(StandardLocation.CLASS_PATH, toFiles(optionsParser.getClassPath())); + fileManager.setLocation( + StandardLocation.PLATFORM_CLASS_PATH, + Iterables.concat( + toFiles(optionsParser.getBootClassPath()), toFiles(optionsParser.getExtdir()))); + fileManager.setLocation( + StandardLocation.ANNOTATION_PROCESSOR_PATH, toFiles(optionsParser.getProcessorPath())); + if (optionsParser.getSourceGenDir() != null) { + Path sourceGenDir = Paths.get(optionsParser.getSourceGenDir()); + Files.createDirectories(sourceGenDir); + fileManager.setLocation( + StandardLocation.SOURCE_OUTPUT, ImmutableList.of(sourceGenDir.toFile())); + } + Path classDir = Paths.get(optionsParser.getClassDir()); + Files.createDirectories(classDir); + fileManager.setLocation(StandardLocation.CLASS_OUTPUT, ImmutableList.of(classDir.toFile())); + } + + /** Sets the compilation's annotation processors. */ + private static void setProcessors( + OptionsParser optionsParser, StandardJavaFileManager fileManager, CompilationTask task) { + ClassLoader processorLoader = + fileManager.getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_PATH); + Builder<Processor> processors = ImmutableList.builder(); + for (String processor : optionsParser.getProcessorNames()) { + try { + processors.add( + (Processor) processorLoader.loadClass(processor).getConstructor().newInstance()); + } catch (ReflectiveOperationException e) { + throw new LinkageError(e.getMessage(), e); + } + } + task.setProcessors(processors.build()); + } + + /** Writes a jar containing any sources generated by annotation processors. */ + private static void writeGeneratedSourceOutput(OptionsParser optionsParser) throws IOException { + if (optionsParser.getGeneratedSourcesOutputJar() == null) { + return; + } + JarCreator jar = new JarCreator(optionsParser.getGeneratedSourcesOutputJar()); + jar.setNormalize(true); + jar.setCompression(optionsParser.compressJar()); + jar.addDirectory(optionsParser.getSourceGenDir()); + jar.execute(); + } + + /** Writes the class output jar, including any resource entries. */ + private static void writeOutput(OptionsParser optionsParser) throws IOException { + JarCreator jar = new JarCreator(optionsParser.getOutputJar()); + jar.setNormalize(true); + jar.setCompression(optionsParser.compressJar()); + jar.addDirectory(optionsParser.getClassDir()); + // TODO(cushon): kill this once resource jar creation is decoupled from JavaBuilder + try (ResourceJarBuilder resourceBuilder = + new ResourceJarBuilder( + ResourceJarOptions.builder() + .setMessages(ImmutableList.copyOf(optionsParser.getMessageFiles())) + .setResourceJars(ImmutableList.copyOf(optionsParser.getResourceJars())) + .setResources(ImmutableList.copyOf(optionsParser.getResourceFiles())) + .setClasspathResources(ImmutableList.copyOf(optionsParser.getRootResourceFiles())) + .build())) { + resourceBuilder.build(jar); + } + jar.execute(); + } + + private static ImmutableList<File> toFiles(String classPath) { + if (classPath == null) { + return ImmutableList.of(); + } + ImmutableList.Builder<File> files = ImmutableList.builder(); + for (String path : Splitter.on(File.pathSeparatorChar).split(classPath)) { + files.add(new File(path)); + } + return files.build(); + } + + @Override + public void close() throws IOException { + for (FileSystem fs : filesystems.values()) { + fs.close(); + } + } + + /** + * Wraps a {@link Path} as a {@link JavaFileObject}; used to avoid extracting source jar entries + * to disk when using file managers that don't support nio. + */ + private static class SourceJarFileObject extends SimpleJavaFileObject { + private final Path path; + + public SourceJarFileObject(Path root, Path path) { + super(URI.create("file:/" + root + "!" + root.resolve(path)), Kind.SOURCE); + this.path = path; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return new String(Files.readAllBytes(path), UTF_8); + } + } +} diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/resourcejar/BUILD b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/resourcejar/BUILD index 5ef3e21919..e40f339d9d 100644 --- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/resourcejar/BUILD +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/resourcejar/BUILD @@ -18,6 +18,7 @@ java_library( "ResourceJarOptionsParser.java", ], visibility = [ + "//src/java_tools/buildjar/java/com/google/devtools/build/buildjar:__pkg__", "//src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar/resourcejar:__pkg__", ], deps = [ @@ -25,3 +26,23 @@ java_library( "//third_party:guava", ], ) + +# +## Bootstrapping using Skylark rules +# + +load("//tools/build_rules:java_rules_skylark.bzl", "bootstrap_java_library", "bootstrap_java_binary") + +bootstrap_java_library( + name = "bootstrap_resourcejar", + srcs = [ + "ResourceJarBuilder.java", + "ResourceJarOptions.java", + "ResourceJarOptionsParser.java", + ], + visibility = ["//src/java_tools/buildjar/java/com/google/devtools/build/buildjar:__pkg__"], + deps = [ + "//src/java_tools/buildjar/java/com/google/devtools/build/buildjar:skylark-deps", + "//src/java_tools/buildjar/java/com/google/devtools/build/buildjar/jarhelper:bootstrap_jarhelper", + ], +) diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/resourcejar/ResourceJarBuilder.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/resourcejar/ResourceJarBuilder.java index 480f929b82..89ec82bfe5 100644 --- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/resourcejar/ResourceJarBuilder.java +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/resourcejar/ResourceJarBuilder.java @@ -14,6 +14,8 @@ package com.google.devtools.build.buildjar.resourcejar; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.devtools.build.buildjar.jarhelper.JarCreator; @@ -52,12 +54,18 @@ public class ResourceJarBuilder implements Closeable { private final ResourceJarOptions options; - private ResourceJarBuilder(ResourceJarOptions options) { + public ResourceJarBuilder(ResourceJarOptions options) { this.options = options; } public void build() throws IOException { + requireNonNull(options.output()); final JarCreator jar = new JarCreator(options.output()); + build(jar); + jar.execute(); + } + + public void build(JarCreator jar) throws IOException { jar.setNormalize(true); jar.setCompression(true); @@ -65,8 +73,6 @@ public class ResourceJarBuilder implements Closeable { jar.addRootEntries(options.classpathResources()); addResourceEntries(jar, options.resources()); addMessageEntries(jar, options.messages()); - - jar.execute(); } private void addResourceJars(final JarCreator jar, ImmutableList<String> resourceJars) diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/resourcejar/ResourceJarOptions.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/resourcejar/ResourceJarOptions.java index bf1afe47c4..923148c6f1 100644 --- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/resourcejar/ResourceJarOptions.java +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/resourcejar/ResourceJarOptions.java @@ -32,7 +32,7 @@ public class ResourceJarOptions { ImmutableList<String> resources, ImmutableList<String> resourceJars, ImmutableList<String> classpathResources) { - this.output = checkNotNull(output); + this.output = output; this.messages = messages; this.resources = resources; this.resourceJars = resourceJars; diff --git a/src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar/BUILD b/src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar/BUILD new file mode 100644 index 0000000000..65ca6bd977 --- /dev/null +++ b/src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar/BUILD @@ -0,0 +1,18 @@ +filegroup( + name = "srcs", + srcs = glob(["**"]) + [ + "//src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar/resourcejar:srcs", + ], + visibility = ["//src/java_tools/buildjar:__pkg__"], +) + +java_test( + name = "VanillaJavaBuilderTest", + srcs = ["VanillaJavaBuilderTest.java"], + deps = [ + "//src/java_tools/buildjar/java/com/google/devtools/build/buildjar:vanilla_java_builder", + "//third_party:guava", + "//third_party:junit4", + "//third_party:truth", + ], +) diff --git a/src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar/VanillaJavaBuilderTest.java b/src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar/VanillaJavaBuilderTest.java new file mode 100644 index 0000000000..71a702ed05 --- /dev/null +++ b/src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar/VanillaJavaBuilderTest.java @@ -0,0 +1,135 @@ +// Copyright 2017 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.buildjar; + +import static com.google.common.truth.Truth.assertThat; +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.io.ByteStreams; +import com.google.devtools.build.buildjar.VanillaJavaBuilder.VanillaJavaBuilderResult; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** {@link VanillaJavaBuilder}Test */ +@RunWith(JUnit4.class) +public class VanillaJavaBuilderTest { + @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); + + VanillaJavaBuilderResult run(List<String> args) throws Exception { + try (VanillaJavaBuilder builder = new VanillaJavaBuilder()) { + return builder.run(args); + } + } + + ImmutableMap<String, byte[]> readJar(File file) throws IOException { + ImmutableMap.Builder<String, byte[]> result = ImmutableMap.builder(); + try (JarFile jf = new JarFile(file)) { + Enumeration<JarEntry> entries = jf.entries(); + while (entries.hasMoreElements()) { + JarEntry je = entries.nextElement(); + result.put(je.getName(), ByteStreams.toByteArray(jf.getInputStream(je))); + } + } + return result.build(); + } + + @Test + public void hello() throws Exception { + Path source = temporaryFolder.newFile("Test.java").toPath(); + Path output = temporaryFolder.newFile("out.jar").toPath(); + Files.write( + source, + ImmutableList.of( + "class A {", // + "}"), + UTF_8); + Path sourceJar = temporaryFolder.newFile("src.srcjar").toPath(); + try (OutputStream os = Files.newOutputStream(sourceJar); + JarOutputStream jos = new JarOutputStream(os)) { + jos.putNextEntry(new JarEntry("B.java")); + jos.write("class B {}".getBytes(UTF_8)); + } + Path resource = temporaryFolder.newFile("resource.properties").toPath(); + Files.write(resource, "hello".getBytes(UTF_8)); + + VanillaJavaBuilderResult result = + run( + ImmutableList.of( + "--sources", + source.toString(), + "--source_jars", + sourceJar.toString(), + "--output", + output.toString(), + "--classpath_resources", + resource.toString(), + "--bootclasspath", + Paths.get(System.getProperty("java.home")).resolve("lib/rt.jar").toString(), + "--classdir", + temporaryFolder.newFolder().toString())); + + assertThat(result.output()).isEmpty(); + assertThat(result.ok()).isTrue(); + + ImmutableMap<String, byte[]> outputEntries = readJar(output.toFile()); + assertThat(outputEntries.keySet()) + .containsExactly( + "META-INF/", "META-INF/MANIFEST.MF", "A.class", "B.class", "resource.properties"); + } + + @Test + public void error() throws Exception { + Path source = temporaryFolder.newFile("Test.java").toPath(); + Path output = temporaryFolder.newFolder().toPath().resolve("out.jar"); + Files.write( + source, + ImmutableList.of( + "class A {", // + "}}"), + UTF_8); + + VanillaJavaBuilderResult result = + run( + ImmutableList.of( + "--sources", + source.toString(), + "--output", + output.toString(), + "--bootclasspath", + Paths.get(System.getProperty("java.home")).resolve("lib/rt.jar").toString(), + "--classdir", + temporaryFolder.newFolder().toString())); + + assertThat(result.output()).contains("class, interface, or enum expected"); + assertThat(result.ok()).isFalse(); + assertThat(Files.exists(output)).isFalse(); + } +} diff --git a/src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar/resourcejar/BUILD b/src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar/resourcejar/BUILD index a587c7cb73..743a4933bd 100644 --- a/src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar/resourcejar/BUILD +++ b/src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar/resourcejar/BUILD @@ -1,7 +1,7 @@ filegroup( name = "srcs", srcs = glob(["**"]), - visibility = ["//src/java_tools/buildjar:__pkg__"], + visibility = ["//src/java_tools/buildjar/javatests/com/google/devtools/build/buildjar:__pkg__"], ) java_test( |