diff --git a/cmd/compose/attach.go b/cmd/compose/attach.go new file mode 100644 index 000000000..79ef12b93 --- /dev/null +++ b/cmd/compose/attach.go @@ -0,0 +1,79 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package compose + +import ( + "context" + + "github.com/docker/cli/cli/command" + "github.com/docker/compose/v2/pkg/api" + "github.com/spf13/cobra" +) + +type attachOpts struct { + *composeOptions + + service string + index int + + detachKeys string + + // todo docker container attach also has: + // --no-stdin // whole point of attach is for STDIN (can already attach to STDOUT and STDERR via docker compose up) + // --sig-proxy + +} + +func attachCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command { + opts := attachOpts{ + composeOptions: &composeOptions{ + ProjectOptions: p, + }, + } + runCmd := &cobra.Command{ + Use: "attach [OPTIONS] SERVICE", + Short: "Attach local standard input, output, and error streams to a service's running container.", + Args: cobra.MinimumNArgs(1), + PreRunE: Adapt(func(ctx context.Context, args []string) error { + opts.service = args[0] + return nil + }), + RunE: Adapt(func(ctx context.Context, args []string) error { + return runAttach(ctx, dockerCli, backend, opts) + }), + ValidArgsFunction: completeServiceNames(dockerCli, p), + } + + runCmd.Flags().IntVar(&opts.index, "index", 0, "index of the container if service has multiple replicas.") + runCmd.Flags().StringVarP(&opts.detachKeys, "detach-keys", "", "", "Override the key sequence for detaching from a container.") + + return runCmd +} + +func runAttach(ctx context.Context, dockerCli command.Cli, backend api.Service, opts attachOpts) error { + projectName, err := opts.toProjectName(dockerCli) + if err != nil { + return err + } + + attachOpts := api.AttachOptions{ + Service: opts.service, + Index: opts.index, + DetachKeys: opts.detachKeys, + } + return backend.Attach(ctx, projectName, attachOpts) +} diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index cddcd3a4c..d7f7f9d7c 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -445,6 +445,7 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { // runCommand(&opts, dockerCli, backend), removeCommand(&opts, dockerCli, backend), execCommand(&opts, dockerCli, backend), + attachCommand(&opts, dockerCli, backend), pauseCommand(&opts, dockerCli, backend), unpauseCommand(&opts, dockerCli, backend), topCommand(&opts, dockerCli, backend), diff --git a/pkg/api/api.go b/pkg/api/api.go index 7dafbe9c1..62a27cf95 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -62,6 +62,8 @@ type Service interface { Remove(ctx context.Context, projectName string, options RemoveOptions) error // Exec executes a command in a running service container Exec(ctx context.Context, projectName string, options RunOptions) (int, error) + // Attach STDIN,STDOUT,STDERR to a running service container + Attach(ctx context.Context, projectName string, options AttachOptions) error // Copy copies a file/folder between a service container and the local filesystem Copy(ctx context.Context, projectName string, options CopyOptions) error // Pause executes the equivalent to a `compose pause` @@ -342,6 +344,14 @@ type RunOptions struct { Index int } +// AttachOptions group options of the Attach API +type AttachOptions struct { + Project *types.Project + Service string + Index int + DetachKeys string +} + // EventsOptions group options of the Events API type EventsOptions struct { Services []string diff --git a/pkg/compose/attach_service.go b/pkg/compose/attach_service.go new file mode 100644 index 000000000..68bf85972 --- /dev/null +++ b/pkg/compose/attach_service.go @@ -0,0 +1,37 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package compose + +import ( + "context" + "strings" + + "github.com/docker/cli/cli/command/container" + "github.com/docker/compose/v2/pkg/api" +) + +func (s *composeService) Attach(ctx context.Context, projectName string, options api.AttachOptions) error { + projectName = strings.ToLower(projectName) + target, err := s.getSpecifiedContainer(ctx, projectName, oneOffInclude, false, options.Service, options.Index) + if err != nil { + return err + } + + var attach container.AttachOptions + attach.DetachKeys = options.DetachKeys + return container.RunAttach(ctx, s.dockerCli, target.ID, &attach) +}