diff options
Diffstat (limited to 'src')
3 files changed, 146 insertions, 5 deletions
diff --git a/src/java_tools/singlejar/BUILD b/src/java_tools/singlejar/BUILD index e9a9a6d4b2..24c9ff50c1 100644 --- a/src/java_tools/singlejar/BUILD +++ b/src/java_tools/singlejar/BUILD @@ -19,6 +19,7 @@ java_library( deps = [ "//src/java_tools/singlejar/java/com/google/devtools/build/zip", "//src/main/java/com/google/devtools/build/lib:shell", + "//src/main/protobuf:worker_protocol_java_proto", "//third_party:jsr305", ], ) @@ -75,7 +76,12 @@ bootstrap_java_library( bootstrap_java_binary( name = "bootstrap", - srcs = glob(["java/**/*.java"]) + ["//src/java_tools/singlejar/java/com/google/devtools/build/zip:java-srcs"], + srcs = glob( + ["java/**/*.java"], + exclude = ["java/**/SingleJarWorker.java"], + ) + [ + "//src/java_tools/singlejar/java/com/google/devtools/build/zip:java-srcs", + ], main_class = "com.google.devtools.build.singlejar.SingleJar", visibility = ["//visibility:public"], deps = [ diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SingleJar.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SingleJar.java index 6dd20a4803..d99d84b7f6 100644 --- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SingleJar.java +++ b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SingleJar.java @@ -16,7 +16,6 @@ package com.google.devtools.build.singlejar; import com.google.devtools.build.singlejar.DefaultJarEntryFilter.PathFilter; import com.google.devtools.build.singlejar.ZipCombiner.OutputMode; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -31,7 +30,6 @@ import java.util.Properties; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; - import javax.annotation.concurrent.NotThreadSafe; /** @@ -377,13 +375,53 @@ public class SingleJar { allowedPaths = new PrefixListPathFilter(prefixes); } + static int singleRun(String[] args) throws IOException { + SingleJar singlejar = new SingleJar(new JavaIoFileSystem()); + return singlejar.run(Arrays.asList(args)); + } + public static void main(String[] args) { + if (shouldRunInWorker(args)) { + if (!canRunInWorker()) { + System.err.println("Asked to run in a worker, but no worker support"); + System.exit(1); + } + try { + runWorker(args); + } catch (Exception e) { + System.err.println("Error running worker : " + e.getMessage()); + System.exit(1); + } + return; + } + try { - SingleJar singlejar = new SingleJar(new JavaIoFileSystem()); - System.exit(singlejar.run(Arrays.asList(args))); + System.exit(singleRun(args)); } catch (IOException e) { System.err.println("SingleJar threw exception : " + e.getMessage()); System.exit(1); } } + + private static void runWorker(String[] args) throws Exception { + // Invocation is done through reflection so that this code will work in bazel open source + // as well. SingleJar is used for bootstrap and thus can not depend on protos (used in + // SingleJarWorker). + Class<?> workerClass = Class.forName("com.google.devtools.build.singlejar.SingleJarWorker"); + workerClass.getMethod("main", String[].class).invoke(null, (Object) args); + } + + private static boolean shouldRunInWorker(String[] args) { + return Arrays.asList(args).contains("--persistent_worker"); + } + + private static boolean canRunInWorker() { + try { + Class.forName("com.google.devtools.build.singlejar.SingleJarWorker"); + return true; + } catch (ClassNotFoundException e1) { + return false; + } + } + } diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SingleJarWorker.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SingleJarWorker.java new file mode 100644 index 0000000000..499192fada --- /dev/null +++ b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SingleJarWorker.java @@ -0,0 +1,97 @@ +// 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.singlejar; + +import com.google.devtools.build.lib.worker.WorkerProtocol.WorkRequest; +import com.google.devtools.build.lib.worker.WorkerProtocol.WorkResponse; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; + +/** + * A blaze worker to run {@link SingleJar} in a warm JVM process. + */ +public class SingleJarWorker { + + public static void main(String[] args) { + new SingleJarWorker().runWorker(); + } + + private PrintStream originalStdout; + private PrintStream originalSterr; + private ByteArrayOutputStream stdoutAndStderr; + + private void runWorker() { + trapOutputs(); + + try { + dispatchWorkRequestsForever(); + } catch (IOException e) { + // IOException will only occur if System.in has been closed + // In that case we silently exit our process + } + } + + private void trapOutputs() { + originalStdout = System.out; + originalSterr = System.err; + stdoutAndStderr = new ByteArrayOutputStream(); + System.setErr(new PrintStream(stdoutAndStderr, true)); + System.setOut(new PrintStream(stdoutAndStderr, true)); + } + + private void dispatchWorkRequestsForever() throws IOException { + while (true) { + WorkRequest workRequest = WorkRequest.parseDelimitedFrom(System.in); + + String[] args = workRequest.getArgumentsList().toArray(new String[0]); + + int returnCode = runSingleJar(args); + + outputResult(returnCode); + } + } + + private void outputResult(int returnCode) throws IOException { + WorkResponse.newBuilder() + .setExitCode(returnCode) + .setOutput(new String(stdoutAndStderr.toByteArray(), StandardCharsets.UTF_8)) + .build() + .writeDelimitedTo(originalStdout); + + // Reset output streams, we are not simply calling reset on the BAOS since this will + // still keep the full buffer allocated. + stdoutAndStderr = new ByteArrayOutputStream(); + System.setErr(new PrintStream(stdoutAndStderr, true)); + System.setOut(new PrintStream(stdoutAndStderr, true)); + } + + private int runSingleJar(String[] args) { + try { + return SingleJar.singleRun(args); + } catch (IOException e) { + // Some IO failures are okay no need to quit the worker + System.err.println("SingleJar threw exception : " + e.getMessage()); + return 1; + } catch (Exception e) { + // We had an actual unexpected error, lets quit the worker + originalSterr.println("SingleJar threw an unexpected exception : " + e.getMessage()); + e.printStackTrace(originalSterr); + System.exit(1); + return 1; + } + } +} |