|  | @@ -18,11 +18,11 @@ package compose
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import (
 | 
	
		
			
				|  |  |  	"context"
 | 
	
		
			
				|  |  | -	"errors"
 | 
	
		
			
				|  |  |  	"fmt"
 | 
	
		
			
				|  |  | -	"github.com/sirupsen/logrus"
 | 
	
		
			
				|  |  |  	"os"
 | 
	
		
			
				|  |  | +	"os/signal"
 | 
	
		
			
				|  |  |  	"path/filepath"
 | 
	
		
			
				|  |  | +	"syscall"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	"github.com/docker/compose-cli/api/client"
 | 
	
		
			
				|  |  |  	"github.com/docker/compose-cli/api/compose"
 | 
	
	
		
			
				|  | @@ -31,6 +31,7 @@ import (
 | 
	
		
			
				|  |  |  	"github.com/docker/compose-cli/cli/formatter"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	"github.com/compose-spec/compose-go/types"
 | 
	
		
			
				|  |  | +	"github.com/sirupsen/logrus"
 | 
	
		
			
				|  |  |  	"github.com/spf13/cobra"
 | 
	
		
			
				|  |  |  )
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -151,47 +152,35 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
 | 
	
		
			
				|  |  |  		return nil
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	ctx, cancel := context.WithCancel(ctx)
 | 
	
		
			
				|  |  | -	listener := make(chan compose.ContainerExited)
 | 
	
		
			
				|  |  | -	exitCode := make(chan int)
 | 
	
		
			
				|  |  | +	queue := make(chan compose.ContainerEvent)
 | 
	
		
			
				|  |  | +	printer := printer{
 | 
	
		
			
				|  |  | +		queue: queue,
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	stopFunc := func() error {
 | 
	
		
			
				|  |  | +		ctx := context.Background()
 | 
	
		
			
				|  |  | +		_, err := progress.Run(ctx, func(ctx context.Context) (string, error) {
 | 
	
		
			
				|  |  | +			return "", c.ComposeService().Stop(ctx, project)
 | 
	
		
			
				|  |  | +		})
 | 
	
		
			
				|  |  | +		return err
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	signalChan := make(chan os.Signal, 1)
 | 
	
		
			
				|  |  | +	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
 | 
	
		
			
				|  |  |  	go func() {
 | 
	
		
			
				|  |  | -		var aborting bool
 | 
	
		
			
				|  |  | -		for {
 | 
	
		
			
				|  |  | -			exit := <-listener
 | 
	
		
			
				|  |  | -			if opts.cascadeStop && !aborting {
 | 
	
		
			
				|  |  | -				aborting = true
 | 
	
		
			
				|  |  | -				cancel()
 | 
	
		
			
				|  |  | -				exitCode <- exit.Status
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | +		<-signalChan
 | 
	
		
			
				|  |  | +		fmt.Println("Gracefully stopping...")
 | 
	
		
			
				|  |  | +		stopFunc() // nolint:errcheck
 | 
	
		
			
				|  |  |  	}()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	err = c.ComposeService().Start(ctx, project, compose.StartOptions{
 | 
	
		
			
				|  |  | -		Attach:   formatter.NewLogConsumer(ctx, os.Stdout),
 | 
	
		
			
				|  |  | -		Listener: listener,
 | 
	
		
			
				|  |  | +		Attach: queue,
 | 
	
		
			
				|  |  |  	})
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if errors.Is(ctx.Err(), context.Canceled) {
 | 
	
		
			
				|  |  | -		select {
 | 
	
		
			
				|  |  | -		case exit := <-exitCode:
 | 
	
		
			
				|  |  | -			fmt.Println("Aborting on container exit...")
 | 
	
		
			
				|  |  | -			err = stop(c, project)
 | 
	
		
			
				|  |  | -			logrus.Error(exit)
 | 
	
		
			
				|  |  | -			// os.Exit(exit)
 | 
	
		
			
				|  |  | -		default:
 | 
	
		
			
				|  |  | -			// cancelled by user
 | 
	
		
			
				|  |  | -			fmt.Println("Gracefully stopping...")
 | 
	
		
			
				|  |  | -			err = stop(c, project)
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | +	if err != nil {
 | 
	
		
			
				|  |  | +		return err
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	return err
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func stop(c *client.Client, project *types.Project) error {
 | 
	
		
			
				|  |  | -	ctx := context.Background()
 | 
	
		
			
				|  |  | -	_, err := progress.Run(ctx, func(ctx context.Context) (string, error) {
 | 
	
		
			
				|  |  | -		return "", c.ComposeService().Stop(ctx, project)
 | 
	
		
			
				|  |  | -	})
 | 
	
		
			
				|  |  | +	_, err = printer.run(ctx, opts.cascadeStop, stopFunc)
 | 
	
		
			
				|  |  | +	// FIXME os.Exit
 | 
	
		
			
				|  |  |  	return err
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -235,3 +224,26 @@ func setup(ctx context.Context, opts composeOptions, services []string) (*client
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	return c, project, nil
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +type printer struct {
 | 
	
		
			
				|  |  | +	queue chan compose.ContainerEvent
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func (p printer) run(ctx context.Context, cascadeStop bool, stopFn func() error) (int, error) { //nolint:unparam
 | 
	
		
			
				|  |  | +	consumer := formatter.NewLogConsumer(ctx, os.Stdout)
 | 
	
		
			
				|  |  | +	for {
 | 
	
		
			
				|  |  | +		event := <-p.queue
 | 
	
		
			
				|  |  | +		switch event.Type {
 | 
	
		
			
				|  |  | +		case compose.ContainerEventExit:
 | 
	
		
			
				|  |  | +			consumer.Status(event.Service, event.Source, fmt.Sprintf("exited with code %d", event.ExitCode))
 | 
	
		
			
				|  |  | +			if cascadeStop {
 | 
	
		
			
				|  |  | +				fmt.Println("Aborting on container exit...")
 | 
	
		
			
				|  |  | +				err := stopFn()
 | 
	
		
			
				|  |  | +				logrus.Error(event.ExitCode)
 | 
	
		
			
				|  |  | +				return event.ExitCode, err
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +		case compose.ContainerEventLog:
 | 
	
		
			
				|  |  | +			consumer.Log(event.Service, event.Source, event.Line)
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 |