Skip to content

Commit 46eafa8

Browse files
authored
[services] Start/stop multiple services DEV-1270 (#381)
## Summary This allows starting/stoping multiple services: `devbox services start` starts all services `devbox services start s1 s2` starts s1 and s2 If a service fails to start/stop we print and error and continue. If only a single service is meant to be started/stoped we return an error. ## How was it tested? ```sh devbox services start devbox services stop devbox services start apacheHttpd php-fpm devbox services stop apacheHttpd php-fpm ```
1 parent 239f4aa commit 46eafa8

File tree

4 files changed

+88
-46
lines changed

4 files changed

+88
-46
lines changed

devbox.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ type Devbox interface {
4141
// ShellPlan creates a plan of the actions that devbox will take to generate its
4242
// shell environment.
4343
ShellPlan() (*plansdk.ShellPlan, error)
44-
StartService(serviceName string) error
45-
StopService(serviceName string) error
44+
StartServices(services ...string) error
45+
StopServices(services ...string) error
4646
}
4747

4848
// Open opens a devbox by reading the config file in dir.

internal/boxcli/services.go

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,18 @@ func ServicesCmd() *cobra.Command {
3434
}
3535

3636
startCommand := &cobra.Command{
37-
Use: "start [service]",
38-
Short: "Starts service",
39-
Args: cobra.ExactArgs(1),
37+
Use: "start [service]...",
38+
Short: "Starts service. If no service is specified, starts all services",
4039
RunE: func(cmd *cobra.Command, args []string) error {
41-
return startService(args[0], flags)
40+
return startServices(cmd, args, flags)
4241
},
4342
}
4443

4544
stopCommand := &cobra.Command{
46-
Use: "stop [service]",
47-
Short: "Stops service",
48-
Args: cobra.ExactArgs(1),
45+
Use: "stop [service]...",
46+
Short: "Stops service. If no service is specified, stops all services",
4947
RunE: func(cmd *cobra.Command, args []string) error {
50-
return stopService(args[0], flags)
48+
return stopServices(cmd, args, flags)
5149
},
5250
}
5351

@@ -73,18 +71,50 @@ func listServices(cmd *cobra.Command, flags servicesCmdFlags) error {
7371
return nil
7472
}
7573

76-
func startService(service string, flags servicesCmdFlags) error {
74+
func startServices(cmd *cobra.Command, services []string, flags servicesCmdFlags) error {
7775
box, err := devbox.Open(flags.config.path, os.Stdout)
7876
if err != nil {
7977
return errors.WithStack(err)
8078
}
81-
return box.StartService(service)
79+
if len(services) == 0 {
80+
services, err = serviceNames(box)
81+
if err != nil {
82+
return err
83+
}
84+
if len(services) == 0 {
85+
cmd.Println("No services to start")
86+
return nil
87+
}
88+
}
89+
return box.StartServices(services...)
8290
}
8391

84-
func stopService(service string, flags servicesCmdFlags) error {
92+
func stopServices(cmd *cobra.Command, services []string, flags servicesCmdFlags) error {
8593
box, err := devbox.Open(flags.config.path, os.Stdout)
8694
if err != nil {
8795
return errors.WithStack(err)
8896
}
89-
return box.StopService(service)
97+
if len(services) == 0 {
98+
services, err = serviceNames(box)
99+
if err != nil {
100+
return err
101+
}
102+
if len(services) == 0 {
103+
cmd.Println("No services to stop")
104+
return nil
105+
}
106+
}
107+
return box.StopServices(services...)
108+
}
109+
110+
func serviceNames(box devbox.Devbox) ([]string, error) {
111+
services, err := box.Services()
112+
if err != nil {
113+
return nil, err
114+
}
115+
names := []string{}
116+
for _, service := range services {
117+
names = append(names, service.Name)
118+
}
119+
return names, nil
90120
}

internal/impl/devbox.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -457,18 +457,18 @@ func (d *Devbox) Services() (plugin.Services, error) {
457457
return plugin.GetServices(d.cfg.Packages, d.configDir)
458458
}
459459

460-
func (d *Devbox) StartService(serviceName string) error {
460+
func (d *Devbox) StartServices(services ...string) error {
461461
if !IsDevboxShellEnabled() {
462-
return d.Exec("devbox", "services", "start", serviceName)
462+
return d.Exec(append([]string{"devbox", "services", "start"}, services...)...)
463463
}
464-
return plugin.StartService(d.cfg.Packages, serviceName, d.configDir, d.writer)
464+
return plugin.StartServices(d.cfg.Packages, services, d.configDir, d.writer)
465465
}
466466

467-
func (d *Devbox) StopService(serviceName string) error {
467+
func (d *Devbox) StopServices(services ...string) error {
468468
if !IsDevboxShellEnabled() {
469-
return d.Exec("devbox", "services", "stop", serviceName)
469+
return d.Exec(append([]string{"devbox", "services", "stop"}, services...)...)
470470
}
471-
return plugin.StopService(d.cfg.Packages, serviceName, d.configDir, d.writer)
471+
return plugin.StopServices(d.cfg.Packages, services, d.configDir, d.writer)
472472
}
473473

474474
func (d *Devbox) generateShellFiles() error {

internal/plugin/services.go

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -48,40 +48,52 @@ func (s *Services) UnmarshalJSON(b []byte) error {
4848
return nil
4949
}
5050

51-
func StartService(pkgs []string, name, rootDir string, out io.Writer) error {
52-
services, err := GetServices(pkgs, rootDir)
51+
func StartServices(pkgs, serviceNames []string, root string, w io.Writer) error {
52+
services, err := GetServices(pkgs, root)
5353
if err != nil {
5454
return err
5555
}
56-
service, found := services[name]
57-
if !found {
58-
return usererr.New("Service not found")
59-
}
60-
cmd := exec.Command("sh", "-c", service.Start)
61-
cmd.Stdout = out
62-
cmd.Stderr = out
63-
err = cmd.Run()
64-
if err == nil {
65-
fmt.Fprintf(out, "Service %q started", name)
56+
for _, name := range serviceNames {
57+
service, found := services[name]
58+
if !found {
59+
return usererr.New("Service not found")
60+
}
61+
cmd := exec.Command("sh", "-c", service.Start)
62+
cmd.Stdout = w
63+
cmd.Stderr = w
64+
if err = cmd.Run(); err != nil {
65+
if len(serviceNames) == 1 {
66+
return usererr.WithUserMessage(err, "Service %q failed to start", name)
67+
}
68+
fmt.Fprintf(w, "Service %q failed to start. Error = %s\n", name, err)
69+
} else {
70+
fmt.Fprintf(w, "Service %q started\n", name)
71+
}
6672
}
67-
return usererr.WithUserMessage(err, "Service %q failed to start", name)
73+
return nil
6874
}
6975

70-
func StopService(pkgs []string, name, rootDir string, out io.Writer) error {
71-
services, err := GetServices(pkgs, rootDir)
76+
func StopServices(pkgs, serviceNames []string, root string, w io.Writer) error {
77+
services, err := GetServices(pkgs, root)
7278
if err != nil {
7379
return err
7480
}
75-
service, found := services[name]
76-
if !found {
77-
return usererr.New("Service not found")
78-
}
79-
cmd := exec.Command("sh", "-c", service.Stop)
80-
cmd.Stdout = out
81-
cmd.Stderr = out
82-
err = cmd.Run()
83-
if err == nil {
84-
fmt.Fprintf(out, "Service %q stopped", name)
81+
for _, name := range serviceNames {
82+
service, found := services[name]
83+
if !found {
84+
return usererr.New("Service not found")
85+
}
86+
cmd := exec.Command("sh", "-c", service.Stop)
87+
cmd.Stdout = w
88+
cmd.Stderr = w
89+
if err = cmd.Run(); err != nil {
90+
if len(serviceNames) == 1 {
91+
return usererr.WithUserMessage(err, "Service %q failed to stop", name)
92+
}
93+
fmt.Fprintf(w, "Service %q failed to stop. Error = %s\n", name, err)
94+
} else {
95+
fmt.Fprintf(w, "Service %q stopped\n", name)
96+
}
8597
}
86-
return usererr.WithUserMessage(err, "Service %q failed to stop", name)
98+
return nil
8799
}

0 commit comments

Comments
 (0)