@@ -19,9 +19,13 @@ package cmd
19
19
import (
20
20
"context"
21
21
"io"
22
+ "strings"
22
23
24
+ "github.com/GoogleContainerTools/skaffold/pkg/skaffold/color"
25
+ "github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
23
26
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner"
24
27
"github.com/pkg/errors"
28
+ "github.com/rivo/tview"
25
29
"github.com/sirupsen/logrus"
26
30
"github.com/spf13/cobra"
27
31
)
@@ -34,7 +38,7 @@ func NewCmdDev(out io.Writer) *cobra.Command {
34
38
Args : cobra .NoArgs ,
35
39
RunE : func (cmd * cobra.Command , args []string ) error {
36
40
opts .Command = "dev"
37
- return dev (out )
41
+ return dev (out , opts . ExperimentalGUI )
38
42
},
39
43
}
40
44
AddRunDevFlags (cmd )
@@ -45,13 +49,17 @@ func NewCmdDev(out io.Writer) *cobra.Command {
45
49
cmd .Flags ().IntVarP (& opts .WatchPollInterval , "watch-poll-interval" , "i" , 1000 , "Interval (in ms) between two checks for file changes" )
46
50
cmd .Flags ().BoolVar (& opts .PortForward , "port-forward" , true , "Port-forward exposed container ports within pods" )
47
51
cmd .Flags ().StringArrayVarP (& opts .CustomLabels , "label" , "l" , nil , "Add custom labels to deployed objects. Set multiple times for multiple labels" )
52
+ cmd .Flags ().BoolVar (& opts .ExperimentalGUI , "experimental-gui" , false , "Experimental Graphical User Interface" )
53
+
48
54
return cmd
49
55
}
50
56
51
- func dev (out io.Writer ) error {
57
+ func dev (out io.Writer , ui bool ) error {
52
58
ctx , cancel := context .WithCancel (context .Background ())
53
59
defer cancel ()
54
- catchCtrlC (cancel )
60
+ if ! ui {
61
+ catchCtrlC (cancel )
62
+ }
55
63
56
64
cleanup := func () {}
57
65
if opts .Cleanup {
@@ -60,6 +68,25 @@ func dev(out io.Writer) error {
60
68
}()
61
69
}
62
70
71
+ var (
72
+ app * tview.Application
73
+ output * config.Output
74
+ )
75
+ if ui {
76
+ app , output = createApp ()
77
+ defer app .Stop ()
78
+
79
+ go func () {
80
+ app .Run ()
81
+ cancel ()
82
+ }()
83
+ } else {
84
+ output = & config.Output {
85
+ Main : out ,
86
+ Logs : out ,
87
+ }
88
+ }
89
+
63
90
for {
64
91
select {
65
92
case <- ctx .Done ():
@@ -70,7 +97,7 @@ func dev(out io.Writer) error {
70
97
return errors .Wrap (err , "creating runner" )
71
98
}
72
99
73
- err = r .Dev (ctx , out , config .Build .Artifacts )
100
+ err = r .Dev (ctx , output , config .Build .Artifacts )
74
101
if r .HasDeployed () {
75
102
cleanup = func () {
76
103
if err := r .Cleanup (context .Background (), out ); err != nil {
@@ -86,3 +113,78 @@ func dev(out io.Writer) error {
86
113
}
87
114
}
88
115
}
116
+
117
+ func createApp () (* tview.Application , * config.Output ) {
118
+ app := tview .NewApplication ()
119
+
120
+ mainView := tview .NewTextView ()
121
+ mainView .
122
+ SetChangedFunc (func () {
123
+ app .Draw ()
124
+ }).
125
+ SetDynamicColors (true ).
126
+ SetBorder (true ).
127
+ SetTitle ("Build" )
128
+
129
+ logsView := tview .NewTextView ()
130
+ logsView .
131
+ SetChangedFunc (func () {
132
+ app .Draw ()
133
+ }).
134
+ SetDynamicColors (true ).
135
+ SetBorder (true ).
136
+ SetTitle ("Logs" )
137
+
138
+ grid := tview .NewGrid ()
139
+ grid .
140
+ SetRows (0 , 0 ).
141
+ SetColumns (0 ).
142
+ SetBorders (false ).
143
+ AddItem (mainView , 0 , 0 , 1 , 1 , 0 , 0 , false ).
144
+ AddItem (logsView , 1 , 0 , 1 , 1 , 0 , 0 , false )
145
+
146
+ app .
147
+ SetRoot (grid , true ).
148
+ SetFocus (grid )
149
+
150
+ output := & config.Output {
151
+ Main : color.ColoredWriter {Writer : ansiWriter (mainView )},
152
+ Logs : color.ColoredWriter {Writer : ansiWriter (logsView )},
153
+ }
154
+
155
+ return app , output
156
+ }
157
+
158
+ func ansiWriter (writer io.Writer ) io.Writer {
159
+ return & ansi {
160
+ Writer : writer ,
161
+ replacer : strings .NewReplacer (
162
+ "\033 [31m" , "[maroon]" ,
163
+ "\033 [32m" , "[green]" ,
164
+ "\033 [33m" , "[olive]" ,
165
+ "\033 [34m" , "[navy]" ,
166
+ "\033 [35m" , "[purple]" ,
167
+ "\033 [36m" , "[teal]" ,
168
+ "\033 [37m" , "[silver]" ,
169
+
170
+ "\033 [91m" , "[red]" ,
171
+ "\033 [92m" , "[lime]" ,
172
+ "\033 [93m" , "[yellow]" ,
173
+ "\033 [94m" , "[blue]" ,
174
+ "\033 [95m" , "[fuchsia]" ,
175
+ "\033 [96m" , "[aqua]" ,
176
+ "\033 [97m" , "[white]" ,
177
+
178
+ "\033 [0m" , "" ,
179
+ ),
180
+ }
181
+ }
182
+
183
+ type ansi struct {
184
+ io.Writer
185
+ replacer * strings.Replacer
186
+ }
187
+
188
+ func (a * ansi ) Write (text []byte ) (int , error ) {
189
+ return a .replacer .WriteString (a .Writer , string (text ))
190
+ }
0 commit comments