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