Signed-off-by: Mehrad Dadar <mehrad.dadar@gmail.com>
This commit is contained in:
Mehrad Dadar 2022-02-05 10:27:52 +03:30
parent 5262d3bbf5
commit 65ed8cf4c2
13 changed files with 83 additions and 58 deletions

View File

@ -65,7 +65,7 @@ func runRemove(ctx context.Context, backend api.Service, opts removeOptions, ser
} }
if opts.stop { if opts.stop {
err := backend.Stop(ctx, project, api.StopOptions{ err := backend.Stop(ctx, project.Name, api.StopOptions{
Services: services, Services: services,
}) })
if err != nil { if err != nil {

View File

@ -49,13 +49,13 @@ func restartCommand(p *projectOptions, backend api.Service) *cobra.Command {
} }
func runRestart(ctx context.Context, backend api.Service, opts restartOptions, services []string) error { func runRestart(ctx context.Context, backend api.Service, opts restartOptions, services []string) error {
project, err := opts.toProject(services) projectName, err := opts.toProjectName()
if err != nil { if err != nil {
return err return err
} }
timeout := time.Duration(opts.timeout) * time.Second timeout := time.Duration(opts.timeout) * time.Second
return backend.Restart(ctx, project, api.RestartOptions{ return backend.Restart(ctx, projectName, api.RestartOptions{
Timeout: &timeout, Timeout: &timeout,
Services: services, Services: services,
}) })

View File

@ -240,5 +240,5 @@ func startDependencies(ctx context.Context, backend api.Service, project types.P
if err := backend.Create(ctx, &project, api.CreateOptions{}); err != nil { if err := backend.Create(ctx, &project, api.CreateOptions{}); err != nil {
return err return err
} }
return backend.Start(ctx, &project, api.StartOptions{}) return backend.Start(ctx, project.Name, api.StartOptions{})
} }

View File

@ -43,10 +43,12 @@ func startCommand(p *projectOptions, backend api.Service) *cobra.Command {
} }
func runStart(ctx context.Context, backend api.Service, opts startOptions, services []string) error { func runStart(ctx context.Context, backend api.Service, opts startOptions, services []string) error {
project, err := opts.toProject(services) projectName, err := opts.toProjectName()
if err != nil { if err != nil {
return err return err
} }
return backend.Start(ctx, project, api.StartOptions{}) return backend.Start(ctx, projectName, api.StartOptions{
AttachTo: services,
})
} }

View File

@ -53,7 +53,7 @@ func stopCommand(p *projectOptions, backend api.Service) *cobra.Command {
} }
func runStop(ctx context.Context, backend api.Service, opts stopOptions, services []string) error { func runStop(ctx context.Context, backend api.Service, opts stopOptions, services []string) error {
project, err := opts.toProject(services) projectName, err := opts.toProjectName()
if err != nil { if err != nil {
return err return err
} }
@ -63,7 +63,7 @@ func runStop(ctx context.Context, backend api.Service, opts stopOptions, service
timeoutValue := time.Duration(opts.timeout) * time.Second timeoutValue := time.Duration(opts.timeout) * time.Second
timeout = &timeoutValue timeout = &timeoutValue
} }
return backend.Stop(ctx, project, api.StopOptions{ return backend.Stop(ctx, projectName, api.StopOptions{
Timeout: timeout, Timeout: timeout,
Services: services, Services: services,
}) })

View File

@ -37,11 +37,11 @@ type Service interface {
// Create executes the equivalent to a `compose create` // Create executes the equivalent to a `compose create`
Create(ctx context.Context, project *types.Project, opts CreateOptions) error Create(ctx context.Context, project *types.Project, opts CreateOptions) error
// Start executes the equivalent to a `compose start` // Start executes the equivalent to a `compose start`
Start(ctx context.Context, project *types.Project, options StartOptions) error Start(ctx context.Context, projectName string, options StartOptions) error
// Restart restarts containers // Restart restarts containers
Restart(ctx context.Context, project *types.Project, options RestartOptions) error Restart(ctx context.Context, projectName string, options RestartOptions) error
// Stop executes the equivalent to a `compose stop` // Stop executes the equivalent to a `compose stop`
Stop(ctx context.Context, project *types.Project, options StopOptions) error Stop(ctx context.Context, projectName string, options StopOptions) error
// Up executes the equivalent to a `compose up` // Up executes the equivalent to a `compose up`
Up(ctx context.Context, project *types.Project, options UpOptions) error Up(ctx context.Context, project *types.Project, options UpOptions) error
// Down executes the equivalent to a `compose down` // Down executes the equivalent to a `compose down`

View File

@ -28,9 +28,9 @@ type ServiceProxy struct {
PushFn func(ctx context.Context, project *types.Project, options PushOptions) error PushFn func(ctx context.Context, project *types.Project, options PushOptions) error
PullFn func(ctx context.Context, project *types.Project, opts PullOptions) error PullFn func(ctx context.Context, project *types.Project, opts PullOptions) error
CreateFn func(ctx context.Context, project *types.Project, opts CreateOptions) error CreateFn func(ctx context.Context, project *types.Project, opts CreateOptions) error
StartFn func(ctx context.Context, project *types.Project, options StartOptions) error StartFn func(ctx context.Context, projectName string, options StartOptions) error
RestartFn func(ctx context.Context, project *types.Project, options RestartOptions) error RestartFn func(ctx context.Context, projectName string, options RestartOptions) error
StopFn func(ctx context.Context, project *types.Project, options StopOptions) error StopFn func(ctx context.Context, projectName string, options StopOptions) error
UpFn func(ctx context.Context, project *types.Project, options UpOptions) error UpFn func(ctx context.Context, project *types.Project, options UpOptions) error
DownFn func(ctx context.Context, projectName string, options DownOptions) error DownFn func(ctx context.Context, projectName string, options DownOptions) error
LogsFn func(ctx context.Context, projectName string, consumer LogConsumer, options LogOptions) error LogsFn func(ctx context.Context, projectName string, consumer LogConsumer, options LogOptions) error
@ -141,36 +141,27 @@ func (s *ServiceProxy) Create(ctx context.Context, project *types.Project, optio
} }
// Start implements Service interface // Start implements Service interface
func (s *ServiceProxy) Start(ctx context.Context, project *types.Project, options StartOptions) error { func (s *ServiceProxy) Start(ctx context.Context, projectName string, options StartOptions) error {
if s.StartFn == nil { if s.StartFn == nil {
return ErrNotImplemented return ErrNotImplemented
} }
for _, i := range s.interceptors { return s.StartFn(ctx, projectName, options)
i(ctx, project)
}
return s.StartFn(ctx, project, options)
} }
// Restart implements Service interface // Restart implements Service interface
func (s *ServiceProxy) Restart(ctx context.Context, project *types.Project, options RestartOptions) error { func (s *ServiceProxy) Restart(ctx context.Context, projectName string, options RestartOptions) error {
if s.RestartFn == nil { if s.RestartFn == nil {
return ErrNotImplemented return ErrNotImplemented
} }
for _, i := range s.interceptors { return s.RestartFn(ctx, projectName, options)
i(ctx, project)
}
return s.RestartFn(ctx, project, options)
} }
// Stop implements Service interface // Stop implements Service interface
func (s *ServiceProxy) Stop(ctx context.Context, project *types.Project, options StopOptions) error { func (s *ServiceProxy) Stop(ctx context.Context, projectName string, options StopOptions) error {
if s.StopFn == nil { if s.StopFn == nil {
return ErrNotImplemented return ErrNotImplemented
} }
for _, i := range s.interceptors { return s.StopFn(ctx, projectName, options)
i(ctx, project)
}
return s.StopFn(ctx, project, options)
} }
// Up implements Service interface // Up implements Service interface

View File

@ -92,3 +92,34 @@ func escapeDollarSign(marshal []byte) []byte {
escDollar := []byte{'$', '$'} escDollar := []byte{'$', '$'}
return bytes.ReplaceAll(marshal, dollar, escDollar) return bytes.ReplaceAll(marshal, dollar, escDollar)
} }
// projectFromName builds a types.Project based on actual resources with compose labels set
func (s *composeService) projectFromName(containers Containers, projectName string) *types.Project {
project := &types.Project{
Name: projectName,
}
if len(containers) == 0 {
return project
}
set := map[string]moby.Container{}
for _, c := range containers {
set[c.Labels[api.ServiceLabel]] = c
}
for s, c := range set {
service := types.ServiceConfig{
Name: s,
Image: c.Image,
Labels: c.Labels,
}
dependencies := c.Labels[api.DependenciesLabel]
if len(dependencies) > 0 {
service.DependsOn = types.DependsOnConfig{}
for _, d := range strings.Split(dependencies, ",") {
service.DependsOn[d] = types.ServiceDependency{}
}
}
project.Services = append(project.Services, service)
}
return project
}

View File

@ -19,7 +19,6 @@ package compose
import ( import (
"context" "context"
"github.com/compose-spec/compose-go/types"
"github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/api"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
@ -27,18 +26,21 @@ import (
"github.com/docker/compose/v2/pkg/utils" "github.com/docker/compose/v2/pkg/utils"
) )
func (s *composeService) Restart(ctx context.Context, project *types.Project, options api.RestartOptions) error { func (s *composeService) Restart(ctx context.Context, projectName string, options api.RestartOptions) error {
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.restart(ctx, project, options) return s.restart(ctx, projectName, options)
}) })
} }
func (s *composeService) restart(ctx context.Context, project *types.Project, options api.RestartOptions) error { func (s *composeService) restart(ctx context.Context, projectName string, options api.RestartOptions) error {
observedState, err := s.getContainers(ctx, project.Name, oneOffInclude, true)
observedState, err := s.getContainers(ctx, projectName, oneOffInclude, true)
if err != nil { if err != nil {
return err return err
} }
project := s.projectFromName(observedState, projectName)
if len(options.Services) == 0 { if len(options.Services) == 0 {
options.Services = project.ServiceNames() options.Services = project.ServiceNames()
} }

View File

@ -28,17 +28,21 @@ import (
"github.com/docker/compose/v2/pkg/progress" "github.com/docker/compose/v2/pkg/progress"
) )
func (s *composeService) Start(ctx context.Context, project *types.Project, options api.StartOptions) error { func (s *composeService) Start(ctx context.Context, projectName string, options api.StartOptions) error {
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.start(ctx, project, options, nil) return s.start(ctx, projectName, options, nil)
}) })
} }
func (s *composeService) start(ctx context.Context, project *types.Project, options api.StartOptions, listener api.ContainerEventListener) error { func (s *composeService) start(ctx context.Context, projectName string, options api.StartOptions, listener api.ContainerEventListener) error {
if len(options.AttachTo) == 0 { var containers Containers
options.AttachTo = project.ServiceNames() containers, err := s.getContainers(ctx, projectName, oneOffInclude, true, options.AttachTo...)
if err != nil {
return err
} }
project := s.projectFromName(containers, projectName)
eg, ctx := errgroup.WithContext(ctx) eg, ctx := errgroup.WithContext(ctx)
if listener != nil { if listener != nil {
attached, err := s.attach(ctx, project, listener, options.AttachTo) attached, err := s.attach(ctx, project, listener, options.AttachTo)
@ -53,7 +57,7 @@ func (s *composeService) start(ctx context.Context, project *types.Project, opti
}) })
} }
err := InDependencyOrder(ctx, project, func(c context.Context, name string) error { err = InDependencyOrder(ctx, project, func(c context.Context, name string) error {
service, err := project.GetService(name) service, err := project.GetService(name)
if err != nil { if err != nil {
return err return err

View File

@ -21,29 +21,31 @@ import (
"github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/progress" "github.com/docker/compose/v2/pkg/progress"
//"github.com/compose-spec/compose-go/types"
"github.com/compose-spec/compose-go/types"
) )
func (s *composeService) Stop(ctx context.Context, project *types.Project, options api.StopOptions) error { func (s *composeService) Stop(ctx context.Context, projectName string, options api.StopOptions) error {
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.stop(ctx, project, options) return s.stop(ctx, projectName, options)
}) })
} }
func (s *composeService) stop(ctx context.Context, project *types.Project, options api.StopOptions) error { func (s *composeService) stop(ctx context.Context, projectName string, options api.StopOptions) error {
w := progress.ContextWriter(ctx) w := progress.ContextWriter(ctx)
services := options.Services services := options.Services
if len(services) == 0 { if len(services) == 0 {
services = project.ServiceNames() services = []string{}
} }
var containers Containers var containers Containers
containers, err := s.getContainers(ctx, project.Name, oneOffInclude, true, services...) containers, err := s.getContainers(ctx, projectName, oneOffInclude, true, services...)
if err != nil { if err != nil {
return err return err
} }
project := s.projectFromName(containers, projectName)
return InReverseDependencyOrder(ctx, project, func(c context.Context, service string) error { return InReverseDependencyOrder(ctx, project, func(c context.Context, service string) error {
return s.stopContainers(ctx, w, containers.filter(isService(service)), options.Timeout) return s.stopContainers(ctx, w, containers.filter(isService(service)), options.Timeout)
}) })

View File

@ -25,7 +25,6 @@ import (
compose "github.com/docker/compose/v2/pkg/api" compose "github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/mocks" "github.com/docker/compose/v2/pkg/mocks"
"github.com/compose-spec/compose-go/types"
moby "github.com/docker/docker/api/types" moby "github.com/docker/docker/api/types"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
@ -50,13 +49,7 @@ func TestStopTimeout(t *testing.T) {
api.EXPECT().ContainerStop(gomock.Any(), "456", &timeout).Return(nil) api.EXPECT().ContainerStop(gomock.Any(), "456", &timeout).Return(nil)
api.EXPECT().ContainerStop(gomock.Any(), "789", &timeout).Return(nil) api.EXPECT().ContainerStop(gomock.Any(), "789", &timeout).Return(nil)
err := tested.Stop(ctx, &types.Project{ err := tested.Stop(ctx, strings.ToLower(testProject), compose.StopOptions{
Name: strings.ToLower(testProject),
Services: []types.ServiceConfig{
{Name: "service1"},
{Name: "service2"},
},
}, compose.StopOptions{
Timeout: &timeout, Timeout: &timeout,
}) })
assert.NilError(t, err) assert.NilError(t, err)

View File

@ -38,7 +38,7 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
return err return err
} }
if options.Start.Attach == nil { if options.Start.Attach == nil {
return s.start(ctx, project, options.Start, nil) return s.start(ctx, project.Name, options.Start, nil)
} }
return nil return nil
}) })
@ -65,7 +65,7 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
}) })
}() }()
return s.Stop(ctx, project, api.StopOptions{ return s.Stop(ctx, project.Name, api.StopOptions{
Services: options.Create.Services, Services: options.Create.Services,
}) })
}) })
@ -85,7 +85,7 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
return err return err
}) })
err = s.start(ctx, project, options.Start, printer.HandleEvent) err = s.start(ctx, project.Name, options.Start, printer.HandleEvent)
if err != nil { if err != nil {
return err return err
} }