1/* 2 Copyright 2020 Docker Compose CLI authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15*/ 16 17package api 18 19import ( 20 "context" 21 22 "github.com/compose-spec/compose-go/types" 23) 24 25// ServiceProxy implements Service by delegating to implementation functions. This allows lazy init and per-method overrides 26type ServiceProxy struct { 27 BuildFn func(ctx context.Context, project *types.Project, options BuildOptions) error 28 PushFn func(ctx context.Context, project *types.Project, options PushOptions) error 29 PullFn func(ctx context.Context, project *types.Project, opts PullOptions) error 30 CreateFn func(ctx context.Context, project *types.Project, opts CreateOptions) error 31 StartFn func(ctx context.Context, project *types.Project, options StartOptions) error 32 RestartFn func(ctx context.Context, project *types.Project, options RestartOptions) error 33 StopFn func(ctx context.Context, project *types.Project, options StopOptions) error 34 UpFn func(ctx context.Context, project *types.Project, options UpOptions) error 35 DownFn func(ctx context.Context, projectName string, options DownOptions) error 36 LogsFn func(ctx context.Context, projectName string, consumer LogConsumer, options LogOptions) error 37 PsFn func(ctx context.Context, projectName string, options PsOptions) ([]ContainerSummary, error) 38 ListFn func(ctx context.Context, options ListOptions) ([]Stack, error) 39 ConvertFn func(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error) 40 KillFn func(ctx context.Context, project *types.Project, options KillOptions) error 41 RunOneOffContainerFn func(ctx context.Context, project *types.Project, opts RunOptions) (int, error) 42 RemoveFn func(ctx context.Context, project *types.Project, options RemoveOptions) error 43 ExecFn func(ctx context.Context, project string, opts RunOptions) (int, error) 44 CopyFn func(ctx context.Context, project *types.Project, opts CopyOptions) error 45 PauseFn func(ctx context.Context, project string, options PauseOptions) error 46 UnPauseFn func(ctx context.Context, project string, options PauseOptions) error 47 TopFn func(ctx context.Context, projectName string, services []string) ([]ContainerProcSummary, error) 48 EventsFn func(ctx context.Context, project string, options EventsOptions) error 49 PortFn func(ctx context.Context, project string, service string, port int, options PortOptions) (string, int, error) 50 ImagesFn func(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error) 51 interceptors []Interceptor 52} 53 54// NewServiceProxy produces a ServiceProxy 55func NewServiceProxy() *ServiceProxy { 56 return &ServiceProxy{} 57} 58 59// Interceptor allow to customize the compose types.Project before the actual Service method is executed 60type Interceptor func(ctx context.Context, project *types.Project) 61 62var _ Service = &ServiceProxy{} 63 64// WithService configure proxy to use specified Service as delegate 65func (s *ServiceProxy) WithService(service Service) *ServiceProxy { 66 s.BuildFn = service.Build 67 s.PushFn = service.Push 68 s.PullFn = service.Pull 69 s.CreateFn = service.Create 70 s.StartFn = service.Start 71 s.RestartFn = service.Restart 72 s.StopFn = service.Stop 73 s.UpFn = service.Up 74 s.DownFn = service.Down 75 s.LogsFn = service.Logs 76 s.PsFn = service.Ps 77 s.ListFn = service.List 78 s.ConvertFn = service.Convert 79 s.KillFn = service.Kill 80 s.RunOneOffContainerFn = service.RunOneOffContainer 81 s.RemoveFn = service.Remove 82 s.ExecFn = service.Exec 83 s.CopyFn = service.Copy 84 s.PauseFn = service.Pause 85 s.UnPauseFn = service.UnPause 86 s.TopFn = service.Top 87 s.EventsFn = service.Events 88 s.PortFn = service.Port 89 s.ImagesFn = service.Images 90 return s 91} 92 93// WithInterceptor configures Interceptor to be applied to Service method execution 94func (s *ServiceProxy) WithInterceptor(interceptors ...Interceptor) *ServiceProxy { 95 s.interceptors = append(s.interceptors, interceptors...) 96 return s 97} 98 99// Build implements Service interface 100func (s *ServiceProxy) Build(ctx context.Context, project *types.Project, options BuildOptions) error { 101 if s.BuildFn == nil { 102 return ErrNotImplemented 103 } 104 for _, i := range s.interceptors { 105 i(ctx, project) 106 } 107 return s.BuildFn(ctx, project, options) 108} 109 110// Push implements Service interface 111func (s *ServiceProxy) Push(ctx context.Context, project *types.Project, options PushOptions) error { 112 if s.PushFn == nil { 113 return ErrNotImplemented 114 } 115 for _, i := range s.interceptors { 116 i(ctx, project) 117 } 118 return s.PushFn(ctx, project, options) 119} 120 121// Pull implements Service interface 122func (s *ServiceProxy) Pull(ctx context.Context, project *types.Project, options PullOptions) error { 123 if s.PullFn == nil { 124 return ErrNotImplemented 125 } 126 for _, i := range s.interceptors { 127 i(ctx, project) 128 } 129 return s.PullFn(ctx, project, options) 130} 131 132// Create implements Service interface 133func (s *ServiceProxy) Create(ctx context.Context, project *types.Project, options CreateOptions) error { 134 if s.CreateFn == nil { 135 return ErrNotImplemented 136 } 137 for _, i := range s.interceptors { 138 i(ctx, project) 139 } 140 return s.CreateFn(ctx, project, options) 141} 142 143// Start implements Service interface 144func (s *ServiceProxy) Start(ctx context.Context, project *types.Project, options StartOptions) error { 145 if s.StartFn == nil { 146 return ErrNotImplemented 147 } 148 for _, i := range s.interceptors { 149 i(ctx, project) 150 } 151 return s.StartFn(ctx, project, options) 152} 153 154// Restart implements Service interface 155func (s *ServiceProxy) Restart(ctx context.Context, project *types.Project, options RestartOptions) error { 156 if s.RestartFn == nil { 157 return ErrNotImplemented 158 } 159 for _, i := range s.interceptors { 160 i(ctx, project) 161 } 162 return s.RestartFn(ctx, project, options) 163} 164 165// Stop implements Service interface 166func (s *ServiceProxy) Stop(ctx context.Context, project *types.Project, options StopOptions) error { 167 if s.StopFn == nil { 168 return ErrNotImplemented 169 } 170 for _, i := range s.interceptors { 171 i(ctx, project) 172 } 173 return s.StopFn(ctx, project, options) 174} 175 176// Up implements Service interface 177func (s *ServiceProxy) Up(ctx context.Context, project *types.Project, options UpOptions) error { 178 if s.UpFn == nil { 179 return ErrNotImplemented 180 } 181 for _, i := range s.interceptors { 182 i(ctx, project) 183 } 184 return s.UpFn(ctx, project, options) 185} 186 187// Down implements Service interface 188func (s *ServiceProxy) Down(ctx context.Context, project string, options DownOptions) error { 189 if s.DownFn == nil { 190 return ErrNotImplemented 191 } 192 return s.DownFn(ctx, project, options) 193} 194 195// Logs implements Service interface 196func (s *ServiceProxy) Logs(ctx context.Context, projectName string, consumer LogConsumer, options LogOptions) error { 197 if s.LogsFn == nil { 198 return ErrNotImplemented 199 } 200 return s.LogsFn(ctx, projectName, consumer, options) 201} 202 203// Ps implements Service interface 204func (s *ServiceProxy) Ps(ctx context.Context, project string, options PsOptions) ([]ContainerSummary, error) { 205 if s.PsFn == nil { 206 return nil, ErrNotImplemented 207 } 208 return s.PsFn(ctx, project, options) 209} 210 211// List implements Service interface 212func (s *ServiceProxy) List(ctx context.Context, options ListOptions) ([]Stack, error) { 213 if s.ListFn == nil { 214 return nil, ErrNotImplemented 215 } 216 return s.ListFn(ctx, options) 217} 218 219// Convert implements Service interface 220func (s *ServiceProxy) Convert(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error) { 221 if s.ConvertFn == nil { 222 return nil, ErrNotImplemented 223 } 224 for _, i := range s.interceptors { 225 i(ctx, project) 226 } 227 return s.ConvertFn(ctx, project, options) 228} 229 230// Kill implements Service interface 231func (s *ServiceProxy) Kill(ctx context.Context, project *types.Project, options KillOptions) error { 232 if s.KillFn == nil { 233 return ErrNotImplemented 234 } 235 for _, i := range s.interceptors { 236 i(ctx, project) 237 } 238 return s.KillFn(ctx, project, options) 239} 240 241// RunOneOffContainer implements Service interface 242func (s *ServiceProxy) RunOneOffContainer(ctx context.Context, project *types.Project, options RunOptions) (int, error) { 243 if s.RunOneOffContainerFn == nil { 244 return 0, ErrNotImplemented 245 } 246 for _, i := range s.interceptors { 247 i(ctx, project) 248 } 249 return s.RunOneOffContainerFn(ctx, project, options) 250} 251 252// Remove implements Service interface 253func (s *ServiceProxy) Remove(ctx context.Context, project *types.Project, options RemoveOptions) error { 254 if s.RemoveFn == nil { 255 return ErrNotImplemented 256 } 257 for _, i := range s.interceptors { 258 i(ctx, project) 259 } 260 return s.RemoveFn(ctx, project, options) 261} 262 263// Exec implements Service interface 264func (s *ServiceProxy) Exec(ctx context.Context, project string, options RunOptions) (int, error) { 265 if s.ExecFn == nil { 266 return 0, ErrNotImplemented 267 } 268 return s.ExecFn(ctx, project, options) 269} 270 271// Copy implements Service interface 272func (s *ServiceProxy) Copy(ctx context.Context, project *types.Project, options CopyOptions) error { 273 if s.CopyFn == nil { 274 return ErrNotImplemented 275 } 276 for _, i := range s.interceptors { 277 i(ctx, project) 278 } 279 return s.CopyFn(ctx, project, options) 280} 281 282// Pause implements Service interface 283func (s *ServiceProxy) Pause(ctx context.Context, project string, options PauseOptions) error { 284 if s.PauseFn == nil { 285 return ErrNotImplemented 286 } 287 return s.PauseFn(ctx, project, options) 288} 289 290// UnPause implements Service interface 291func (s *ServiceProxy) UnPause(ctx context.Context, project string, options PauseOptions) error { 292 if s.UnPauseFn == nil { 293 return ErrNotImplemented 294 } 295 return s.UnPauseFn(ctx, project, options) 296} 297 298// Top implements Service interface 299func (s *ServiceProxy) Top(ctx context.Context, project string, services []string) ([]ContainerProcSummary, error) { 300 if s.TopFn == nil { 301 return nil, ErrNotImplemented 302 } 303 return s.TopFn(ctx, project, services) 304} 305 306// Events implements Service interface 307func (s *ServiceProxy) Events(ctx context.Context, project string, options EventsOptions) error { 308 if s.EventsFn == nil { 309 return ErrNotImplemented 310 } 311 return s.EventsFn(ctx, project, options) 312} 313 314// Port implements Service interface 315func (s *ServiceProxy) Port(ctx context.Context, project string, service string, port int, options PortOptions) (string, int, error) { 316 if s.PortFn == nil { 317 return "", 0, ErrNotImplemented 318 } 319 return s.PortFn(ctx, project, service, port, options) 320} 321 322// Images implements Service interface 323func (s *ServiceProxy) Images(ctx context.Context, project string, options ImagesOptions) ([]ImageSummary, error) { 324 if s.ImagesFn == nil { 325 return nil, ErrNotImplemented 326 } 327 return s.ImagesFn(ctx, project, options) 328} 329