@@ -9,21 +9,22 @@ import (
99 "os"
1010 "path/filepath"
1111 "strings"
12- "text/tabwriter"
1312 "time"
1413
1514 "github.com/junixlabs/devbox/internal/config"
1615 "github.com/junixlabs/devbox/internal/doctor"
1716 devboxerr "github.com/junixlabs/devbox/internal/errors"
1817 devboxssh "github.com/junixlabs/devbox/internal/ssh"
1918 "github.com/junixlabs/devbox/internal/tailscale"
19+ "github.com/junixlabs/devbox/internal/ui"
2020 "github.com/junixlabs/devbox/internal/workspace"
2121 "github.com/spf13/cobra"
2222)
2323
2424var (
2525 version = "0.1.0-dev"
2626 verbose bool
27+ noColor bool
2728)
2829
2930func main () {
@@ -41,9 +42,11 @@ func main() {
4142 level = slog .LevelDebug
4243 }
4344 slog .SetDefault (slog .New (slog .NewTextHandler (os .Stderr , & slog.HandlerOptions {Level : level })))
45+ ui .SetNoColor (noColor )
4446 },
4547 }
4648 rootCmd .PersistentFlags ().BoolVarP (& verbose , "verbose" , "v" , false , "Enable debug logging" )
49+ rootCmd .PersistentFlags ().BoolVar (& noColor , "no-color" , false , "Disable colored output" )
4750
4851 rootCmd .AddCommand (initCmd ())
4952 rootCmd .AddCommand (upCmd (wm ))
@@ -104,14 +107,17 @@ func upCmd(wm workspace.Manager) *cobra.Command {
104107 cfg .Branch = b
105108 }
106109
110+ spin := ui .StartSpinner ("Starting workspace..." )
107111 ws , err := wm .Create (cfg .Name , project , cfg .Branch )
108112 if err != nil {
113+ ui .StopSpinner (spin , false )
109114 return fmt .Errorf ("devbox up: %w" , err )
110115 }
111116
112117 // Expose ports via Tailscale on the remote server
113118 sshExec , err := devboxssh .New ()
114119 if err != nil {
120+ ui .StopSpinner (spin , false )
115121 return fmt .Errorf ("devbox up: %w" , err )
116122 }
117123 defer sshExec .Close ()
@@ -122,18 +128,14 @@ func upCmd(wm workspace.Manager) *cobra.Command {
122128 fmt .Fprintf (os .Stderr , "Warning: failed to expose port %s (%d): %v\n " , name , port , err )
123129 }
124130 }
131+ ui .StopSpinner (spin , true )
125132
126133 tsStatus , _ := tm .Status ()
127-
128- fmt .Printf ("\n Workspace %q created on %s\n \n " , ws .Name , cfg .Server )
129- fmt .Printf (" SSH: ssh %s\n " , cfg .Server )
134+ url := ""
130135 if tsStatus != nil {
131- fmt .Printf (" URL: %s\n " , tailscale .WorkspaceURL (tsStatus .Hostname , tsStatus .TailnetName ))
132- }
133- for name , port := range cfg .Ports {
134- fmt .Printf (" Port: %s -> %d\n " , name , port )
136+ url = tailscale .WorkspaceURL (tsStatus .Hostname , tsStatus .TailnetName )
135137 }
136- fmt . Println ( )
138+ ui . PrintUpSuccess ( ws . Name , cfg . Server , url , cfg . Ports )
137139
138140 return nil
139141 },
@@ -157,12 +159,16 @@ func stopCmd(wm workspace.Manager) *cobra.Command {
157159 return fmt .Errorf ("devbox stop: %w" , err )
158160 }
159161
162+ spin := ui .StartSpinner ("Stopping workspace..." )
163+
160164 if err := wm .Stop (name ); err != nil {
165+ ui .StopSpinner (spin , false )
161166 return fmt .Errorf ("devbox stop: %w" , err )
162167 }
163168
164169 sshExec , err := devboxssh .New ()
165170 if err != nil {
171+ ui .StopSpinner (spin , false )
166172 return fmt .Errorf ("devbox stop: %w" , err )
167173 }
168174 defer sshExec .Close ()
@@ -174,6 +180,7 @@ func stopCmd(wm workspace.Manager) *cobra.Command {
174180 }
175181 }
176182
183+ ui .StopSpinner (spin , true )
177184 fmt .Printf ("Workspace %q stopped\n " , name )
178185 return nil
179186 },
@@ -197,14 +204,18 @@ func listCmd(wm workspace.Manager) *cobra.Command {
197204 return nil
198205 }
199206
200- w := tabwriter . NewWriter ( os . Stdout , 0 , 0 , 3 , ' ' , 0 )
201- fmt . Fprintln ( w , "NAME \t STATUS \t SERVER \t PORTS \t CREATED" )
207+ headers := [] string { "NAME" , "STATUS" , "SERVER" , "PORTS" , "CREATED" }
208+ rows := make ([][] string , 0 , len ( workspaces ) )
202209 for _ , ws := range workspaces {
203- fmt .Fprintf (w , "%s\t %s\t %s\t %s\t %s\n " ,
204- ws .Name , ws .Status , ws .ServerHost ,
205- formatPorts (ws .Ports ), timeAgo (ws .CreatedAt ))
210+ rows = append (rows , []string {
211+ ws .Name ,
212+ ui .StatusColor (ws .Status ),
213+ ws .ServerHost ,
214+ formatPorts (ws .Ports ),
215+ timeAgo (ws .CreatedAt ),
216+ })
206217 }
207- w . Flush ( )
218+ ui . PrintTable ( headers , rows )
208219
209220 return nil
210221 },
@@ -238,12 +249,16 @@ func destroyCmd(wm workspace.Manager) *cobra.Command {
238249 return fmt .Errorf ("devbox destroy: %w" , err )
239250 }
240251
252+ spin := ui .StartSpinner ("Destroying workspace..." )
253+
241254 if err := wm .Destroy (name ); err != nil {
255+ ui .StopSpinner (spin , false )
242256 return fmt .Errorf ("devbox destroy: %w" , err )
243257 }
244258
245259 sshExec , err := devboxssh .New ()
246260 if err != nil {
261+ ui .StopSpinner (spin , false )
247262 return fmt .Errorf ("devbox destroy: %w" , err )
248263 }
249264 defer sshExec .Close ()
@@ -255,6 +270,7 @@ func destroyCmd(wm workspace.Manager) *cobra.Command {
255270 }
256271 }
257272
273+ ui .StopSpinner (spin , true )
258274 fmt .Printf ("Workspace %q destroyed\n " , name )
259275 return nil
260276 },
0 commit comments