Browse Source

introduce ServiceProxy for backend lazy initialization

Signed-off-by: Nicolas De Loof <[email protected]>
Nicolas De Loof 4 years ago
parent
commit
62af4e0cc7
4 changed files with 336 additions and 301 deletions
  1. 0 148
      api/compose/delegator.go
  2. 0 148
      api/compose/noimpl.go
  3. 333 0
      api/compose/proxy.go
  4. 3 5
      main.go

+ 0 - 148
api/compose/delegator.go

@@ -1,148 +0,0 @@
-/*
-   Copyright 2020 Docker Compose CLI authors
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package compose
-
-import (
-	"context"
-
-	"github.com/compose-spec/compose-go/types"
-)
-
-// ServiceDelegator implements Service by delegating to another implementation. This allows lazy init
-type ServiceDelegator struct {
-	Delegate Service
-}
-
-//Build implements Service interface
-func (s *ServiceDelegator) Build(ctx context.Context, project *types.Project, options BuildOptions) error {
-	return s.Delegate.Build(ctx, project, options)
-}
-
-//Push implements Service interface
-func (s *ServiceDelegator) Push(ctx context.Context, project *types.Project, options PushOptions) error {
-	return s.Delegate.Push(ctx, project, options)
-}
-
-//Pull implements Service interface
-func (s *ServiceDelegator) Pull(ctx context.Context, project *types.Project, options PullOptions) error {
-	return s.Delegate.Pull(ctx, project, options)
-}
-
-//Create implements Service interface
-func (s *ServiceDelegator) Create(ctx context.Context, project *types.Project, options CreateOptions) error {
-	return s.Delegate.Create(ctx, project, options)
-}
-
-//Start implements Service interface
-func (s *ServiceDelegator) Start(ctx context.Context, project *types.Project, options StartOptions) error {
-	return s.Delegate.Start(ctx, project, options)
-}
-
-//Restart implements Service interface
-func (s *ServiceDelegator) Restart(ctx context.Context, project *types.Project, options RestartOptions) error {
-	return s.Delegate.Restart(ctx, project, options)
-}
-
-//Stop implements Service interface
-func (s *ServiceDelegator) Stop(ctx context.Context, project *types.Project, options StopOptions) error {
-	return s.Delegate.Stop(ctx, project, options)
-}
-
-//Up implements Service interface
-func (s *ServiceDelegator) Up(ctx context.Context, project *types.Project, options UpOptions) error {
-	return s.Delegate.Up(ctx, project, options)
-}
-
-//Down implements Service interface
-func (s *ServiceDelegator) Down(ctx context.Context, project string, options DownOptions) error {
-	return s.Delegate.Down(ctx, project, options)
-}
-
-//Logs implements Service interface
-func (s *ServiceDelegator) Logs(ctx context.Context, project string, consumer LogConsumer, options LogOptions) error {
-	return s.Delegate.Logs(ctx, project, consumer, options)
-}
-
-//Ps implements Service interface
-func (s *ServiceDelegator) Ps(ctx context.Context, project string, options PsOptions) ([]ContainerSummary, error) {
-	return s.Delegate.Ps(ctx, project, options)
-}
-
-//List implements Service interface
-func (s *ServiceDelegator) List(ctx context.Context, options ListOptions) ([]Stack, error) {
-	return s.Delegate.List(ctx, options)
-}
-
-//Convert implements Service interface
-func (s *ServiceDelegator) Convert(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error) {
-	return s.Delegate.Convert(ctx, project, options)
-}
-
-//Kill implements Service interface
-func (s *ServiceDelegator) Kill(ctx context.Context, project *types.Project, options KillOptions) error {
-	return s.Delegate.Kill(ctx, project, options)
-}
-
-//RunOneOffContainer implements Service interface
-func (s *ServiceDelegator) RunOneOffContainer(ctx context.Context, project *types.Project, options RunOptions) (int, error) {
-	return s.Delegate.RunOneOffContainer(ctx, project, options)
-}
-
-//Remove implements Service interface
-func (s *ServiceDelegator) Remove(ctx context.Context, project *types.Project, options RemoveOptions) ([]string, error) {
-	return s.Delegate.Remove(ctx, project, options)
-}
-
-//Exec implements Service interface
-func (s *ServiceDelegator) Exec(ctx context.Context, project *types.Project, options RunOptions) (int, error) {
-	return s.Delegate.Exec(ctx, project, options)
-}
-
-//Copy implements Service interface
-func (s *ServiceDelegator) Copy(ctx context.Context, project *types.Project, options CopyOptions) error {
-	return s.Delegate.Copy(ctx, project, options)
-}
-
-//Pause implements Service interface
-func (s *ServiceDelegator) Pause(ctx context.Context, project string, options PauseOptions) error {
-	return s.Delegate.Pause(ctx, project, options)
-}
-
-//UnPause implements Service interface
-func (s *ServiceDelegator) UnPause(ctx context.Context, project string, options PauseOptions) error {
-	return s.Delegate.UnPause(ctx, project, options)
-}
-
-//Top implements Service interface
-func (s *ServiceDelegator) Top(ctx context.Context, project string, services []string) ([]ContainerProcSummary, error) {
-	return s.Delegate.Top(ctx, project, services)
-}
-
-//Events implements Service interface
-func (s *ServiceDelegator) Events(ctx context.Context, project string, options EventsOptions) error {
-	return s.Delegate.Events(ctx, project, options)
-}
-
-//Port implements Service interface
-func (s *ServiceDelegator) Port(ctx context.Context, project string, service string, port int, options PortOptions) (string, int, error) {
-	return s.Delegate.Port(ctx, project, service, port, options)
-}
-
-//Images implements Service interface
-func (s *ServiceDelegator) Images(ctx context.Context, project string, options ImagesOptions) ([]ImageSummary, error) {
-	return s.Delegate.Images(ctx, project, options)
-}

+ 0 - 148
api/compose/noimpl.go

@@ -1,148 +0,0 @@
-/*
-   Copyright 2020 Docker Compose CLI authors
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package compose
-
-import (
-	"context"
-
-	"github.com/compose-spec/compose-go/types"
-
-	"github.com/docker/compose-cli/api/errdefs"
-)
-
-// NoImpl implements Service to return ErrNotImplemented
-type NoImpl struct{}
-
-//Build implements Service interface
-func (s NoImpl) Build(ctx context.Context, project *types.Project, options BuildOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//Push implements Service interface
-func (s NoImpl) Push(ctx context.Context, project *types.Project, options PushOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//Pull implements Service interface
-func (s NoImpl) Pull(ctx context.Context, project *types.Project, options PullOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//Create implements Service interface
-func (s NoImpl) Create(ctx context.Context, project *types.Project, options CreateOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//Start implements Service interface
-func (s NoImpl) Start(ctx context.Context, project *types.Project, options StartOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//Restart implements Service interface
-func (s NoImpl) Restart(ctx context.Context, project *types.Project, options RestartOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//Stop implements Service interface
-func (s NoImpl) Stop(ctx context.Context, project *types.Project, options StopOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//Up implements Service interface
-func (s NoImpl) Up(ctx context.Context, project *types.Project, options UpOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//Down implements Service interface
-func (s NoImpl) Down(ctx context.Context, project string, options DownOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//Logs implements Service interface
-func (s NoImpl) Logs(ctx context.Context, project string, consumer LogConsumer, options LogOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//Ps implements Service interface
-func (s NoImpl) Ps(ctx context.Context, project string, options PsOptions) ([]ContainerSummary, error) {
-	return nil, errdefs.ErrNotImplemented
-}
-
-//List implements Service interface
-func (s NoImpl) List(ctx context.Context, options ListOptions) ([]Stack, error) {
-	return nil, errdefs.ErrNotImplemented
-}
-
-//Convert implements Service interface
-func (s NoImpl) Convert(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error) {
-	return nil, errdefs.ErrNotImplemented
-}
-
-//Kill implements Service interface
-func (s NoImpl) Kill(ctx context.Context, project *types.Project, options KillOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//RunOneOffContainer implements Service interface
-func (s NoImpl) RunOneOffContainer(ctx context.Context, project *types.Project, options RunOptions) (int, error) {
-	return 0, errdefs.ErrNotImplemented
-}
-
-//Remove implements Service interface
-func (s NoImpl) Remove(ctx context.Context, project *types.Project, options RemoveOptions) ([]string, error) {
-	return nil, errdefs.ErrNotImplemented
-}
-
-//Exec implements Service interface
-func (s NoImpl) Exec(ctx context.Context, project *types.Project, opts RunOptions) (int, error) {
-	return 0, errdefs.ErrNotImplemented
-}
-
-//Copy implements Service interface
-func (s NoImpl) Copy(ctx context.Context, project *types.Project, opts CopyOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//Pause implements Service interface
-func (s NoImpl) Pause(ctx context.Context, project string, options PauseOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//UnPause implements Service interface
-func (s NoImpl) UnPause(ctx context.Context, project string, options PauseOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//Top implements Service interface
-func (s NoImpl) Top(ctx context.Context, project string, services []string) ([]ContainerProcSummary, error) {
-	return nil, errdefs.ErrNotImplemented
-}
-
-//Events implements Service interface
-func (s NoImpl) Events(ctx context.Context, project string, options EventsOptions) error {
-	return errdefs.ErrNotImplemented
-}
-
-//Port implements Service interface
-func (s NoImpl) Port(ctx context.Context, project string, service string, port int, options PortOptions) (string, int, error) {
-	return "", 0, errdefs.ErrNotImplemented
-}
-
-//Images implements Service interface
-func (s NoImpl) Images(ctx context.Context, project string, options ImagesOptions) ([]ImageSummary, error) {
-	return nil, errdefs.ErrNotImplemented
-}

+ 333 - 0
api/compose/proxy.go

@@ -0,0 +1,333 @@
+/*
+   Copyright 2020 Docker Compose CLI authors
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package compose
+
+import (
+	"context"
+
+	"github.com/docker/compose-cli/api/errdefs"
+
+	"github.com/compose-spec/compose-go/types"
+)
+
+// ServiceProxy implements Service by delegating to implementation functions. This allows lazy init and per-method overrides
+type ServiceProxy struct {
+	BuildFn              func(ctx context.Context, project *types.Project, options BuildOptions) error
+	PushFn               func(ctx context.Context, project *types.Project, options PushOptions) error
+	PullFn               func(ctx context.Context, project *types.Project, opts PullOptions) error
+	CreateFn             func(ctx context.Context, project *types.Project, opts CreateOptions) error
+	StartFn              func(ctx context.Context, project *types.Project, options StartOptions) error
+	RestartFn            func(ctx context.Context, project *types.Project, options RestartOptions) error
+	StopFn               func(ctx context.Context, project *types.Project, options StopOptions) error
+	UpFn                 func(ctx context.Context, project *types.Project, options UpOptions) error
+	DownFn               func(ctx context.Context, projectName string, options DownOptions) error
+	LogsFn               func(ctx context.Context, projectName string, consumer LogConsumer, options LogOptions) error
+	PsFn                 func(ctx context.Context, projectName string, options PsOptions) ([]ContainerSummary, error)
+	ListFn               func(ctx context.Context, options ListOptions) ([]Stack, error)
+	ConvertFn            func(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error)
+	KillFn               func(ctx context.Context, project *types.Project, options KillOptions) error
+	RunOneOffContainerFn func(ctx context.Context, project *types.Project, opts RunOptions) (int, error)
+	RemoveFn             func(ctx context.Context, project *types.Project, options RemoveOptions) ([]string, error)
+	ExecFn               func(ctx context.Context, project *types.Project, opts RunOptions) (int, error)
+	CopyFn               func(ctx context.Context, project *types.Project, opts CopyOptions) error
+	PauseFn              func(ctx context.Context, project string, options PauseOptions) error
+	UnPauseFn            func(ctx context.Context, project string, options PauseOptions) error
+	TopFn                func(ctx context.Context, projectName string, services []string) ([]ContainerProcSummary, error)
+	EventsFn             func(ctx context.Context, project string, options EventsOptions) error
+	PortFn               func(ctx context.Context, project string, service string, port int, options PortOptions) (string, int, error)
+	ImagesFn             func(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error)
+	interceptors         []Interceptor
+}
+
+// NewServiceProxy produces a ServiceProxy
+func NewServiceProxy() *ServiceProxy {
+	return &ServiceProxy{}
+}
+
+// Interceptor allow to customize the compose types.Project before the actual Service method is executed
+type Interceptor func(ctx context.Context, project *types.Project)
+
+var _ Service = &ServiceProxy{}
+
+// WithService configure proxy to use specified Service as delegate
+func (s *ServiceProxy) WithService(service Service) *ServiceProxy {
+	s.BuildFn = service.Build
+	s.PushFn = service.Push
+	s.PullFn = service.Pull
+	s.CreateFn = service.Create
+	s.StartFn = service.Start
+	s.RestartFn = service.Restart
+	s.StopFn = service.Stop
+	s.UpFn = service.Up
+	s.DownFn = service.Down
+	s.LogsFn = service.Logs
+	s.PsFn = service.Ps
+	s.ListFn = service.List
+	s.ConvertFn = service.Convert
+	s.KillFn = service.Kill
+	s.RunOneOffContainerFn = service.RunOneOffContainer
+	s.RemoveFn = service.Remove
+	s.ExecFn = service.Exec
+	s.CopyFn = service.Copy
+	s.PauseFn = service.Pause
+	s.UnPauseFn = service.UnPause
+	s.TopFn = service.Top
+	s.EventsFn = service.Events
+	s.PortFn = service.Port
+	s.ImagesFn = service.Images
+	return s
+}
+
+// WithInterceptor configures Interceptor to be applied to Service method execution
+func (s *ServiceProxy) WithInterceptor(interceptors ...Interceptor) *ServiceProxy {
+	s.interceptors = append(s.interceptors, interceptors...)
+	return s
+}
+
+//Build implements Service interface
+func (s *ServiceProxy) Build(ctx context.Context, project *types.Project, options BuildOptions) error {
+	if s.BuildFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	for _, i := range s.interceptors {
+		i(ctx, project)
+	}
+	return s.BuildFn(ctx, project, options)
+}
+
+//Push implements Service interface
+func (s *ServiceProxy) Push(ctx context.Context, project *types.Project, options PushOptions) error {
+	if s.PushFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	for _, i := range s.interceptors {
+		i(ctx, project)
+	}
+	return s.PushFn(ctx, project, options)
+}
+
+//Pull implements Service interface
+func (s *ServiceProxy) Pull(ctx context.Context, project *types.Project, options PullOptions) error {
+	if s.PullFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	for _, i := range s.interceptors {
+		i(ctx, project)
+	}
+	return s.PullFn(ctx, project, options)
+}
+
+//Create implements Service interface
+func (s *ServiceProxy) Create(ctx context.Context, project *types.Project, options CreateOptions) error {
+	if s.CreateFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	for _, i := range s.interceptors {
+		i(ctx, project)
+	}
+	return s.CreateFn(ctx, project, options)
+}
+
+//Start implements Service interface
+func (s *ServiceProxy) Start(ctx context.Context, project *types.Project, options StartOptions) error {
+	if s.StartFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	for _, i := range s.interceptors {
+		i(ctx, project)
+	}
+	return s.StartFn(ctx, project, options)
+}
+
+//Restart implements Service interface
+func (s *ServiceProxy) Restart(ctx context.Context, project *types.Project, options RestartOptions) error {
+	if s.RestartFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	for _, i := range s.interceptors {
+		i(ctx, project)
+	}
+	return s.RestartFn(ctx, project, options)
+}
+
+//Stop implements Service interface
+func (s *ServiceProxy) Stop(ctx context.Context, project *types.Project, options StopOptions) error {
+	if s.StopFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	for _, i := range s.interceptors {
+		i(ctx, project)
+	}
+	return s.StopFn(ctx, project, options)
+}
+
+//Up implements Service interface
+func (s *ServiceProxy) Up(ctx context.Context, project *types.Project, options UpOptions) error {
+	if s.UpFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	for _, i := range s.interceptors {
+		i(ctx, project)
+	}
+	return s.UpFn(ctx, project, options)
+}
+
+//Down implements Service interface
+func (s *ServiceProxy) Down(ctx context.Context, project string, options DownOptions) error {
+	if s.DownFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	return s.DownFn(ctx, project, options)
+}
+
+//Logs implements Service interface
+func (s *ServiceProxy) Logs(ctx context.Context, project string, consumer LogConsumer, options LogOptions) error {
+	if s.LogsFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	return s.LogsFn(ctx, project, consumer, options)
+}
+
+//Ps implements Service interface
+func (s *ServiceProxy) Ps(ctx context.Context, project string, options PsOptions) ([]ContainerSummary, error) {
+	if s.PsFn == nil {
+		return nil, errdefs.ErrNotImplemented
+	}
+	return s.PsFn(ctx, project, options)
+}
+
+//List implements Service interface
+func (s *ServiceProxy) List(ctx context.Context, options ListOptions) ([]Stack, error) {
+	if s.ListFn == nil {
+		return nil, errdefs.ErrNotImplemented
+	}
+	return s.ListFn(ctx, options)
+}
+
+//Convert implements Service interface
+func (s *ServiceProxy) Convert(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error) {
+	if s.ConvertFn == nil {
+		return nil, errdefs.ErrNotImplemented
+	}
+	for _, i := range s.interceptors {
+		i(ctx, project)
+	}
+	return s.ConvertFn(ctx, project, options)
+}
+
+//Kill implements Service interface
+func (s *ServiceProxy) Kill(ctx context.Context, project *types.Project, options KillOptions) error {
+	if s.KillFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	for _, i := range s.interceptors {
+		i(ctx, project)
+	}
+	return s.KillFn(ctx, project, options)
+}
+
+//RunOneOffContainer implements Service interface
+func (s *ServiceProxy) RunOneOffContainer(ctx context.Context, project *types.Project, options RunOptions) (int, error) {
+	if s.RunOneOffContainerFn == nil {
+		return 0, errdefs.ErrNotImplemented
+	}
+	for _, i := range s.interceptors {
+		i(ctx, project)
+	}
+	return s.RunOneOffContainerFn(ctx, project, options)
+}
+
+//Remove implements Service interface
+func (s *ServiceProxy) Remove(ctx context.Context, project *types.Project, options RemoveOptions) ([]string, error) {
+	if s.RemoveFn == nil {
+		return nil, errdefs.ErrNotImplemented
+	}
+	for _, i := range s.interceptors {
+		i(ctx, project)
+	}
+	return s.RemoveFn(ctx, project, options)
+}
+
+//Exec implements Service interface
+func (s *ServiceProxy) Exec(ctx context.Context, project *types.Project, options RunOptions) (int, error) {
+	if s.ExecFn == nil {
+		return 0, errdefs.ErrNotImplemented
+	}
+	for _, i := range s.interceptors {
+		i(ctx, project)
+	}
+	return s.ExecFn(ctx, project, options)
+}
+
+//Copy implements Service interface
+func (s *ServiceProxy) Copy(ctx context.Context, project *types.Project, options CopyOptions) error {
+	if s.CopyFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	for _, i := range s.interceptors {
+		i(ctx, project)
+	}
+	return s.CopyFn(ctx, project, options)
+}
+
+//Pause implements Service interface
+func (s *ServiceProxy) Pause(ctx context.Context, project string, options PauseOptions) error {
+	if s.PauseFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	return s.PauseFn(ctx, project, options)
+}
+
+//UnPause implements Service interface
+func (s *ServiceProxy) UnPause(ctx context.Context, project string, options PauseOptions) error {
+	if s.UnPauseFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	return s.UnPauseFn(ctx, project, options)
+}
+
+//Top implements Service interface
+func (s *ServiceProxy) Top(ctx context.Context, project string, services []string) ([]ContainerProcSummary, error) {
+	if s.TopFn == nil {
+		return nil, errdefs.ErrNotImplemented
+	}
+	return s.TopFn(ctx, project, services)
+}
+
+//Events implements Service interface
+func (s *ServiceProxy) Events(ctx context.Context, project string, options EventsOptions) error {
+	if s.EventsFn == nil {
+		return errdefs.ErrNotImplemented
+	}
+	return s.EventsFn(ctx, project, options)
+}
+
+//Port implements Service interface
+func (s *ServiceProxy) Port(ctx context.Context, project string, service string, port int, options PortOptions) (string, int, error) {
+	if s.PortFn == nil {
+		return "", 0, errdefs.ErrNotImplemented
+	}
+	return s.PortFn(ctx, project, service, port, options)
+}
+
+//Images implements Service interface
+func (s *ServiceProxy) Images(ctx context.Context, project string, options ImagesOptions) ([]ImageSummary, error) {
+	if s.ImagesFn == nil {
+		return nil, errdefs.ErrNotImplemented
+	}
+	return s.ImagesFn(ctx, project, options)
+}

+ 3 - 5
main.go

@@ -35,16 +35,14 @@ import (
 
 func main() {
 	plugin.Run(func(dockerCli command.Cli) *cobra.Command {
-		lazyInit := api.ServiceDelegator{
-			Delegate: api.NoImpl{},
-		}
-		cmd := compose.RootCommand(store.DefaultContextType, &lazyInit)
+		lazyInit := api.NewServiceProxy()
+		cmd := compose.RootCommand(store.DefaultContextType, lazyInit)
 		originalPreRun := cmd.PersistentPreRunE
 		cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
 			if err := plugin.PersistentPreRunE(cmd, args); err != nil {
 				return err
 			}
-			lazyInit.Delegate = impl.NewComposeService(dockerCli.Client(), dockerCli.ConfigFile())
+			lazyInit.WithService(impl.NewComposeService(dockerCli.Client(), dockerCli.ConfigFile()))
 			if originalPreRun != nil {
 				return originalPreRun(cmd, args)
 			}