Skip to content

Commit ffa8777

Browse files
committed
Revert Path to string and convert path list to watch config list
Signed-off-by: Joana Hrotkó <[email protected]>
1 parent b0bb892 commit ffa8777

File tree

7 files changed

+96
-121
lines changed

7 files changed

+96
-121
lines changed

Diff for: loader/loader_test.go

+7-39
Original file line numberDiff line numberDiff line change
@@ -3142,7 +3142,7 @@ services:
31423142
assert.DeepEqual(t, *frontend.Develop, types.DevelopConfig{
31433143
Watch: []types.Trigger{
31443144
{
3145-
Path: []string{"./webapp/html"},
3145+
Path: "./webapp/html",
31463146
Action: types.WatchActionSync,
31473147
Target: "/var/www",
31483148
Ignore: []string{"node_modules/"},
@@ -3157,7 +3157,11 @@ services:
31573157
assert.DeepEqual(t, *backend.Develop, types.DevelopConfig{
31583158
Watch: []types.Trigger{
31593159
{
3160-
Path: []string{"./backend/src", "./backend"},
3160+
Path: "./backend/src",
3161+
Action: types.WatchActionRebuild,
3162+
},
3163+
{
3164+
Path: "./backend",
31613165
Action: types.WatchActionRebuild,
31623166
},
31633167
},
@@ -3167,7 +3171,7 @@ services:
31673171
assert.DeepEqual(t, *proxy.Develop, types.DevelopConfig{
31683172
Watch: []types.Trigger{
31693173
{
3170-
Path: []string{"./proxy/proxy.conf"},
3174+
Path: "./proxy/proxy.conf",
31713175
Action: types.WatchActionSyncRestart,
31723176
Target: "/etc/nginx/proxy.conf",
31733177
},
@@ -3194,42 +3198,6 @@ services:
31943198
})
31953199
assert.ErrorContains(t, err, "validating filename0.yml: services.frontend.develop.watch.0 action is required")
31963200
})
3197-
3198-
t.Run("should return an error when cannot resolve path", func(t *testing.T) {
3199-
b, err := os.ReadFile("testdata/watch/compose-test-watch-star.yaml")
3200-
assert.NilError(t, err)
3201-
3202-
configDetails := types.ConfigDetails{
3203-
WorkingDir: "testdata",
3204-
ConfigFiles: []types.ConfigFile{
3205-
{Filename: "watch/compose-test-watch-star.yaml", Content: b},
3206-
},
3207-
Environment: map[string]string{},
3208-
}
3209-
expServices := types.Services{
3210-
"app": {
3211-
Name: "app",
3212-
Image: "example/app",
3213-
Environment: types.MappingWithEquals{},
3214-
Networks: map[string]*types.ServiceNetworkConfig{"default": nil},
3215-
Develop: &types.DevelopConfig{
3216-
Watch: []types.Trigger{
3217-
{
3218-
Path: []string{
3219-
filepath.FromSlash("testdata/watch/other.txt"),
3220-
filepath.FromSlash("testdata/watch/some-text.txt"),
3221-
},
3222-
Action: types.WatchActionRebuild,
3223-
},
3224-
},
3225-
},
3226-
},
3227-
}
3228-
3229-
actual, err := Load(configDetails)
3230-
assert.NilError(t, err)
3231-
assert.DeepEqual(t, actual.Services, expServices)
3232-
})
32333201
}
32343202

32353203
func TestBadServiceConfig(t *testing.T) {

Diff for: loader/validate.go

-4
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,6 @@ func checkConsistency(project *types.Project) error {
170170
if watch.Action != types.WatchActionRebuild && watch.Action != types.WatchActionRestart {
171171
if watch.Target == "" {
172172
return fmt.Errorf("services.%s.develop.watch: target is required for %s, %s and %s actions: %w", s.Name, types.WatchActionSync, types.WatchActionSyncExec, types.WatchActionSyncRestart, errdefs.ErrInvalid)
173-
174-
}
175-
if len(watch.Path) > 1 {
176-
return fmt.Errorf("services.%s.develop.watch: detected multiple paths %s for action %s. Multiple files are only valid for %s and %s actions: %w", s.Name, watch.Path, watch.Action, types.WatchActionRebuild, types.WatchActionRestart, errdefs.ErrInvalid)
177173
}
178174
}
179175
}

Diff for: loader/validate_test.go

+5-27
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ func TestValidateWatch(t *testing.T) {
292292
Watch: []types.Trigger{
293293
{
294294
Action: types.WatchActionSync,
295-
Path: []string{"/app"},
295+
Path: "/app",
296296
Target: "/container/app",
297297
},
298298
},
@@ -365,7 +365,7 @@ func TestValidateWatch(t *testing.T) {
365365
Watch: []types.Trigger{
366366
{
367367
Action: tt.action,
368-
Path: []string{"/app"},
368+
Path: "/app",
369369
// Missing Target
370370
},
371371
},
@@ -376,28 +376,6 @@ func TestValidateWatch(t *testing.T) {
376376
err := checkConsistency(&project)
377377
assert.Error(t, err, "services.myservice.develop.watch: target is required for sync, sync+exec and sync+restart actions: invalid compose project")
378378
})
379-
380-
t.Run(fmt.Sprintf("watch config is INVALID with one or more paths for %s action", tt.action), func(t *testing.T) {
381-
project := types.Project{
382-
Services: types.Services{
383-
"myservice": {
384-
Name: "myservice",
385-
Image: "scratch",
386-
Develop: &types.DevelopConfig{
387-
Watch: []types.Trigger{
388-
{
389-
Action: tt.action,
390-
Path: []string{"/app", "/app2"}, // should only be one path
391-
Target: "/container/app",
392-
},
393-
},
394-
},
395-
},
396-
},
397-
}
398-
err := checkConsistency(&project)
399-
assert.ErrorContains(t, err, "services.myservice.develop.watch: detected multiple paths")
400-
})
401379
}
402380
tests = []WatchActionTest{
403381
{action: types.WatchActionRebuild},
@@ -414,7 +392,7 @@ func TestValidateWatch(t *testing.T) {
414392
Watch: []types.Trigger{
415393
{
416394
Action: tt.action,
417-
Path: []string{"/app"},
395+
Path: "/app",
418396
},
419397
},
420398
},
@@ -435,11 +413,11 @@ func TestValidateWatch(t *testing.T) {
435413
Watch: []types.Trigger{
436414
{
437415
Action: tt.action,
438-
Path: []string{"/app"},
416+
Path: "/app",
439417
},
440418
{
441419
Action: tt.action,
442-
Path: []string{"/app", "/app2"},
420+
Path: "/app2",
443421
},
444422
},
445423
},

Diff for: paths/unix.go

+4-37
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package paths
1818

1919
import (
20-
"fmt"
2120
"path"
2221
"path/filepath"
2322

@@ -50,41 +49,9 @@ func (r *relativePathsResolver) absSymbolicLink(value any) (any, error) {
5049
if err != nil {
5150
return nil, err
5251
}
53-
switch t := abs.(type) {
54-
case string:
55-
// this can return []string if * matches more than one file
56-
return resolveAbsStarPath(t)
57-
case []any:
58-
var res []any
59-
for _, tt := range t {
60-
s, _ := tt.(string)
61-
r, err := resolveAbsStarPath(s)
62-
if err != nil {
63-
return nil, err
64-
}
65-
res = append(res, r...)
66-
}
67-
return res, nil
68-
}
69-
70-
return abs, nil
71-
}
72-
73-
func resolveAbsStarPath(t string) ([]any, error) {
74-
matches, err := filepath.Glob(t)
75-
if err != nil {
76-
return nil, err
77-
}
78-
if len(matches) == 0 {
79-
return nil, fmt.Errorf("could not resolve %s. Please make sure it exists?", t)
80-
}
81-
res := make([]any, len(matches))
82-
for i, m := range matches {
83-
symb, err := utils.ResolveSymbolicLink(m)
84-
if err != nil {
85-
return nil, err
86-
}
87-
res[i] = symb
52+
str, ok := abs.(string)
53+
if !ok {
54+
return abs, nil
8855
}
89-
return res, nil
56+
return utils.ResolveSymbolicLink(str)
9057
}

Diff for: transform/canonical.go

+46-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func init() {
3636
transformers["services.*.networks"] = transformServiceNetworks
3737
transformers["services.*.volumes.*"] = transformVolumeMount
3838
transformers["services.*.dns"] = transformStringOrList
39-
transformers["services.*.develop.watch.*.path"] = transformStringOrList
39+
transformers["services.*.develop.watch"] = transformWatch
4040
transformers["services.*.devices.*"] = transformDeviceMapping
4141
transformers["services.*.secrets.*"] = transformFileMount
4242
transformers["services.*.configs.*"] = transformFileMount
@@ -52,6 +52,51 @@ func init() {
5252
transformers["include.*"] = transformInclude
5353
}
5454

55+
func transformWatch(data any, _ tree.Path, _ bool) (any, error) {
56+
t, ok := data.([]interface{})
57+
if !ok {
58+
return data, nil
59+
}
60+
61+
for i, w := range t {
62+
watchConf, ok := w.(map[string]interface{})
63+
if !ok {
64+
continue
65+
}
66+
path, ok := watchConf["path"]
67+
if !ok {
68+
// This should not happen
69+
continue
70+
}
71+
paths, ok := path.([]interface{})
72+
if !ok {
73+
// if path is a string there is nothing to do
74+
continue
75+
}
76+
77+
// remove the current path that is a list
78+
if i == len(t)-1 {
79+
t = t[:i]
80+
} else {
81+
t = append(t[:i], t[i+1:])
82+
}
83+
84+
// transform each element into a watch item
85+
for _, p := range paths {
86+
extend := make(map[string]interface{})
87+
for k, v := range watchConf {
88+
if k == "path" {
89+
extend[k] = p
90+
continue
91+
}
92+
extend[k] = v
93+
}
94+
t = append(t, extend)
95+
}
96+
}
97+
return t, nil
98+
}
99+
55100
func transformStringOrList(data any, _ tree.Path, _ bool) (any, error) {
56101
switch t := data.(type) {
57102
case string:

Diff for: types/develop.go

+30-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616

1717
package types
1818

19+
import (
20+
"path/filepath"
21+
"strings"
22+
)
23+
1924
type DevelopConfig struct {
2025
Watch []Trigger `yaml:"watch,omitempty" json:"watch,omitempty"`
2126

@@ -33,10 +38,34 @@ const (
3338
)
3439

3540
type Trigger struct {
36-
Path StringList `yaml:"path" json:"path"`
41+
Path string `yaml:"path" json:"path"`
3742
Action WatchAction `yaml:"action" json:"action"`
3843
Target string `yaml:"target,omitempty" json:"target,omitempty"`
3944
Exec ServiceHook `yaml:"exec,omitempty" json:"exec,omitempty"`
4045
Ignore []string `yaml:"ignore,omitempty" json:"ignore,omitempty"`
4146
Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
4247
}
48+
49+
func (t Trigger) AnchorPath() string {
50+
if t.IsGlobPath() {
51+
pathList := strings.Split(filepath.FromSlash(t.Path), "/")
52+
path := []string{}
53+
54+
for _, a := range pathList {
55+
if strings.Contains(a, "*") {
56+
break
57+
}
58+
path = append(path, a)
59+
}
60+
return strings.Join(path, string(filepath.Separator))
61+
}
62+
return t.Path
63+
}
64+
65+
func (t Trigger) IsGlobPath() bool {
66+
return strings.Contains(t.Path, "*")
67+
}
68+
69+
func (t Trigger) IsSyncAction() bool {
70+
return t.Action == WatchActionSync || t.Action == WatchActionSyncRestart
71+
}

Diff for: validation/validation.go

+4-12
Original file line numberDiff line numberDiff line change
@@ -90,19 +90,11 @@ func checkFileObject(keys ...string) checkerFunc {
9090
}
9191

9292
func checkPath(value any, p tree.Path) error {
93-
switch v := value.(type) {
94-
case string:
95-
if v == "" {
96-
return fmt.Errorf("%s: value can't be blank", p)
97-
}
98-
case []interface{}:
99-
for _, el := range v {
100-
e := el.(string)
101-
if e == "" {
102-
return fmt.Errorf("%s: value in paths can't be blank", e)
103-
}
104-
}
93+
v := value.(string)
94+
if v == "" {
95+
return fmt.Errorf("%s: value can't be blank", p)
10596
}
97+
10698
return nil
10799
}
108100

0 commit comments

Comments
 (0)