Merge pull request #1377 from docker/pull_deps

introduce pull --include-deps
This commit is contained in:
Nicolas De loof 2021-03-02 15:51:38 +01:00 committed by GitHub
commit 0037e0755f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 96 additions and 68 deletions

View File

@ -85,6 +85,8 @@ type CreateOptions struct {
RecreateDependencies string RecreateDependencies string
// Inherit reuse anonymous volumes from previous container // Inherit reuse anonymous volumes from previous container
Inherit bool Inherit bool
// Timeout set delay to wait for container to gracelfuly stop before sending SIGKILL
Timeout *time.Duration
} }
// StartOptions group options of the Start API // StartOptions group options of the Start API

View File

@ -28,7 +28,8 @@ import (
type pullOptions struct { type pullOptions struct {
*projectOptions *projectOptions
composeOptions composeOptions
quiet bool quiet bool
includeDeps bool
} }
func pullCommand(p *projectOptions) *cobra.Command { func pullCommand(p *projectOptions) *cobra.Command {
@ -43,6 +44,7 @@ func pullCommand(p *projectOptions) *cobra.Command {
}, },
} }
cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Pull without printing progress information") cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Pull without printing progress information")
cmd.Flags().BoolVar(&opts.includeDeps, "include-deps", false, "Also pull services declared as dependencies")
return cmd return cmd
} }
@ -57,6 +59,19 @@ func runPull(ctx context.Context, opts pullOptions, services []string) error {
return err return err
} }
if !opts.includeDeps {
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.quiet { if opts.quiet {
return c.ComposeService().Pull(ctx, project) return c.ComposeService().Pull(ctx, project)
} }

View File

@ -93,7 +93,11 @@ func runRun(ctx context.Context, opts runOptions) error {
if err != nil { if err != nil {
return err return err
} }
project.DisabledServices = append(project.DisabledServices, project.Services...) for _, s := range project.Services {
if s.Name != opts.Service {
project.DisabledServices = append(project.DisabledServices, s)
}
}
project.Services = types.Services{enabled} project.Services = types.Services{enabled}
} }

View File

@ -27,17 +27,17 @@ import (
"syscall" "syscall"
"time" "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/client"
"github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/api/compose"
"github.com/docker/compose-cli/api/context/store" "github.com/docker/compose-cli/api/context/store"
"github.com/docker/compose-cli/api/progress" "github.com/docker/compose-cli/api/progress"
"github.com/docker/compose-cli/cli/cmd" "github.com/docker/compose-cli/cli/cmd"
"github.com/docker/compose-cli/cli/formatter" "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 // composeOptions hold options common to `up` and `run` to run compose project
@ -69,26 +69,74 @@ type upOptions struct {
noInherit bool noInherit bool
} }
func (o upOptions) recreateStrategy() string { func (opts upOptions) recreateStrategy() string {
if o.noRecreate { if opts.noRecreate {
return compose.RecreateNever return compose.RecreateNever
} }
if o.forceRecreate { if opts.forceRecreate {
return compose.RecreateForce return compose.RecreateForce
} }
return compose.RecreateDiverged return compose.RecreateDiverged
} }
func (o upOptions) dependenciesRecreateStrategy() string { func (opts upOptions) dependenciesRecreateStrategy() string {
if o.noRecreate { if opts.noRecreate {
return compose.RecreateNever return compose.RecreateNever
} }
if o.recreateDeps { if opts.recreateDeps {
return compose.RecreateForce return compose.RecreateForce
} }
return compose.RecreateDiverged 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 { func upCommand(p *projectOptions, contextType string) *cobra.Command {
opts := upOptions{ opts := upOptions{
composeOptions: &composeOptions{ composeOptions: &composeOptions{
@ -157,7 +205,7 @@ func runUp(ctx context.Context, opts upOptions, services []string) error {
return err return err
} }
err = applyScaleOpt(opts.scale, project) err = opts.apply(project, services)
if err != nil { if err != nil {
return err return err
} }
@ -176,35 +224,11 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
return err return err
} }
if opts.noDeps { err = opts.apply(project, services)
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)
if err != nil { if err != nil {
return err 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 = progress.Run(ctx, func(ctx context.Context) (string, error) {
err := c.ComposeService().Create(ctx, project, compose.CreateOptions{ err := c.ComposeService().Create(ctx, project, compose.CreateOptions{
Services: services, Services: services,
@ -212,6 +236,7 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
Recreate: opts.recreateStrategy(), Recreate: opts.recreateStrategy(),
RecreateDependencies: opts.dependenciesRecreateStrategy(), RecreateDependencies: opts.dependenciesRecreateStrategy(),
Inherit: !opts.noInherit, Inherit: !opts.noInherit,
Timeout: opts.GetTimeout(),
}) })
if err != nil { if err != nil {
return "", err return "", err
@ -282,25 +307,6 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
return err 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 { func setServiceScale(project *types.Project, name string, replicas int) error {
for i, s := range project.Services { for i, s := range project.Services {
if s.Name == name { if s.Name == name {

View File

@ -34,7 +34,8 @@ func TestApplyScaleOpt(t *testing.T) {
}, },
}, },
} }
err := applyScaleOpt([]string{"foo=2"}, &p) opt := upOptions{scale: []string{"foo=2"}}
err := opt.apply(&p, nil)
assert.NilError(t, err) assert.NilError(t, err)
foo, err := p.GetService("foo") foo, err := p.GetService("foo")
assert.NilError(t, err) assert.NilError(t, err)

View File

@ -42,7 +42,7 @@ const (
"Remove the custom name to scale the service.\n" "Remove the custom name to scale the service.\n"
) )
func (s *composeService) ensureScale(ctx context.Context, project *types.Project, service types.ServiceConfig) (*errgroup.Group, []moby.Container, error) { func (s *composeService) ensureScale(ctx context.Context, project *types.Project, service types.ServiceConfig, timeout *time.Duration) (*errgroup.Group, []moby.Container, error) {
cState, err := GetContextContainerState(ctx) cState, err := GetContextContainerState(ctx)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -73,7 +73,7 @@ func (s *composeService) ensureScale(ctx context.Context, project *types.Project
for i := scale; i < len(actual); i++ { for i := scale; i < len(actual); i++ {
container := actual[i] container := actual[i]
eg.Go(func() error { eg.Go(func() error {
err := s.apiClient.ContainerStop(ctx, container.ID, nil) err := s.apiClient.ContainerStop(ctx, container.ID, timeout)
if err != nil { if err != nil {
return err return err
} }
@ -85,8 +85,8 @@ func (s *composeService) ensureScale(ctx context.Context, project *types.Project
return eg, actual, nil return eg, actual, nil
} }
func (s *composeService) ensureService(ctx context.Context, project *types.Project, service types.ServiceConfig, recreate string, inherit bool) error { func (s *composeService) ensureService(ctx context.Context, project *types.Project, service types.ServiceConfig, recreate string, inherit bool, timeout *time.Duration) error {
eg, actual, err := s.ensureScale(ctx, project, service) eg, actual, err := s.ensureScale(ctx, project, service, timeout)
if err != nil { if err != nil {
return err return err
} }
@ -106,7 +106,7 @@ func (s *composeService) ensureService(ctx context.Context, project *types.Proje
diverged := container.Labels[configHashLabel] != expected diverged := container.Labels[configHashLabel] != expected
if diverged || recreate == compose.RecreateForce || service.Extensions[extLifecycle] == forceRecreate { if diverged || recreate == compose.RecreateForce || service.Extensions[extLifecycle] == forceRecreate {
eg.Go(func() error { eg.Go(func() error {
return s.recreateContainer(ctx, project, service, container, inherit) return s.recreateContainer(ctx, project, service, container, inherit, timeout)
}) })
continue continue
} }
@ -209,10 +209,10 @@ func (s *composeService) createContainer(ctx context.Context, project *types.Pro
return nil return nil
} }
func (s *composeService) recreateContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, container moby.Container, inherit bool) error { func (s *composeService) recreateContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, container moby.Container, inherit bool, timeout *time.Duration) error {
w := progress.ContextWriter(ctx) w := progress.ContextWriter(ctx)
w.Event(progress.NewEvent(getContainerProgressName(container), progress.Working, "Recreate")) w.Event(progress.NewEvent(getContainerProgressName(container), progress.Working, "Recreate"))
err := s.apiClient.ContainerStop(ctx, container.ID, nil) err := s.apiClient.ContainerStop(ctx, container.ID, timeout)
if err != nil { if err != nil {
return err return err
} }

View File

@ -102,9 +102,9 @@ func (s *composeService) Create(ctx context.Context, project *types.Project, opt
return InDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error { return InDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error {
if contains(opts.Services, service.Name) { if contains(opts.Services, service.Name) {
return s.ensureService(c, project, service, opts.Recreate, opts.Inherit) return s.ensureService(c, project, service, opts.Recreate, opts.Inherit, opts.Timeout)
} }
return s.ensureService(c, project, service, opts.RecreateDependencies, opts.Inherit) return s.ensureService(c, project, service, opts.RecreateDependencies, opts.Inherit, opts.Timeout)
}) })
} }