mirror of
https://github.com/docker/compose.git
synced 2025-07-23 05:34:36 +02:00
Merge pull request #1377 from docker/pull_deps
introduce pull --include-deps
This commit is contained in:
commit
0037e0755f
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user