devtools: Add gosh.Pipeline, simplify AddStd{out,err}Writer.

This CL introduces a new Pipeline concept to gosh.  The idea is
similar to bash command pipelines; you can connect a sequence of
commands together, with stdout and/or stderr of one command
connected to the stdin of the next command.  The Pipeline API is
similar to the Cmd API, with unnecessary methods removed, and
with Pipe{Stdout,Stderr,CombinedOutput} methods to construct the
pipeline.

Also simplified Cmd.AddStd{out,err}Writer semantics, by changing
the argument from io.WriteCloser to io.Writer.  We no longer
automatically close these writers on exit.  This means we can now
write AddStdoutWriter(os.Stdout) without needing
gosh.NopWriteCloser, which has been removed.

If you need to close your writer, you are responsible for calling
close at the appropriate point in the code yourself.

MultiPart: 2/4

Change-Id: I355ced34f26acb62d4991d160c61da1b3de63714
diff --git a/exec.go b/exec.go
index 2aafef3..76ce51c 100644
--- a/exec.go
+++ b/exec.go
@@ -10,6 +10,7 @@
 
 	"v.io/x/lib/cmdline"
 	"v.io/x/lib/gosh"
+	"v.io/x/lib/textutil"
 )
 
 var cmdMadbExec = &cmdline.Command{
@@ -71,9 +72,13 @@
 	cmdArgs := append([]string{"-s", device}, args...)
 	cmd := sh.Cmd("adb", cmdArgs...)
 
-	cmd.AddStdoutWriter(newPrefixer(os.Stdout, device))
-	cmd.AddStderrWriter(newPrefixer(os.Stderr, device))
+	stdout := textutil.PrefixLineWriter(os.Stdout, "["+device+"]\t")
+	stderr := textutil.PrefixLineWriter(os.Stderr, "["+device+"]\t")
+	cmd.AddStdoutWriter(stdout)
+	cmd.AddStderrWriter(stderr)
 	cmd.Run()
+	stdout.Flush()
+	stderr.Flush()
 
 	return sh.Err
 }
diff --git a/prefixer.go b/prefixer.go
deleted file mode 100644
index ed2c573..0000000
--- a/prefixer.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
-	"fmt"
-	"io"
-
-	"v.io/x/lib/textutil"
-)
-
-// prefixer is a io.WriteCloser that adds given prefix to each line of the output.
-type prefixer struct {
-	textutil.WriteFlusher
-}
-
-// newPrefixer returns a new prefixer that uses the given prefix.
-func newPrefixer(writer io.Writer, prefix string) *prefixer {
-	return &prefixer{
-		WriteFlusher: textutil.PrefixLineWriter(writer, fmt.Sprintf("[%v]\t", prefix)),
-	}
-}
-
-// Close flushes the remaining buffer content with prefix, and closes the underlying writer if applicable.
-// This internally calls Flush() on the underlying textutil.WriteFlusher.
-func (p *prefixer) Close() error {
-	return p.WriteFlusher.Flush()
-}
diff --git a/prefixer_test.go b/prefixer_test.go
deleted file mode 100644
index 63e1332..0000000
--- a/prefixer_test.go
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
-	"bytes"
-	"fmt"
-	"testing"
-)
-
-func TestPrefixerSingleDevice(t *testing.T) {
-	buffer := bytes.Buffer{}
-	prefixer := newPrefixer(&buffer, "deviceid01")
-
-	fmt.Fprintln(prefixer, "First line.")
-	fmt.Fprintln(prefixer, "Second line.")
-	prefixer.Close()
-
-	want := `[deviceid01]	First line.
-[deviceid01]	Second line.
-`
-
-	if got := buffer.String(); got != want {
-		t.Fatalf("unmatched results: got %v, want %v", got, want)
-	}
-}
-
-func TestPrefixerTwoDevices(t *testing.T) {
-	// Two devices case
-	buffer := bytes.Buffer{}
-	prefixer1 := newPrefixer(&buffer, "deviceid01")
-	prefixer2 := newPrefixer(&buffer, "deviceid02")
-
-	fmt.Fprintf(prefixer2, "Second")
-	fmt.Fprintln(prefixer1, "First line.")
-	fmt.Fprintln(prefixer2, " line.")
-	fmt.Fprintln(prefixer1, "Third line.")
-	fmt.Fprintln(prefixer2, "Fourth line.")
-	prefixer1.Close()
-	prefixer2.Close()
-
-	want := `[deviceid01]	First line.
-[deviceid02]	Second line.
-[deviceid01]	Third line.
-[deviceid02]	Fourth line.
-`
-
-	if got := buffer.String(); got != want {
-		t.Fatalf("unmatched results: got %v, want %v", got, want)
-	}
-}
-
-func TestPrefixerLastLine(t *testing.T) {
-	// For the last line, a newline character should be added automatically.
-	buffer := bytes.Buffer{}
-	prefixer := newPrefixer(&buffer, "deviceid01")
-
-	fmt.Fprintf(prefixer, "First line.")
-	prefixer.Close()
-
-	want := `[deviceid01]	First line.
-`
-
-	if got := buffer.String(); got != want {
-		t.Fatalf("unmatched results: got %v, want %v", got, want)
-	}
-}