diff options
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( |