Defines a CommandConsole interface (#32)

This interface abstract away the Eclipse API around console so that
the command class does not know anything about Eclipse.
A future change will move the CommandConsoleFactoryImpl out of the package.
diff --git a/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/Command.java b/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/Command.java
index cd4cccf..889f237 100644
--- a/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/Command.java
+++ b/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/Command.java
@@ -14,23 +14,15 @@
 
 package com.google.devtools.bazel.e4b.command;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.bazel.e4b.command.CommandConsole.CommandConsoleFactory;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.function.Function;
 
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.ui.console.ConsolePlugin;
-import org.eclipse.ui.console.IConsole;
-import org.eclipse.ui.console.IConsoleManager;
-import org.eclipse.ui.console.MessageConsole;
-import org.eclipse.ui.console.MessageConsoleStream;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-
 /**
  * A utility class to spawn a command and parse its output. It allow to filter the output,
  * redirecting part of it to the console and getting the rest in a list of string.
@@ -40,6 +32,9 @@
  */
 final class Command {
 
+  // TODO: inject
+  private final CommandConsoleFactory consoleFactory = new CommandConsoleFactoryImpl();
+
   private final File directory;
   private final ImmutableList<String> args;
   private final SelectOutputStream stdout;
@@ -52,16 +47,13 @@
     this.directory = directory;
     this.args = args;
     if (consoleName != null) {
-      MessageConsole console = findConsole(consoleName);
-      MessageConsoleStream stream = console.newMessageStream();
-      stream.setActivateOnWrite(true);
-      stream.write("*** Running " + String.join("", args.toString()) + " from "
-          + directory.toString() + " ***\n");
+      CommandConsole console = consoleFactory.get(consoleName,
+          "Running " + String.join(" ", args) + " from " + directory.toString());
       if (stdout == null) {
-        stdout = console.newMessageStream();
+        stdout = console.createOutputStream();
       }
       if (stderr == null) {
-        stderr = getErrorStream(console);
+        stderr = console.createErrorStream();
       }
     }
     this.stderr = new SelectOutputStream(stderr, stderrSelector);
@@ -91,33 +83,6 @@
     return r;
   }
 
-  // Taken from the eclipse website, find a console
-  private static MessageConsole findConsole(String name) {
-    ConsolePlugin plugin = ConsolePlugin.getDefault();
-    IConsoleManager conMan = plugin.getConsoleManager();
-    IConsole[] existing = conMan.getConsoles();
-    for (int i = 0; i < existing.length; i++) {
-      if (name.equals(existing[i].getName())) {
-        return (MessageConsole) existing[i];
-      }
-    }
-    // no console found, so create a new one
-    MessageConsole myConsole = new MessageConsole(name, null);
-    conMan.addConsoles(new IConsole[] {myConsole});
-    return myConsole;
-  }
-
-  // Get the error stream for the given console (a stream that print in red).
-  private static MessageConsoleStream getErrorStream(MessageConsole console) {
-    final MessageConsoleStream errorStream = console.newMessageStream();
-    Display display = Display.getCurrent();
-    if (display == null) {
-      display = Display.getDefault();
-    }
-    display.asyncExec(() -> errorStream.setColor(new Color(null, 255, 0, 0)));
-    return errorStream;
-  }
-
   // Launch a thread to copy all data from inputStream to outputStream
   private static void copyStream(InputStream inputStream, OutputStream outputStream) {
     if (outputStream != null) new Thread(new Runnable() {
diff --git a/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/CommandConsole.java b/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/CommandConsole.java
new file mode 100644
index 0000000..02f571d
--- /dev/null
+++ b/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/CommandConsole.java
@@ -0,0 +1,40 @@
+// 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.bazel.e4b.command;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An interface to describe an output console to stream output from a command. A command console
+ * should be able to provide output stream for both normal ouput and error output.
+ */
+public interface CommandConsole {
+
+  /** Create an {@link OuputStream} suitable to print standard output of a command. */
+  OutputStream createOutputStream();
+
+  /** Create an {@link OuputStream} suitable to print standard error output of a command. */
+  OutputStream createErrorStream();
+
+  /** A factory that returns a command console by name */
+  interface CommandConsoleFactory {
+    /**
+     * Returns a {@link CommandConsole} that has the name {@code name}. {@code title} will be
+     * written at the beginning of the console.
+     */
+    CommandConsole get(String name, String title) throws IOException;
+  }
+}
diff --git a/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/CommandConsoleFactoryImpl.java b/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/CommandConsoleFactoryImpl.java
new file mode 100644
index 0000000..2cf5485
--- /dev/null
+++ b/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/CommandConsoleFactoryImpl.java
@@ -0,0 +1,81 @@
+// 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.bazel.e4b.command;
+
+import com.google.devtools.bazel.e4b.command.CommandConsole.CommandConsoleFactory;
+import java.io.IOException;
+import java.io.OutputStream;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.console.ConsolePlugin;
+import org.eclipse.ui.console.IConsole;
+import org.eclipse.ui.console.IConsoleManager;
+import org.eclipse.ui.console.MessageConsole;
+import org.eclipse.ui.console.MessageConsoleStream;
+
+/** Implementation of {@link CommandConsoleFactory} using Eclipse's console */
+class CommandConsoleFactoryImpl implements CommandConsoleFactory {
+
+  private static class CommandConsoleImpl implements CommandConsole {
+
+    private MessageConsole console;
+
+    CommandConsoleImpl(MessageConsole console) {
+      this.console = console;
+    }
+
+    @Override
+    public OutputStream createOutputStream() {
+      return console.newMessageStream();
+    }
+
+    @Override
+    public OutputStream createErrorStream() {
+      // Get the error stream for the given console (a stream that print in red).
+      final MessageConsoleStream errorStream = console.newMessageStream();
+      Display display = Display.getCurrent();
+      if (display == null) {
+        display = Display.getDefault();
+      }
+      display.asyncExec(() -> errorStream.setColor(new Color(null, 255, 0, 0)));
+      return errorStream;
+    }
+  }
+
+  @Override
+  public CommandConsole get(String name, String title) throws IOException {
+    MessageConsole console = findConsole(name);
+    MessageConsoleStream stream = console.newMessageStream();
+    stream.setActivateOnWrite(true);
+    stream.write("*** " + title + " ***\n");
+    return new CommandConsoleImpl(console);
+  }
+
+  // Taken from the eclipse website, find a console
+  private static MessageConsole findConsole(String name) {
+    ConsolePlugin plugin = ConsolePlugin.getDefault();
+    IConsoleManager conMan = plugin.getConsoleManager();
+    IConsole[] existing = conMan.getConsoles();
+    for (int i = 0; i < existing.length; i++) {
+      if (name.equals(existing[i].getName())) {
+        return (MessageConsole) existing[i];
+      }
+    }
+    // no console found, so create a new one
+    MessageConsole myConsole = new MessageConsole(name, null);
+    conMan.addConsoles(new IConsole[] {myConsole});
+    return myConsole;
+  }
+}