diff --git a/aci/compose.go b/aci/compose.go index f430ae34..a8e65c2a 100644 --- a/aci/compose.go +++ b/aci/compose.go @@ -202,9 +202,6 @@ func (cs *aciComposeService) Convert(ctx context.Context, project *types.Project return nil, errdefs.ErrNotImplemented } -func (cs *aciComposeService) CreateOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) (string, error) { +func (cs *aciComposeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) (string, error) { return "", errdefs.ErrNotImplemented } -func (cs *aciComposeService) Run(ctx context.Context, container string, detach bool) error { - return errdefs.ErrNotImplemented -} diff --git a/api/client/compose.go b/api/client/compose.go index 5693842d..2525b0d5 100644 --- a/api/client/compose.go +++ b/api/client/compose.go @@ -72,10 +72,6 @@ func (c *composeService) Convert(context.Context, *types.Project, compose.Conver return nil, errdefs.ErrNotImplemented } -func (c *composeService) CreateOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) (string, error) { +func (c *composeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) (string, error) { return "", errdefs.ErrNotImplemented } - -func (c *composeService) Run(ctx context.Context, container string, detach bool) error { - return errdefs.ErrNotImplemented -} diff --git a/api/compose/api.go b/api/compose/api.go index b0c57d4c..f1b8e667 100644 --- a/api/compose/api.go +++ b/api/compose/api.go @@ -46,10 +46,8 @@ type Service interface { List(ctx context.Context, projectName string) ([]Stack, error) // Convert translate compose model into backend's native format Convert(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error) - // CreateOneOffContainer creates a service oneoff container and starts its dependencies - CreateOneOffContainer(ctx context.Context, project *types.Project, opts RunOptions) (string, error) - // Run attaches to and starts a one-off container - Run(ctx context.Context, container string, detach bool) error + // RunOneOffContainer creates a service oneoff container and starts its dependencies + RunOneOffContainer(ctx context.Context, project *types.Project, opts RunOptions) (string, error) } // UpOptions group options of the Up API @@ -74,6 +72,7 @@ type ConvertOptions struct { type RunOptions struct { Name string Command []string + Detach bool } // PortPublisher hold status about published port diff --git a/cli/cmd/compose/run.go b/cli/cmd/compose/run.go index 3979ff75..42e47842 100644 --- a/cli/cmd/compose/run.go +++ b/cli/cmd/compose/run.go @@ -20,6 +20,7 @@ import ( "context" "fmt" + "github.com/compose-spec/compose-go/types" "github.com/spf13/cobra" "github.com/docker/compose-cli/api/compose" @@ -72,17 +73,30 @@ func runRun(ctx context.Context, opts runOptions) error { return err } + dependencies := []types.ServiceConfig{} + originalServices := project.Services containerID, err := progress.Run(ctx, func(ctx context.Context) (string, error) { - return c.ComposeService().CreateOneOffContainer(ctx, project, compose.RunOptions{ - Name: opts.Name, - Command: opts.Command, - }) + for _, service := range originalServices { + if service.Name != opts.Name { + dependencies = append(dependencies, service) + } + } + project.Services = types.Services(dependencies) + if err := c.ComposeService().Create(ctx, project); err != nil { + return "", err + } + if err := c.ComposeService().Start(ctx, project, nil); err != nil { + return "", err + } + return "", nil }) if err != nil { return err } + + project.Services = originalServices // start container and attach to container streams - err = c.ComposeService().Run(ctx, containerID, opts.Detach) + containerID, err = c.ComposeService().RunOneOffContainer(ctx, project, compose.RunOptions{Name: opts.Name, Command: opts.Command, Detach: opts.Detach}) if err != nil { return err } diff --git a/ecs/local/compose.go b/ecs/local/compose.go index 9dac1de8..8f5c5bd3 100644 --- a/ecs/local/compose.go +++ b/ecs/local/compose.go @@ -163,9 +163,6 @@ func (e ecsLocalSimulation) Ps(ctx context.Context, projectName string) ([]compo func (e ecsLocalSimulation) List(ctx context.Context, projectName string) ([]compose.Stack, error) { return e.compose.List(ctx, projectName) } -func (e ecsLocalSimulation) CreateOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) (string, error) { +func (e ecsLocalSimulation) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) (string, error) { return "", errors.Wrap(errdefs.ErrNotImplemented, "use docker-compose run") } -func (e ecsLocalSimulation) Run(ctx context.Context, container string, detach bool) error { - return errdefs.ErrNotImplemented -} diff --git a/ecs/run.go b/ecs/run.go index 643c944c..4ce83c33 100644 --- a/ecs/run.go +++ b/ecs/run.go @@ -24,10 +24,6 @@ import ( "github.com/docker/compose-cli/errdefs" ) -func (b *ecsAPIService) CreateOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) (string, error) { +func (b *ecsAPIService) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) (string, error) { return "", errdefs.ErrNotImplemented } - -func (b *ecsAPIService) Run(ctx context.Context, container string, detach bool) error { - return errdefs.ErrNotImplemented -} diff --git a/example/backend.go b/example/backend.go index 55a32d1d..2aba4a76 100644 --- a/example/backend.go +++ b/example/backend.go @@ -182,10 +182,6 @@ func (cs *composeService) Logs(ctx context.Context, projectName string, consumer func (cs *composeService) Convert(ctx context.Context, project *types.Project, options compose.ConvertOptions) ([]byte, error) { return nil, errdefs.ErrNotImplemented } -func (cs *composeService) CreateOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) (string, error) { +func (cs *composeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) (string, error) { return "", errdefs.ErrNotImplemented } - -func (cs *composeService) Run(ctx context.Context, container string, detach bool) error { - return errdefs.ErrNotImplemented -} diff --git a/local/compose/run.go b/local/compose/run.go index 77682ff1..2c7b1e6d 100644 --- a/local/compose/run.go +++ b/local/compose/run.go @@ -29,27 +29,27 @@ import ( moby "github.com/docker/docker/pkg/stringid" ) -func (s *composeService) CreateOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) (string, error) { +func (s *composeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) (string, error) { originalServices := project.Services - dependencies := []types.ServiceConfig{} var requestedService types.ServiceConfig for _, service := range originalServices { - if service.Name != opts.Name { - dependencies = append(dependencies, service) - } else { + if service.Name == opts.Name { requestedService = service } } - project.Services = types.Services(dependencies) - if err := s.Create(ctx, project); err != nil { - return "", err - } - if err := s.Start(ctx, project, nil); err != nil { - return "", err - } project.Services = originalServices - updateOneOffServiceConfig(&requestedService, project.Name, opts) + if len(opts.Command) > 0 { + requestedService.Command = opts.Command + } + requestedService.Scale = 1 + requestedService.Tty = true + requestedService.StdinOpen = true + + slug := moby.GenerateRandomID() + requestedService.ContainerName = fmt.Sprintf("%s_%s_run_%s", project.Name, requestedService.Name, moby.TruncateID(slug)) + requestedService.Labels = requestedService.Labels.Add(slugLabel, slug) + requestedService.Labels = requestedService.Labels.Add(oneoffLabel, "True") if err := s.waitDependencies(ctx, project, requestedService); err != nil { return "", err @@ -59,15 +59,13 @@ func (s *composeService) CreateOneOffContainer(ctx context.Context, project *typ return "", err } - return requestedService.ContainerName, err -} + containerID := requestedService.ContainerName -func (s *composeService) Run(ctx context.Context, container string, detach bool) error { - if detach { - return s.apiClient.ContainerStart(ctx, container, apitypes.ContainerStartOptions{}) + if opts.Detach { + return containerID, s.apiClient.ContainerStart(ctx, containerID, apitypes.ContainerStartOptions{}) } - cnx, err := s.apiClient.ContainerAttach(ctx, container, apitypes.ContainerAttachOptions{ + cnx, err := s.apiClient.ContainerAttach(ctx, containerID, apitypes.ContainerAttachOptions{ Stream: true, Stdin: true, Stdout: true, @@ -75,7 +73,7 @@ func (s *composeService) Run(ctx context.Context, container string, detach bool) Logs: true, }) if err != nil { - return err + return containerID, err } defer cnx.Close() @@ -102,32 +100,17 @@ func (s *composeService) Run(ctx context.Context, container string, detach bool) }() // start container - err = s.apiClient.ContainerStart(ctx, container, apitypes.ContainerStartOptions{}) + err = s.apiClient.ContainerStart(ctx, containerID, apitypes.ContainerStartOptions{}) if err != nil { - return err + return containerID, err } for { select { case err := <-readChannel: - return err + return containerID, err case err := <-writeChannel: - return err + return containerID, err } } } - -func updateOneOffServiceConfig(service *types.ServiceConfig, projectName string, opts compose.RunOptions) { - if len(opts.Command) > 0 { - service.Command = opts.Command - } - slug := moby.GenerateRandomID() - service.Scale = 1 - service.ContainerName = fmt.Sprintf("%s_%s_run_%s", projectName, service.Name, moby.TruncateID(slug)) - service.Labels = types.Labels{ - slugLabel: slug, - oneoffLabel: "True", - } - service.Tty = true - service.StdinOpen = true -}