Skip to content

Commit 671507a

Browse files
ndeloofglours
authored andcommitted
fix panic
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
1 parent 56ab28a commit 671507a

File tree

2 files changed

+58
-4
lines changed

2 files changed

+58
-4
lines changed

pkg/watch/watcher_darwin.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"fmt"
2323
"os"
2424
"path/filepath"
25+
"sync"
2526
"time"
2627

2728
"github.com/fsnotify/fsevents"
@@ -38,6 +39,7 @@ type fseventNotify struct {
3839
stop chan struct{}
3940

4041
pathsWereWatching map[string]any
42+
closeOnce sync.Once
4143
}
4244

4345
func (d *fseventNotify) loop() {
@@ -81,6 +83,8 @@ func (d *fseventNotify) Start() error {
8183
return nil
8284
}
8385

86+
d.closeOnce = sync.Once{}
87+
8488
numberOfWatches.Add(int64(len(d.stream.Paths)))
8589

8690
err := d.stream.Start()
@@ -92,11 +96,13 @@ func (d *fseventNotify) Start() error {
9296
}
9397

9498
func (d *fseventNotify) Close() error {
95-
numberOfWatches.Add(int64(-len(d.stream.Paths)))
99+
d.closeOnce.Do(func() {
100+
numberOfWatches.Add(int64(-len(d.stream.Paths)))
96101

97-
d.stream.Stop()
98-
close(d.errors)
99-
close(d.stop)
102+
d.stream.Stop()
103+
close(d.errors)
104+
close(d.stop)
105+
})
100106

101107
return nil
102108
}

pkg/watch/watcher_darwin_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//go:build fsnotify
2+
3+
/*
4+
Copyright 2020 Docker Compose CLI authors
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
package watch
20+
21+
import (
22+
"testing"
23+
24+
"gotest.tools/v3/assert"
25+
)
26+
27+
func TestFseventNotifyCloseIdempotent(t *testing.T) {
28+
// Create a watcher with a temporary directory
29+
tmpDir := t.TempDir()
30+
watcher, err := newWatcher([]string{tmpDir})
31+
assert.NilError(t, err)
32+
33+
// Start the watcher
34+
err = watcher.Start()
35+
assert.NilError(t, err)
36+
37+
// Close should work the first time
38+
err = watcher.Close()
39+
assert.NilError(t, err)
40+
41+
// Close should be idempotent - calling it again should not panic
42+
err = watcher.Close()
43+
assert.NilError(t, err)
44+
45+
// Even a third time should be safe
46+
err = watcher.Close()
47+
assert.NilError(t, err)
48+
}

0 commit comments

Comments
 (0)