Skip to content

Commit 3d88bd1

Browse files
gloursndeloof
authored andcommitted
improve Project API consistency
Signed-off-by: Guillaume Lours <[email protected]>
1 parent ef965fe commit 3d88bd1

File tree

6 files changed

+78
-85
lines changed

6 files changed

+78
-85
lines changed

loader/loader.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,12 +451,12 @@ func load(ctx context.Context, configDetails types.ConfigDetails, opts *Options,
451451
}
452452
}
453453

454-
if project, err = project.ApplyProfiles(opts.Profiles); err != nil {
454+
if project, err = project.WithProfiles(opts.Profiles); err != nil {
455455
return nil, err
456456
}
457457

458458
if !opts.SkipResolveEnvironment {
459-
project, err = project.ResolveServicesEnvironment(opts.discardEnvFiles)
459+
project, err = project.WithServicesEnvironmentResolved(opts.discardEnvFiles)
460460
if err != nil {
461461
return nil, err
462462
}

loader/loader_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2131,7 +2131,7 @@ func TestLoadServiceWithEnvFile(t *testing.T) {
21312131
},
21322132
},
21332133
}
2134-
p, err = p.ResolveServicesEnvironment(false)
2134+
p, err = p.WithServicesEnvironmentResolved(false)
21352135
assert.NilError(t, err)
21362136
service, err := p.GetService("test")
21372137
assert.NilError(t, err)

types/config_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ func Test_WithServices(t *testing.T) {
4949
},
5050
}
5151
order := []string{}
52-
fn := func(name string, _ ServiceConfig) error {
52+
fn := func(name string, _ *ServiceConfig) error {
5353
order = append(order, name)
5454
return nil
5555
}
5656

57-
p, err := p.WithServices(nil, fn)
57+
err := p.ForEachService(nil, fn)
5858
assert.NilError(t, err)
5959
assert.DeepEqual(t, order, []string{"service_2", "service_3", "service_1"})
6060
}

types/project.go

Lines changed: 50 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -186,21 +186,15 @@ func (p *Project) AllServices() Services {
186186
return all
187187
}
188188

189-
type ServiceFunc func(name string, service ServiceConfig) error
189+
type ServiceFunc func(name string, service *ServiceConfig) error
190190

191-
// WithServices runs ServiceFunc on each service and dependencies according to DependencyPolicy
192-
// It returns a new Project instance with the changes and keep the original Project unchanged
193-
func (p *Project) WithServices(names []string, fn ServiceFunc, options ...DependencyOption) (*Project, error) {
194-
newProject, err := p.deepCopy()
195-
if err != nil {
196-
return nil, err
197-
}
191+
// ForEachService runs ServiceFunc on each service and dependencies according to DependencyPolicy
192+
func (p *Project) ForEachService(names []string, fn ServiceFunc, options ...DependencyOption) error {
198193
if len(options) == 0 {
199194
// backward compatibility
200195
options = []DependencyOption{IncludeDependencies}
201196
}
202-
err = newProject.withServices(names, fn, map[string]bool{}, options, map[string]ServiceDependency{})
203-
return newProject, err
197+
return p.withServices(names, fn, map[string]bool{}, options, map[string]ServiceDependency{})
204198
}
205199

206200
type withServicesOptions struct {
@@ -249,7 +243,7 @@ func (p *Project) withServices(names []string, fn ServiceFunc, seen map[string]b
249243
return err
250244
}
251245
}
252-
if err := fn(name, service); err != nil {
246+
if err := fn(name, service.deepCopy()); err != nil {
253247
return err
254248
}
255249
}
@@ -299,13 +293,10 @@ func (s ServiceConfig) HasProfile(profiles []string) bool {
299293
return false
300294
}
301295

302-
// ApplyProfiles disables service which don't match selected profiles
296+
// WithProfiles disables services which don't match selected profiles
303297
// It returns a new Project instance with the changes and keep the original Project unchanged
304-
func (p *Project) ApplyProfiles(profiles []string) (*Project, error) {
305-
newProject, err := p.deepCopy()
306-
if err != nil {
307-
return nil, err
308-
}
298+
func (p *Project) WithProfiles(profiles []string) (*Project, error) {
299+
newProject := p.deepCopy()
309300
for _, p := range profiles {
310301
if p == "*" {
311302
return newProject, nil
@@ -326,13 +317,10 @@ func (p *Project) ApplyProfiles(profiles []string) (*Project, error) {
326317
return newProject, nil
327318
}
328319

329-
// EnableServices ensures services are enabled and activate profiles accordingly
320+
// WithServicesEnabled ensures services are enabled and activate profiles accordingly
330321
// It returns a new Project instance with the changes and keep the original Project unchanged
331-
func (p *Project) EnableServices(names ...string) (*Project, error) {
332-
newProject, err := p.deepCopy()
333-
if err != nil {
334-
return nil, err
335-
}
322+
func (p *Project) WithServicesEnabled(names ...string) (*Project, error) {
323+
newProject := p.deepCopy()
336324
if len(names) == 0 {
337325
return newProject, nil
338326
}
@@ -346,18 +334,18 @@ func (p *Project) EnableServices(names ...string) (*Project, error) {
346334
service := p.DisabledServices[name]
347335
profiles = append(profiles, service.Profiles...)
348336
}
349-
newProject, err = newProject.ApplyProfiles(profiles)
337+
newProject, err := newProject.WithProfiles(profiles)
350338
if err != nil {
351339
return newProject, err
352340
}
353341

354-
return newProject.ResolveServicesEnvironment(true)
342+
return newProject.WithServicesEnvironmentResolved(true)
355343
}
356344

357345
// WithoutUnnecessaryResources drops networks/volumes/secrets/configs that are not referenced by active services
358346
// It returns a new Project instance with the changes and keep the original Project unchanged
359-
func (p *Project) WithoutUnnecessaryResources() (*Project, error) {
360-
newProject, err := p.deepCopy()
347+
func (p *Project) WithoutUnnecessaryResources() *Project {
348+
newProject := p.deepCopy()
361349
requiredNetworks := map[string]struct{}{}
362350
requiredVolumes := map[string]struct{}{}
363351
requiredSecrets := map[string]struct{}{}
@@ -416,7 +404,7 @@ func (p *Project) WithoutUnnecessaryResources() (*Project, error) {
416404
}
417405
}
418406
newProject.Configs = configs
419-
return newProject, err
407+
return newProject
420408
}
421409

422410
type DependencyOption func(options *withServicesOptions)
@@ -433,16 +421,17 @@ func IgnoreDependencies(options *withServicesOptions) {
433421
options.dependencyPolicy = ignoreDependencies
434422
}
435423

436-
// ForServices restricts the project model to selected services and dependencies
424+
// WithSelectedServices restricts the project model to selected services and dependencies
437425
// It returns a new Project instance with the changes and keep the original Project unchanged
438-
func (p *Project) ForServices(names []string, options ...DependencyOption) (*Project, error) {
426+
func (p *Project) WithSelectedServices(names []string, options ...DependencyOption) (*Project, error) {
427+
newProject := p.deepCopy()
439428
if len(names) == 0 {
440429
// All services
441-
return p.deepCopy()
430+
return newProject, nil
442431
}
443432

444433
set := utils.NewSet[string]()
445-
newProject, err := p.WithServices(names, func(name string, service ServiceConfig) error {
434+
err := p.ForEachService(names, func(name string, service *ServiceConfig) error {
446435
set.Add(name)
447436
return nil
448437
}, options...)
@@ -464,44 +453,43 @@ func (p *Project) ForServices(names []string, options ...DependencyOption) (*Pro
464453
s.DependsOn = dependencies
465454
enabled[name] = s
466455
} else {
467-
if newProject, err = newProject.DisableService(s); err != nil {
468-
return nil, err
469-
}
456+
newProject = newProject.WithServicesDisabled(name)
470457
}
471458
}
472459
newProject.Services = enabled
473460
return newProject, nil
474461
}
475462

476-
// DisableService removes from the project model the given service and its references in all dependencies
463+
// WithServicesDisabled removes from the project model the given services and their references in all dependencies
477464
// It returns a new Project instance with the changes and keep the original Project unchanged
478-
func (p *Project) DisableService(service ServiceConfig) (*Project, error) {
479-
newProject, err := p.deepCopy()
480-
if err != nil {
481-
return nil, err
482-
}
483-
// We should remove all dependencies which reference the disabled service
484-
for i, s := range newProject.Services {
485-
if _, ok := s.DependsOn[service.Name]; ok {
486-
delete(s.DependsOn, service.Name)
487-
newProject.Services[i] = s
488-
}
465+
func (p *Project) WithServicesDisabled(names ...string) *Project {
466+
newProject := p.deepCopy()
467+
if len(names) == 0 {
468+
return newProject
489469
}
490-
delete(p.Services, service.Name)
491470
if newProject.DisabledServices == nil {
492471
newProject.DisabledServices = Services{}
493472
}
494-
newProject.DisabledServices[service.Name] = service
495-
return newProject, err
473+
for _, name := range names {
474+
// We should remove all dependencies which reference the disabled service
475+
for i, s := range newProject.Services {
476+
if _, ok := s.DependsOn[name]; ok {
477+
delete(s.DependsOn, name)
478+
newProject.Services[i] = s
479+
}
480+
}
481+
if service, ok := newProject.Services[name]; ok {
482+
newProject.DisabledServices[name] = service
483+
delete(newProject.Services, name)
484+
}
485+
}
486+
return newProject
496487
}
497488

498-
// ResolveImages updates services images to include digest computed by a resolver function
489+
// WithImagesResolved updates services images to include digest computed by a resolver function
499490
// It returns a new Project instance with the changes and keep the original Project unchanged
500-
func (p *Project) ResolveImages(resolver func(named reference.Named) (godigest.Digest, error)) (*Project, error) {
501-
newProject, err := p.deepCopy()
502-
if err != nil {
503-
return nil, err
504-
}
491+
func (p *Project) WithImagesResolved(resolver func(named reference.Named) (godigest.Digest, error)) (*Project, error) {
492+
newProject := p.deepCopy()
505493
eg := errgroup.Group{}
506494
for i, s := range newProject.Services {
507495
idx := i
@@ -574,13 +562,10 @@ func (p *Project) MarshalJSON() ([]byte, error) {
574562
return json.Marshal(m)
575563
}
576564

577-
// ResolveServicesEnvironment parses env_files set for services to resolve the actual environment map for services
565+
// WithServicesEnvironmentResolved parses env_files set for services to resolve the actual environment map for services
578566
// It returns a new Project instance with the changes and keep the original Project unchanged
579-
func (p Project) ResolveServicesEnvironment(discardEnvFiles bool) (*Project, error) {
580-
newProject, err := p.deepCopy()
581-
if err != nil {
582-
return nil, err
583-
}
567+
func (p Project) WithServicesEnvironmentResolved(discardEnvFiles bool) (*Project, error) {
568+
newProject := p.deepCopy()
584569
for i, service := range newProject.Services {
585570
service.Environment = service.Environment.Resolve(newProject.Environment.Resolve)
586571

@@ -623,10 +608,10 @@ func (p Project) ResolveServicesEnvironment(discardEnvFiles bool) (*Project, err
623608
return newProject, nil
624609
}
625610

626-
func (p *Project) deepCopy() (*Project, error) {
611+
func (p *Project) deepCopy() *Project {
627612
instance, err := copystructure.Copy(p)
628613
if err != nil {
629-
return nil, err
614+
panic(err)
630615
}
631-
return instance.(*Project), nil
616+
return instance.(*Project)
632617
}

types/project_test.go

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ import (
2828

2929
func Test_ApplyProfiles(t *testing.T) {
3030
p := makeProject()
31-
p, err := p.ApplyProfiles([]string{"foo"})
31+
p, err := p.WithProfiles([]string{"foo"})
3232
assert.NilError(t, err)
3333
assert.DeepEqual(t, p.ServiceNames(), []string{"service_1", "service_2", "service_6"})
3434
assert.DeepEqual(t, p.DisabledServiceNames(), []string{"service_3", "service_4", "service_5"})
3535

36-
p, err = p.EnableServices("service_4")
36+
p, err = p.WithServicesEnabled("service_4")
3737
assert.NilError(t, err)
3838

3939
assert.DeepEqual(t, p.ServiceNames(), []string{"service_1", "service_2", "service_4", "service_5", "service_6"})
@@ -47,8 +47,7 @@ func Test_WithoutUnnecessaryResources(t *testing.T) {
4747
p.Volumes["unused"] = VolumeConfig{}
4848
p.Secrets["unused"] = SecretConfig{}
4949
p.Configs["unused"] = ConfigObjConfig{}
50-
p, err := p.WithoutUnnecessaryResources()
51-
assert.NilError(t, err)
50+
p = p.WithoutUnnecessaryResources()
5251
if _, ok := p.Networks["unused"]; ok {
5352
t.Fail()
5453
}
@@ -65,7 +64,7 @@ func Test_WithoutUnnecessaryResources(t *testing.T) {
6564

6665
func Test_NoProfiles(t *testing.T) {
6766
p := makeProject()
68-
p, err := p.ApplyProfiles(nil)
67+
p, err := p.WithProfiles(nil)
6968
assert.NilError(t, err)
7069
assert.Equal(t, len(p.Services), 2)
7170
assert.Equal(t, len(p.DisabledServices), 4)
@@ -84,21 +83,21 @@ func Test_ServiceProfiles(t *testing.T) {
8483

8584
func Test_ForServices(t *testing.T) {
8685
p := makeProject()
87-
p, err := p.ForServices([]string{"service_2"})
86+
p, err := p.WithSelectedServices([]string{"service_2"})
8887
assert.NilError(t, err)
8988

9089
assert.DeepEqual(t, p.DisabledServiceNames(), []string{"service_3", "service_4", "service_5", "service_6"})
9190

9291
// Should not load the dependency service_1 when explicitly loading service_6
9392
p = makeProject()
94-
p, err = p.ForServices([]string{"service_6"})
93+
p, err = p.WithSelectedServices([]string{"service_6"})
9594
assert.NilError(t, err)
9695
assert.DeepEqual(t, p.DisabledServiceNames(), []string{"service_1", "service_2", "service_3", "service_4", "service_5"})
9796
}
9897

9998
func Test_ForServicesIgnoreDependencies(t *testing.T) {
10099
p := makeProject()
101-
p, err := p.ForServices([]string{"service_2"}, IgnoreDependencies)
100+
p, err := p.WithSelectedServices([]string{"service_2"}, IgnoreDependencies)
102101
assert.NilError(t, err)
103102

104103
assert.Equal(t, len(p.DisabledServices), 5)
@@ -107,7 +106,7 @@ func Test_ForServicesIgnoreDependencies(t *testing.T) {
107106
assert.Equal(t, len(service.DependsOn), 0)
108107

109108
p = makeProject()
110-
p, err = p.ForServices([]string{"service_2", "service_3"}, IgnoreDependencies)
109+
p, err = p.WithSelectedServices([]string{"service_2", "service_3"}, IgnoreDependencies)
111110
assert.NilError(t, err)
112111

113112
assert.Equal(t, len(p.DisabledServices), 4)
@@ -123,7 +122,7 @@ func Test_ForServicesCycle(t *testing.T) {
123122
service := p.Services["service_1"]
124123
service.Links = []string{"service_2"}
125124
p.Services["service_1"] = service
126-
p, err := p.ForServices([]string{"service_2"})
125+
p, err := p.WithSelectedServices([]string{"service_2"})
127126
assert.NilError(t, err)
128127
}
129128

@@ -200,7 +199,7 @@ func Test_ResolveImages(t *testing.T) {
200199
service := p.Services["service_1"]
201200
service.Image = test.image
202201
p.Services["service_1"] = service
203-
p, err := p.ResolveImages(resolver)
202+
p, err := p.WithImagesResolved(resolver)
204203
assert.NilError(t, err)
205204
assert.Equal(t, p.Services["service_1"].Image, test.resolved)
206205
}
@@ -209,15 +208,15 @@ func Test_ResolveImages(t *testing.T) {
209208
func TestWithServices(t *testing.T) {
210209
p := makeProject()
211210
var seen []string
212-
p, err := p.WithServices([]string{"service_3"}, func(name string, _ ServiceConfig) error {
211+
err := p.ForEachService([]string{"service_3"}, func(name string, _ *ServiceConfig) error {
213212
seen = append(seen, name)
214213
return nil
215214
}, IncludeDependencies)
216215
assert.NilError(t, err)
217216
assert.DeepEqual(t, seen, []string{"service_1", "service_2", "service_3"})
218217

219218
seen = []string{}
220-
p, err = p.WithServices([]string{"service_1"}, func(name string, _ ServiceConfig) error {
219+
err = p.ForEachService([]string{"service_1"}, func(name string, _ *ServiceConfig) error {
221220
seen = append(seen, name)
222221
return nil
223222
}, IncludeDependents)
@@ -226,15 +225,15 @@ func TestWithServices(t *testing.T) {
226225
assert.Check(t, utils.ArrayContains(seen, []string{"service_3", "service_4", "service_2", "service_1"}))
227226

228227
seen = []string{}
229-
p, err = p.WithServices([]string{"service_1"}, func(name string, _ ServiceConfig) error {
228+
err = p.ForEachService([]string{"service_1"}, func(name string, _ *ServiceConfig) error {
230229
seen = append(seen, name)
231230
return nil
232231
}, IgnoreDependencies)
233232
assert.NilError(t, err)
234233
assert.DeepEqual(t, seen, []string{"service_1"})
235234

236235
seen = []string{}
237-
p, err = p.WithServices([]string{"service_4"}, func(name string, _ ServiceConfig) error {
236+
err = p.ForEachService([]string{"service_4"}, func(name string, _ *ServiceConfig) error {
238237
seen = append(seen, name)
239238
return nil
240239
}, IncludeDependencies)

0 commit comments

Comments
 (0)