cli: option to write status messages on stdout (#10549)

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De loof 2023-05-11 18:45:00 +02:00 committed by GitHub
parent 0363d9260a
commit a14abb9044
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 44 additions and 26 deletions

View File

@ -52,7 +52,7 @@ func (s *composeService) Build(ctx context.Context, project *types.Project, opti
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
_, err := s.build(ctx, project, options)
return err
}, s.stderr(), "Building")
}, s.stdinfo(), "Building")
}
func (s *composeService) build(ctx context.Context, project *types.Project, options api.BuildOptions) (map[string]string, error) { //nolint:gocyclo

View File

@ -21,6 +21,7 @@ import (
"encoding/json"
"fmt"
"io"
"os"
"strconv"
"strings"
@ -40,6 +41,15 @@ import (
"github.com/docker/compose/v2/pkg/api"
)
var stdioToStdout bool
func init() {
out, ok := os.LookupEnv("COMPOSE_STATUS_STDOUT")
if ok {
stdioToStdout, _ = strconv.ParseBool(out)
}
}
// NewComposeService create a local implementation of the compose.Service API
func NewComposeService(dockerCli command.Cli) api.Service {
return &composeService{
@ -97,6 +107,13 @@ func (s *composeService) stderr() io.Writer {
return s.dockerCli.Err()
}
func (s *composeService) stdinfo() io.Writer {
if stdioToStdout {
return s.dockerCli.Out()
}
return s.dockerCli.Err()
}
func getCanonicalContainerName(c moby.Container) string {
if len(c.Names) == 0 {
// corner case, sometime happens on removal. return short ID as a safeguard value

View File

@ -46,7 +46,7 @@ const (
func (s *composeService) Copy(ctx context.Context, projectName string, options api.CopyOptions) error {
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
return s.copy(ctx, projectName, options)
}, s.stderr(), "Copying")
}, s.stdinfo(), "Copying")
}
func (s *composeService) copy(ctx context.Context, projectName string, options api.CopyOptions) error {

View File

@ -51,7 +51,7 @@ import (
func (s *composeService) Create(ctx context.Context, project *types.Project, options api.CreateOptions) error {
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
return s.create(ctx, project, options)
}, s.stderr(), "Creating")
}, s.stdinfo(), "Creating")
}
func (s *composeService) create(ctx context.Context, project *types.Project, options api.CreateOptions) error {

View File

@ -41,7 +41,7 @@ type downOp func() error
func (s *composeService) Down(ctx context.Context, projectName string, options api.DownOptions) error {
return progress.Run(ctx, func(ctx context.Context) error {
return s.down(ctx, strings.ToLower(projectName), options)
}, s.stderr())
}, s.stdinfo())
}
func (s *composeService) down(ctx context.Context, projectName string, options api.DownOptions) error {

View File

@ -31,7 +31,7 @@ import (
func (s *composeService) Kill(ctx context.Context, projectName string, options api.KillOptions) error {
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
return s.kill(ctx, strings.ToLower(projectName), options)
}, s.stderr(), "Killing")
}, s.stdinfo(), "Killing")
}
func (s *composeService) kill(ctx context.Context, projectName string, options api.KillOptions) error {
@ -57,7 +57,8 @@ func (s *composeService) kill(ctx context.Context, projectName string, options a
containers = containers.filter(isService(project.ServiceNames()...))
}
if len(containers) == 0 {
fmt.Fprintf(s.stderr(), "no container to kill")
fmt.Fprintf(s.stdinfo(), "no container to kill")
return nil
}
eg, ctx := errgroup.WithContext(ctx)

View File

@ -30,7 +30,7 @@ import (
func (s *composeService) Pause(ctx context.Context, projectName string, options api.PauseOptions) error {
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
return s.pause(ctx, strings.ToLower(projectName), options)
}, s.stderr(), "Pausing")
}, s.stdinfo(), "Pausing")
}
func (s *composeService) pause(ctx context.Context, projectName string, options api.PauseOptions) error {
@ -62,7 +62,7 @@ func (s *composeService) pause(ctx context.Context, projectName string, options
func (s *composeService) UnPause(ctx context.Context, projectName string, options api.PauseOptions) error {
return progress.Run(ctx, func(ctx context.Context) error {
return s.unPause(ctx, strings.ToLower(projectName), options)
}, s.stderr())
}, s.stdinfo())
}
func (s *composeService) unPause(ctx context.Context, projectName string, options api.PauseOptions) error {

View File

@ -44,7 +44,7 @@ func (s *composeService) Pull(ctx context.Context, project *types.Project, optio
}
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
return s.pull(ctx, project, options)
}, s.stderr(), "Pulling")
}, s.stdinfo(), "Pulling")
}
func (s *composeService) pull(ctx context.Context, project *types.Project, opts api.PullOptions) error { //nolint:gocyclo
@ -305,7 +305,7 @@ func (s *composeService) pullRequiredImages(ctx context.Context, project *types.
}
}
return err
}, s.stderr())
}, s.stdinfo())
}
func isServiceImageToBuild(service types.ServiceConfig, services []types.ServiceConfig) bool {

View File

@ -42,7 +42,7 @@ func (s *composeService) Push(ctx context.Context, project *types.Project, optio
}
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
return s.push(ctx, project, options)
}, s.stderr(), "Pushing")
}, s.stdinfo(), "Pushing")
}
func (s *composeService) push(ctx context.Context, project *types.Project, options api.PushOptions) error {

View File

@ -75,10 +75,10 @@ func (s *composeService) Remove(ctx context.Context, projectName string, options
stoppedContainers.forEach(func(c moby.Container) {
names = append(names, getCanonicalContainerName(c))
})
fmt.Fprintln(s.stderr(), names)
fmt.Fprintln(s.stdinfo(), names)
if len(names) == 0 {
fmt.Fprintln(s.stderr(), "No stopped containers")
fmt.Fprintln(s.stdinfo(), "No stopped containers")
return nil
}
msg := fmt.Sprintf("Going to remove %s", strings.Join(names, ", "))
@ -95,7 +95,7 @@ func (s *composeService) Remove(ctx context.Context, projectName string, options
}
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
return s.remove(ctx, stoppedContainers, options)
}, s.stderr(), "Removing")
}, s.stdinfo(), "Removing")
}
func (s *composeService) remove(ctx context.Context, containers Containers, options api.RemoveOptions) error {

View File

@ -31,7 +31,7 @@ import (
func (s *composeService) Restart(ctx context.Context, projectName string, options api.RestartOptions) error {
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
return s.restart(ctx, strings.ToLower(projectName), options)
}, s.stderr(), "Restarting")
}, s.stdinfo(), "Restarting")
}
func (s *composeService) restart(ctx context.Context, projectName string, options api.RestartOptions) error {

View File

@ -38,7 +38,7 @@ import (
func (s *composeService) Start(ctx context.Context, projectName string, options api.StartOptions) error {
return progress.Run(ctx, func(ctx context.Context) error {
return s.start(ctx, strings.ToLower(projectName), options, nil)
}, s.stderr())
}, s.stdinfo())
}
func (s *composeService) start(ctx context.Context, projectName string, options api.StartOptions, listener api.ContainerEventListener) error {

View File

@ -28,7 +28,7 @@ import (
func (s *composeService) Stop(ctx context.Context, projectName string, options api.StopOptions) error {
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
return s.stop(ctx, strings.ToLower(projectName), options)
}, s.stderr(), "Stopping")
}, s.stdinfo(), "Stopping")
}
func (s *composeService) stop(ctx context.Context, projectName string, options api.StopOptions) error {

View File

@ -40,7 +40,7 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
return s.start(ctx, project.Name, options.Start, nil)
}
return nil
}, s.stderr())
}, s.stdinfo())
if err != nil {
return err
}
@ -59,7 +59,7 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
stopFunc := func() error {
fmt.Fprintln(s.stderr(), "Aborting on container exit...")
fmt.Fprintln(s.stdinfo(), "Aborting on container exit...")
ctx := context.Background()
return progress.Run(ctx, func(ctx context.Context) error {
go func() {
@ -74,7 +74,7 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
Services: options.Create.Services,
Project: project,
})
}, s.stderr())
}, s.stdinfo())
}
var isTerminated bool
@ -83,7 +83,7 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
<-signalChan
isTerminated = true
printer.Cancel()
fmt.Fprintln(s.stderr(), "Gracefully stopping... (press Ctrl+C again to force)")
fmt.Fprintln(s.stdinfo(), "Gracefully stopping... (press Ctrl+C again to force)")
eg.Go(stopFunc)
}()

View File

@ -155,7 +155,7 @@ func (s *composeService) Watch(ctx context.Context, project *types.Project, serv
return err
}
fmt.Fprintf(s.stderr(), "watching %s\n", bc)
fmt.Fprintf(s.stdinfo(), "watching %s\n", bc)
err = watcher.Start()
if err != nil {
return err
@ -207,7 +207,7 @@ WATCH:
continue
}
fmt.Fprintf(s.stderr(), "change detected on %s\n", hostPath)
fmt.Fprintf(s.stdinfo(), "change detected on %s\n", hostPath)
f := fileMapping{
HostPath: hostPath,
@ -283,7 +283,7 @@ func (s *composeService) makeRebuildFn(ctx context.Context, project *types.Proje
}
fmt.Fprintf(
s.stderr(),
s.stdinfo(),
"Rebuilding %s after changes were detected:%s\n",
strings.Join(serviceNames, ", "),
strings.Join(append([]string{""}, allPaths.Elements()...), "\n - "),
@ -319,7 +319,7 @@ func (s *composeService) makeSyncFn(ctx context.Context, project *types.Project,
if err != nil {
return err
}
fmt.Fprintf(s.stderr(), "%s updated\n", opt.ContainerPath)
fmt.Fprintf(s.stdinfo(), "%s updated\n", opt.ContainerPath)
} else if errors.Is(statErr, fs.ErrNotExist) {
_, err := s.Exec(ctx, project.Name, api.RunOptions{
Service: opt.Service,
@ -329,7 +329,7 @@ func (s *composeService) makeSyncFn(ctx context.Context, project *types.Project,
if err != nil {
logrus.Warnf("failed to delete %q from %s: %v", opt.ContainerPath, opt.Service, err)
}
fmt.Fprintf(s.stderr(), "%s deleted from container\n", opt.ContainerPath)
fmt.Fprintf(s.stdinfo(), "%s deleted from container\n", opt.ContainerPath)
}
}
}