aboutsummaryrefslogtreecommitdiff
path: root/pkg/cli/interface.go
diff options
context:
space:
mode:
authorStefan Majewsky <majewsky@gmx.net>2017-05-07 22:46:38 +0200
committerStefan Majewsky <majewsky@gmx.net>2017-05-07 23:02:08 +0200
commit36b903423828b2e35c9c1fde3fdc898fe2ed23ca (patch)
tree22770bbade8c8e20a3b6f4e9f5a91ed9d5580f89 /pkg/cli/interface.go
parent385645d1a0bb9ae618e92d2e7a2ea6fe256b5ba2 (diff)
downloadgofu-36b903423828b2e35c9c1fde3fdc898fe2ed23ca.tar.gz
refactor towards new cli.Interface
Diffstat (limited to 'pkg/cli/interface.go')
-rw-r--r--pkg/cli/interface.go157
1 files changed, 157 insertions, 0 deletions
diff --git a/pkg/cli/interface.go b/pkg/cli/interface.go
new file mode 100644
index 0000000..7ebde9d
--- /dev/null
+++ b/pkg/cli/interface.go
@@ -0,0 +1,157 @@
+/*******************************************************************************
+*
+* Copyright 2017 Stefan Majewsky <majewsky@gmx.net>
+*
+* This program is free software: you can redistribute it and/or modify it under
+* the terms of the GNU General Public License as published by the Free Software
+* Foundation, either version 3 of the License, or (at your option) any later
+* version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with
+* this program. If not, see <http://www.gnu.org/licenses/>.
+*
+*******************************************************************************/
+
+package cli
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "os"
+ "sort"
+ "strings"
+)
+
+//NewInterface creates an Interface instance.
+func NewInterface(stdin, stdout, stderr *os.File) (*Interface, error) {
+ //TODO: check terminal.IsTerminal(int(stdin.Fd())) and choose the TUI instance accordingly
+ return &Interface{
+ stdin: stdin,
+ stdout: stdout,
+ stderr: stderr,
+ stdinBuf: bufio.NewReader(stdin),
+ tui: &terminalTUI{},
+ }, nil
+}
+
+//Interface wraps access to the CLI, including input, output and subprocesses.
+type Interface struct {
+ //TODO: flag isStdinTerminal that disables color output and swaps out the TUI instance
+ stdin io.Reader
+ stdout io.Writer
+ stderr io.Writer
+ stdinBuf *bufio.Reader
+ tui TUI
+ //If this flag is set, only ShowResult() will write into stdout; everything
+ //else that usually goes to stdout goes to stderr instead.
+ //
+ //This is useful when gofu is expected to output a certain value to stdout
+ //which is used by the next program in the pipe, and additional output from
+ //subprocesses could confuse the stdout handler.
+ StdoutProtected bool
+}
+
+//TUI provides the interactive parts of the cli.Interface, so that these can be
+//easily swapped out for mock implementations in unit tests.
+type TUI interface {
+ //ReadLine reads a line from stdin (if tty: uses canonical mode).
+ ReadLine(prompt string) (string, error)
+ //Confirm displays a yes/no question and returns whether the user answered "yes".
+ Confirm(question string) (bool, error)
+ //Query displays a question and a set of answers and allows the user to select
+ //one of the answers. Returns the Return attribute of the selected Choice.
+ Query(prompt string, choices ...Choice) (string, error)
+}
+
+func (i *Interface) safeStdout() io.Writer {
+ if i.StdoutProtected {
+ return i.stderr
+ }
+ return i.stdout
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// input
+
+//ReadLine reads a line from stdin (if tty: uses canonical mode).
+func (i *Interface) ReadLine(prompt string) (string, error) {
+ return i.tui.ReadLine(prompt)
+}
+
+//Confirm displays a yes/no question and returns whether the user answered "yes".
+func (i *Interface) Confirm(question string) (bool, error) {
+ return i.tui.Confirm(question)
+}
+
+//Query displays a question and a set of answers and allows the user to select
+//one of the answers. Returns the Return attribute of the selected Choice.
+func (i *Interface) Query(prompt string, choices ...Choice) (string, error) {
+ return i.tui.Query(prompt, choices...)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// subprocesses
+
+//Run executes the given command on the same stdout and stderr.
+func (i *Interface) Run(c Command) error {
+ return c.run(i.safeStdout(), i.stderr)
+}
+
+//CaptureStdout executes the given command on the same stderr and captures its stdout.
+func (i *Interface) CaptureStdout(c Command) (string, error) {
+ var buf bytes.Buffer
+ err := c.run(&buf, i.stderr)
+ return string(buf.Bytes()), err
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// output
+
+//ShowResult displays the result of a computation on stdout.
+func (i *Interface) ShowResult(str string) {
+ str = strings.TrimSpace(str) + "\n"
+ i.stdout.Write([]byte(str))
+}
+
+//ShowResultsSorted calls ShowResult() on each of the results after sorting them.
+func (i *Interface) ShowResultsSorted(strs []string) {
+ sort.Strings(strs)
+ for _, str := range strs {
+ i.ShowResult(str)
+ }
+}
+
+//ShowProgress displays a progress message on stderr.
+func (i *Interface) ShowProgress(str string) {
+ i.stderr.Write(StyledText{
+ Styled(">> ", AnsiNormal, AnsiBold, AnsiCyan),
+ Styled(strings.TrimSpace(str)+"\n", AnsiCyan),
+ }.DisplayString(true))
+}
+
+//ShowWarning displays a warning message on stderr.
+func (i *Interface) ShowWarning(str string) {
+ i.stderr.Write(StyledText{
+ Styled("!! ", AnsiNormal, AnsiBold, AnsiYellow),
+ Styled(strings.TrimSpace(str)+"\n", AnsiYellow),
+ }.DisplayString(true))
+}
+
+//ShowError displays an error message on stderr.
+func (i *Interface) ShowError(err string) {
+ i.stderr.Write(StyledText{
+ Styled("!! ", AnsiNormal, AnsiBold, AnsiRed),
+ Styled(strings.TrimSpace(err)+"\n", AnsiRed),
+ }.DisplayString(true))
+}
+
+//ShowUsage displays a usage synopsis on stderr.
+func (i *Interface) ShowUsage(str string) {
+ str = strings.TrimSpace(str) + "\n"
+ i.stderr.Write([]byte(str))
+}