|  | @@ -27,17 +27,17 @@ import (
 | 
	
		
			
				|  |  |  	"syscall"
 | 
	
		
			
				|  |  |  	"time"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	"github.com/compose-spec/compose-go/types"
 | 
	
		
			
				|  |  | +	"github.com/sirupsen/logrus"
 | 
	
		
			
				|  |  | +	"github.com/spf13/cobra"
 | 
	
		
			
				|  |  | +	"golang.org/x/sync/errgroup"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	"github.com/docker/compose-cli/api/client"
 | 
	
		
			
				|  |  |  	"github.com/docker/compose-cli/api/compose"
 | 
	
		
			
				|  |  |  	"github.com/docker/compose-cli/api/context/store"
 | 
	
		
			
				|  |  |  	"github.com/docker/compose-cli/api/progress"
 | 
	
		
			
				|  |  |  	"github.com/docker/compose-cli/cli/cmd"
 | 
	
		
			
				|  |  |  	"github.com/docker/compose-cli/cli/formatter"
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	"github.com/compose-spec/compose-go/types"
 | 
	
		
			
				|  |  | -	"github.com/sirupsen/logrus"
 | 
	
		
			
				|  |  | -	"github.com/spf13/cobra"
 | 
	
		
			
				|  |  | -	"golang.org/x/sync/errgroup"
 | 
	
		
			
				|  |  |  )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // composeOptions hold options common to `up` and `run` to run compose project
 | 
	
	
		
			
				|  | @@ -69,26 +69,74 @@ type upOptions struct {
 | 
	
		
			
				|  |  |  	noInherit     bool
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (o upOptions) recreateStrategy() string {
 | 
	
		
			
				|  |  | -	if o.noRecreate {
 | 
	
		
			
				|  |  | +func (opts upOptions) recreateStrategy() string {
 | 
	
		
			
				|  |  | +	if opts.noRecreate {
 | 
	
		
			
				|  |  |  		return compose.RecreateNever
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	if o.forceRecreate {
 | 
	
		
			
				|  |  | +	if opts.forceRecreate {
 | 
	
		
			
				|  |  |  		return compose.RecreateForce
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	return compose.RecreateDiverged
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (o upOptions) dependenciesRecreateStrategy() string {
 | 
	
		
			
				|  |  | -	if o.noRecreate {
 | 
	
		
			
				|  |  | +func (opts upOptions) dependenciesRecreateStrategy() string {
 | 
	
		
			
				|  |  | +	if opts.noRecreate {
 | 
	
		
			
				|  |  |  		return compose.RecreateNever
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	if o.recreateDeps {
 | 
	
		
			
				|  |  | +	if opts.recreateDeps {
 | 
	
		
			
				|  |  |  		return compose.RecreateForce
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	return compose.RecreateDiverged
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +func (opts upOptions) GetTimeout() *time.Duration {
 | 
	
		
			
				|  |  | +	if opts.timeChanged {
 | 
	
		
			
				|  |  | +		t := time.Duration(opts.timeout) * time.Second
 | 
	
		
			
				|  |  | +		return &t
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	return nil
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func (opts upOptions) apply(project *types.Project, services []string) error {
 | 
	
		
			
				|  |  | +	if opts.noDeps {
 | 
	
		
			
				|  |  | +		enabled, err := project.GetServices(services...)
 | 
	
		
			
				|  |  | +		if err != nil {
 | 
	
		
			
				|  |  | +			return err
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		for _, s := range project.Services {
 | 
	
		
			
				|  |  | +			if !contains(services, s.Name) {
 | 
	
		
			
				|  |  | +				project.DisabledServices = append(project.DisabledServices, s)
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		project.Services = enabled
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if opts.exitCodeFrom != "" {
 | 
	
		
			
				|  |  | +		_, err := project.GetService(opts.exitCodeFrom)
 | 
	
		
			
				|  |  | +		if err != nil {
 | 
	
		
			
				|  |  | +			return err
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for _, scale := range opts.scale {
 | 
	
		
			
				|  |  | +		split := strings.Split(scale, "=")
 | 
	
		
			
				|  |  | +		if len(split) != 2 {
 | 
	
		
			
				|  |  | +			return fmt.Errorf("invalid --scale option %q. Should be SERVICE=NUM", scale)
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		name := split[0]
 | 
	
		
			
				|  |  | +		replicas, err := strconv.Atoi(split[1])
 | 
	
		
			
				|  |  | +		if err != nil {
 | 
	
		
			
				|  |  | +			return err
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		err = setServiceScale(project, name, replicas)
 | 
	
		
			
				|  |  | +		if err != nil {
 | 
	
		
			
				|  |  | +			return err
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return nil
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  func upCommand(p *projectOptions, contextType string) *cobra.Command {
 | 
	
		
			
				|  |  |  	opts := upOptions{
 | 
	
		
			
				|  |  |  		composeOptions: &composeOptions{
 | 
	
	
		
			
				|  | @@ -157,7 +205,7 @@ func runUp(ctx context.Context, opts upOptions, services []string) error {
 | 
	
		
			
				|  |  |  		return err
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	err = applyScaleOpt(opts.scale, project)
 | 
	
		
			
				|  |  | +	err = opts.apply(project, services)
 | 
	
		
			
				|  |  |  	if err != nil {
 | 
	
		
			
				|  |  |  		return err
 | 
	
		
			
				|  |  |  	}
 | 
	
	
		
			
				|  | @@ -176,35 +224,11 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
 | 
	
		
			
				|  |  |  		return err
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	if opts.noDeps {
 | 
	
		
			
				|  |  | -		enabled, err := project.GetServices(services...)
 | 
	
		
			
				|  |  | -		if err != nil {
 | 
	
		
			
				|  |  | -			return err
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		project.DisabledServices = append(project.DisabledServices, project.Services...)
 | 
	
		
			
				|  |  | -		project.Services = enabled
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	err = applyScaleOpt(opts.scale, project)
 | 
	
		
			
				|  |  | +	err = opts.apply(project, services)
 | 
	
		
			
				|  |  |  	if err != nil {
 | 
	
		
			
				|  |  |  		return err
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	if opts.exitCodeFrom != "" {
 | 
	
		
			
				|  |  | -		_, err := project.GetService(opts.exitCodeFrom)
 | 
	
		
			
				|  |  | -		if err != nil {
 | 
	
		
			
				|  |  | -			return err
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if opts.timeChanged {
 | 
	
		
			
				|  |  | -		timeoutValue := types.Duration(time.Duration(opts.timeout) * time.Second)
 | 
	
		
			
				|  |  | -		for i, s := range project.Services {
 | 
	
		
			
				|  |  | -			s.StopGracePeriod = &timeoutValue
 | 
	
		
			
				|  |  | -			project.Services[i] = s
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
 | 
	
		
			
				|  |  |  		err := c.ComposeService().Create(ctx, project, compose.CreateOptions{
 | 
	
		
			
				|  |  |  			Services:             services,
 | 
	
	
		
			
				|  | @@ -212,6 +236,7 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
 | 
	
		
			
				|  |  |  			Recreate:             opts.recreateStrategy(),
 | 
	
		
			
				|  |  |  			RecreateDependencies: opts.dependenciesRecreateStrategy(),
 | 
	
		
			
				|  |  |  			Inherit:              !opts.noInherit,
 | 
	
		
			
				|  |  | +			Timeout:              opts.GetTimeout(),
 | 
	
		
			
				|  |  |  		})
 | 
	
		
			
				|  |  |  		if err != nil {
 | 
	
		
			
				|  |  |  			return "", err
 | 
	
	
		
			
				|  | @@ -282,25 +307,6 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
 | 
	
		
			
				|  |  |  	return err
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func applyScaleOpt(opts []string, project *types.Project) error {
 | 
	
		
			
				|  |  | -	for _, scale := range opts {
 | 
	
		
			
				|  |  | -		split := strings.Split(scale, "=")
 | 
	
		
			
				|  |  | -		if len(split) != 2 {
 | 
	
		
			
				|  |  | -			return fmt.Errorf("invalid --scale option %q. Should be SERVICE=NUM", scale)
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		name := split[0]
 | 
	
		
			
				|  |  | -		replicas, err := strconv.Atoi(split[1])
 | 
	
		
			
				|  |  | -		if err != nil {
 | 
	
		
			
				|  |  | -			return err
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		err = setServiceScale(project, name, replicas)
 | 
	
		
			
				|  |  | -		if err != nil {
 | 
	
		
			
				|  |  | -			return err
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	return nil
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  func setServiceScale(project *types.Project, name string, replicas int) error {
 | 
	
		
			
				|  |  |  	for i, s := range project.Services {
 | 
	
		
			
				|  |  |  		if s.Name == name {
 |