| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * 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.android.tools.idea.gradle.invoker; |
| |
| import com.android.tools.idea.gradle.invoker.console.view.GradleConsoleView; |
| import com.android.utils.SdkUtils; |
| import com.google.common.io.Closeables; |
| import com.intellij.execution.ui.ConsoleViewContentType; |
| import org.gradle.tooling.BuildLauncher; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| |
| import static com.intellij.execution.ui.ConsoleViewContentType.ERROR_OUTPUT; |
| import static com.intellij.execution.ui.ConsoleViewContentType.NORMAL_OUTPUT; |
| |
| /** |
| * Collects and redirects the output to the "Gradle Console" view. |
| */ |
| class GradleOutputForwarder { |
| private static final int SIZE = 2048; |
| |
| @NotNull private final ByteArrayOutputStream myStdErr; |
| @NotNull private final ByteArrayOutputStream myOutput; |
| @NotNull private final GradleConsoleView myConsoleView; |
| |
| private ConsoleViewContentType myPreviousContentType; |
| |
| GradleOutputForwarder(@NotNull GradleConsoleView consoleView) { |
| myConsoleView = consoleView; |
| myStdErr = new ByteArrayOutputStream(SIZE); |
| myOutput = new ByteArrayOutputStream(SIZE * 2); |
| } |
| |
| void attachTo(@NotNull BuildLauncher launcher, @Nullable Listener listener) { |
| OutputStream stdout = new ConsoleAwareOutputStream(this, NORMAL_OUTPUT, listener); |
| OutputStream stderr = new ConsoleAwareOutputStream(this, ERROR_OUTPUT, listener); |
| |
| launcher.setStandardOutput(stdout); |
| launcher.setStandardError(stderr); |
| } |
| |
| void close() { |
| try { |
| Closeables.close(myOutput, true /* swallowIOException */); |
| Closeables.close(myStdErr, true /* swallowIOException */); |
| } catch (IOException e) { |
| // Cannot happen |
| } |
| } |
| |
| @NotNull |
| String getStdErr() { |
| return myStdErr.toString(); |
| } |
| |
| void write(@NotNull ConsoleViewContentType contentType, @NotNull byte[] b, int off, int len) { |
| boolean addNewLine = false; |
| // We are combining input from stdout and stderr and that we want to make sure that whenever the output is mixed it starts on a new |
| // line. |
| if (contentType != myPreviousContentType) { |
| addNewLine = myPreviousContentType != null; |
| myPreviousContentType = contentType; |
| } |
| String lineSeparator = SdkUtils.getLineSeparator(); |
| boolean newLineAdded = false; |
| if (addNewLine) { |
| byte[] bytes = lineSeparator.getBytes(); |
| myOutput.write(bytes, 0, bytes.length); |
| myConsoleView.print(lineSeparator, contentType); |
| newLineAdded = true; |
| } |
| String text = new String(b, off, len); |
| if (lineSeparator.equals(text) && newLineAdded) { |
| return; |
| } |
| myOutput.write(b, off, len); |
| if (contentType == ERROR_OUTPUT) { |
| myStdErr.write(b, off, len); |
| } |
| myConsoleView.print(text, contentType); |
| } |
| |
| @Override |
| public String toString() { |
| return myOutput.toString(); |
| } |
| |
| interface Listener { |
| void onOutput(@NotNull ConsoleViewContentType contentType, @NotNull byte[] data, int offset, int length); |
| } |
| |
| private static class ConsoleAwareOutputStream extends OutputStream { |
| @NotNull private final GradleOutputForwarder myOutput; |
| @NotNull private final ConsoleViewContentType myContentType; |
| @Nullable private final Listener myListener; |
| |
| ConsoleAwareOutputStream(@NotNull GradleOutputForwarder output, |
| @NotNull ConsoleViewContentType contentType, |
| @Nullable Listener listener) |
| { |
| myOutput = output; |
| myContentType = contentType; |
| myListener = listener; |
| } |
| |
| @Override |
| public void write(int b) { |
| } |
| |
| @Override |
| public void write(@NotNull byte[] b, int off, int len) { |
| if (myListener != null) { |
| myListener.onOutput(myContentType, b, off, len); |
| } |
| myOutput.write(myContentType, b, off, len); |
| } |
| } |
| } |