|  | // Copyright 2014 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.lib.shell; | 
|  |  | 
|  | import java.io.IOException; | 
|  | import java.io.InputStream; | 
|  | import java.io.OutputStream; | 
|  |  | 
|  | /** | 
|  | * Provides sinks for input streams.  Continuously read an input stream | 
|  | * until the end-of-file is encountered.  The stream may be redirected to | 
|  | * an {@link OutputStream}, or discarded. | 
|  | * <p> | 
|  | * This class is useful for handing the {@code stdout} and {@code stderr} | 
|  | * streams from a {@link Process} started with {@link Runtime#exec(String)}. | 
|  | * If these streams are not consumed, the Process may block resulting in a | 
|  | * deadlock. | 
|  | * | 
|  | * @see <a href="http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html"> | 
|  | *      JavaWorld: When Runtime.exec() won't</a> | 
|  | */ | 
|  | public final class InputStreamSink { | 
|  |  | 
|  | /** | 
|  | * Black hole into which bytes are sometimes discarded by {@link NullSink}. | 
|  | * It is shared by all threads since the actual contents of the buffer | 
|  | * are irrelevant. | 
|  | */ | 
|  | private static final byte[] DISCARD = new byte[4096]; | 
|  |  | 
|  | // Suppresses default constructor; ensures non-instantiability | 
|  | private InputStreamSink() {} | 
|  |  | 
|  | /** | 
|  | * A {@link Thread} which reads and discards data from an | 
|  | * {@link InputStream}. | 
|  | */ | 
|  | private static class NullSink implements Runnable { | 
|  | private final InputStream in; | 
|  |  | 
|  | public NullSink(InputStream in) { | 
|  | this.in = in; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void run() { | 
|  | try { | 
|  | try { | 
|  | // Attempt to just skip all input | 
|  | do { | 
|  | in.skip(Integer.MAX_VALUE); | 
|  | } while (in.read() != -1); // Need to test for EOF | 
|  | } catch (IOException ioe) { | 
|  | // Some streams throw IOException when skip() is called; | 
|  | // resort to reading off all input with read(): | 
|  | while (in.read(DISCARD) != -1) { | 
|  | // no loop body | 
|  | } | 
|  | } | 
|  | } catch (IOException e) { | 
|  | throw new RuntimeException(e); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * A {@link Thread} which reads data from an {@link InputStream}, | 
|  | * and translates it into an {@link OutputStream}. | 
|  | */ | 
|  | private static class CopySink implements Runnable { | 
|  |  | 
|  | private final InputStream in; | 
|  | private final OutputStream out; | 
|  |  | 
|  | public CopySink(InputStream in, OutputStream out) { | 
|  | this.in = in; | 
|  | this.out = out; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void run() { | 
|  | try { | 
|  | byte[] buffer = new byte[2048]; | 
|  | int bytesRead; | 
|  | while ((bytesRead = in.read(buffer)) >= 0) { | 
|  | out.write(buffer, 0, bytesRead); | 
|  | out.flush(); | 
|  | } | 
|  | } catch (IOException e) { | 
|  | throw new RuntimeException(e); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Creates a {@link Runnable} which consumes the provided | 
|  | * {@link InputStream} 'in', discarding its contents. | 
|  | */ | 
|  | public static Runnable newRunnableSink(InputStream in) { | 
|  | if (in == null) { | 
|  | throw new NullPointerException("in"); | 
|  | } | 
|  | return new NullSink(in); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Creates a {@link Runnable} which copies everything from 'in' | 
|  | * to 'out'. 'out' will be written to and flushed after each | 
|  | * read from 'in'. However, 'out' will not be closed. | 
|  | */ | 
|  | public static Runnable newRunnableSink(InputStream in, OutputStream out) { | 
|  | if (in == null) { | 
|  | throw new NullPointerException("in"); | 
|  | } | 
|  | if (out == null) { | 
|  | throw new NullPointerException("out"); | 
|  | } | 
|  | return new CopySink(in, out); | 
|  | } | 
|  | } |