-
Notifications
You must be signed in to change notification settings - Fork 0
/
cmd.go
83 lines (75 loc) · 1.57 KB
/
cmd.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package cmd
import (
"bufio"
"context"
"fmt"
"io"
"io/fs"
"os"
"strings"
"sync"
"time"
)
// Fetcher is an interface for cmd.Plugin
type Fetcher interface {
Fetch(ctx context.Context) ([]string, error)
}
// Starter is an interface for terminal.UI
type Starter interface {
Start(ctx context.Context, wg *sync.WaitGroup)
}
type Stdout interface {
io.Writer
Stat() (fs.FileInfo, error)
}
type Cmd struct {
plugin Fetcher
stderr io.Writer
stdout Stdout
ui Starter
UIStopTimeout time.Duration
}
func NewCmd(plugin Fetcher, stdout Stdout, stderr io.Writer, ui Starter) (*Cmd, error) {
return &Cmd{
plugin: plugin,
stderr: stderr,
stdout: stdout,
ui: ui,
UIStopTimeout: 500 * time.Millisecond,
}, nil
}
func (c *Cmd) Run(ctx context.Context) error {
wg := &sync.WaitGroup{}
fileInfo, err := c.stdout.Stat()
if err != nil {
return err
}
uiCtx, cancel := context.WithCancel(ctx)
defer cancel()
// Only start UI if we are connected to a TTY
if fileInfo.Mode()&os.ModeCharDevice != 0 {
wg.Add(1)
go c.ui.Start(uiCtx, wg)
}
resources, err := c.plugin.Fetch(ctx)
cancel()
c.waitForUI(wg)
if err != nil {
return err
}
if len(resources) == 0 {
fmt.Fprintln(c.stderr, "No resources found.")
return nil
}
bufferedStdout := bufio.NewWriter(c.stdout)
bufferedStdout.WriteString(strings.Join(resources, "\n") + "\n")
return bufferedStdout.Flush()
}
func (c *Cmd) waitForUI(wg *sync.WaitGroup) {
stopped := make(chan struct{})
go func() {
defer close(stopped)
wg.Wait()
}()
<-stopped
}