| // 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.bazel.e4b.command; | |
| import java.io.ByteArrayOutputStream; | |
| import java.io.IOException; | |
| import java.io.OutputStream; | |
| import java.io.UnsupportedEncodingException; | |
| import java.nio.charset.StandardCharsets; | |
| import java.util.LinkedList; | |
| import java.util.List; | |
| import java.util.function.Function; | |
| import com.google.common.base.Preconditions; | |
| import com.google.common.collect.ImmutableList; | |
| /** | |
| * A wrapper output stream to output part of the result to a given output and extracting the other | |
| * part with a selector function. The other part is return as a list of string. | |
| */ | |
| public class SelectOutputStream extends OutputStream { | |
| private OutputStream output; | |
| private Function<String, String> selector; | |
| private boolean closed = false; | |
| private List<String> lines = new LinkedList<>(); | |
| private ByteArrayOutputStream stream = new ByteArrayOutputStream(); | |
| /** | |
| * Create a SelectOutputStream. <code>output<code> is the output stream where non-selected lines | |
| * will be printed. <code>selector<code> is a function that will be called on each line. If | |
| * <code>selector</code> returns a non null value, then the resulting value will be stored in a | |
| * lines buffer that can be consumed with the {@link #getLines()} method. If <code>selector</code> | |
| * returns a null value, the corresponding line will be send to <code>output</code>. | |
| * | |
| * <p> | |
| * Both <code>output</code> and <code>selector</code> can be null. If <code>output</code> is null, | |
| * unselected lines will be discarded. If <code>selector</code> is null, all lines will be | |
| * considered as unselected. | |
| */ | |
| public SelectOutputStream(OutputStream output, Function<String, String> selector) { | |
| super(); | |
| this.output = output; | |
| this.selector = selector; | |
| } | |
| @Override | |
| public void write(int b) throws IOException { | |
| Preconditions.checkState(!closed, "Attempted to write on a closed stream"); | |
| byte b0 = (byte) b; | |
| if (b0 == '\n') { | |
| select(true); | |
| } else { | |
| stream.write(b); | |
| } | |
| } | |
| private void select(boolean appendNewLine) throws UnsupportedEncodingException, IOException { | |
| String line = null; | |
| if (selector != null) { | |
| line = selector.apply(stream.toString(StandardCharsets.UTF_8.name())); | |
| } | |
| if (line != null) { | |
| lines.add(line); | |
| } else if (output != null) { | |
| if (appendNewLine) { | |
| stream.write('\n'); | |
| } | |
| output.write(stream.toByteArray()); | |
| } | |
| stream.reset(); | |
| } | |
| @Override | |
| public void close() throws IOException { | |
| Preconditions.checkState(!closed); | |
| super.close(); | |
| select(false); | |
| closed = true; | |
| } | |
| /** | |
| * Returns the list of selected lines. | |
| */ | |
| ImmutableList<String> getLines() { | |
| return ImmutableList.copyOf(lines); | |
| } | |
| } |