Skip to content

Commit

Permalink
Merge pull request #10311 from milas/fw-ephemeral
Browse files Browse the repository at this point in the history
watch: ignore ephemeral files & minor output tweaks
  • Loading branch information
milas committed Feb 27, 2023
2 parents c0daf8d + da1ca57 commit d4f156c
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 11 deletions.
32 changes: 23 additions & 9 deletions pkg/compose/watch.go
Expand Up @@ -22,14 +22,15 @@ import (
"time"

"github.com/compose-spec/compose-go/types"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/utils"
"github.com/docker/compose/v2/pkg/watch"
"github.com/jonboulle/clockwork"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"

"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/utils"
"github.com/docker/compose/v2/pkg/watch"
)

type DevelopmentConfig struct {
Expand Down Expand Up @@ -82,10 +83,23 @@ func (s *composeService) Watch(ctx context.Context, project *types.Project, serv
}
bc := service.Build.Context

ignore, err := watch.LoadDockerIgnore(bc)
dockerIgnores, err := watch.LoadDockerIgnore(bc)
if err != nil {
return err
}

// add a hardcoded set of ignores on top of what came from .dockerignore
// some of this should likely be configurable (e.g. there could be cases
// where you want `.git` to be synced) but this is suitable for now
dotGitIgnore, err := watch.NewDockerPatternMatcher("/", []string{".git/"})
if err != nil {
return err
}
ignore := watch.NewCompositeMatcher(
dockerIgnores,
watch.EphemeralPathMatcher,
dotGitIgnore,
)

watcher, err := watch.NewWatcher([]string{bc}, ignore)
if err != nil {
Expand All @@ -109,7 +123,7 @@ func (s *composeService) Watch(ctx context.Context, project *types.Project, serv
path := event.Path()

for _, trigger := range config.Watch {
logrus.Debugf("change deteced on %s - comparing with %s", path, trigger.Path)
logrus.Debugf("change detected on %s - comparing with %s", path, trigger.Path)
if watch.IsChild(trigger.Path, path) {
fmt.Fprintf(s.stderr(), "change detected on %s\n", path)

Expand All @@ -126,7 +140,7 @@ func (s *composeService) Watch(ctx context.Context, project *types.Project, serv
Destination: fmt.Sprintf("%s:%s", name, dest),
}
case WatchActionRebuild:
logrus.Debugf("modified file %s require image to be rebuilt", path)
logrus.Debugf("modified file %s requires image to be rebuilt", path)
needRebuild <- name
default:
return fmt.Errorf("watch action %q is not supported", trigger)
Expand Down Expand Up @@ -176,7 +190,7 @@ func (s *composeService) makeRebuildFn(ctx context.Context, project *types.Proje
Services: services,
})
if err != nil {
fmt.Fprintf(s.stderr(), "Build failed")
fmt.Fprintf(s.stderr(), "Build failed\n")
}
for i, service := range project.Services {
if id, ok := imageIds[service.Name]; ok {
Expand All @@ -196,7 +210,7 @@ func (s *composeService) makeRebuildFn(ctx context.Context, project *types.Proje
},
})
if err != nil {
fmt.Fprintf(s.stderr(), "Application failed to start after update")
fmt.Fprintf(s.stderr(), "Application failed to start after update\n")
}
}
}
Expand All @@ -212,7 +226,7 @@ func (s *composeService) makeSyncFn(ctx context.Context, project *types.Project,
if err != nil {
return err
}
fmt.Fprintf(s.stderr(), "%s updated\n", opt.Source)
fmt.Fprintf(s.stderr(), "%s updated\n", opt.Destination)
}
}
}
Expand Down
60 changes: 60 additions & 0 deletions pkg/watch/ephemeral.go
@@ -0,0 +1,60 @@
/*
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 watch

// EphemeralPathMatcher filters out spurious changes that we don't want to
// rebuild on, like IDE temp/lock files.
//
// This isn't an ideal solution. In an ideal world, the user would put
// everything to ignore in their tiltignore/dockerignore files. This is a
// stop-gap so they don't have a terrible experience if those files aren't
// there or aren't in the right places.
//
// https://app.clubhouse.io/windmill/story/691/filter-out-ephemeral-file-changes
var EphemeralPathMatcher = initEphemeralPathMatcher()

func initEphemeralPathMatcher() PathMatcher {
golandPatterns := []string{"**/*___jb_old___", "**/*___jb_tmp___", "**/.idea/**"}
emacsPatterns := []string{"**/.#*", "**/#*#"}
// if .swp is taken (presumably because multiple vims are running in that dir),
// vim will go with .swo, .swn, etc, and then even .svz, .svy!
// https://github.com/vim/vim/blob/ea781459b9617aa47335061fcc78403495260315/src/memline.c#L5076
// ignoring .sw? seems dangerous, since things like .swf or .swi exist, but ignoring the first few
// seems safe and should catch most cases
vimPatterns := []string{"**/4913", "**/*~", "**/.*.swp", "**/.*.swx", "**/.*.swo", "**/.*.swn"}
// kate (the default text editor for KDE) uses a file similar to Vim's .swp
// files, but it doesn't have the "incrememnting" character problem mentioned
// above
katePatterns := []string{"**/.*.kate-swp"}
// go stdlib creates tmpfiles to determine umask for setting permissions
// during file creation; they are then immediately deleted
// https://github.com/golang/go/blob/0b5218cf4e3e5c17344ea113af346e8e0836f6c4/src/cmd/go/internal/work/exec.go#L1764
goPatterns := []string{"**/*-go-tmp-umask"}

var allPatterns []string
allPatterns = append(allPatterns, golandPatterns...)
allPatterns = append(allPatterns, emacsPatterns...)
allPatterns = append(allPatterns, vimPatterns...)
allPatterns = append(allPatterns, katePatterns...)
allPatterns = append(allPatterns, goPatterns...)

matcher, err := NewDockerPatternMatcher("/", allPatterns)
if err != nil {
panic(err)
}
return matcher
}
36 changes: 36 additions & 0 deletions pkg/watch/notify.go
Expand Up @@ -106,3 +106,39 @@ func DesiredWindowsBufferSize() int {
func IsWindowsShortReadError(err error) bool {
return runtime.GOOS == "windows" && !errors.Is(err, fsnotify.ErrEventOverflow)
}

type CompositePathMatcher struct {
Matchers []PathMatcher
}

func NewCompositeMatcher(matchers ...PathMatcher) PathMatcher {
if len(matchers) == 0 {
return EmptyMatcher{}
}
return CompositePathMatcher{Matchers: matchers}
}

func (c CompositePathMatcher) Matches(f string) (bool, error) {
for _, t := range c.Matchers {
ret, err := t.Matches(f)
if err != nil {
return false, err
}
if ret {
return true, nil
}
}
return false, nil
}

func (c CompositePathMatcher) MatchesEntireDir(f string) (bool, error) {
for _, t := range c.Matchers {
matches, err := t.MatchesEntireDir(f)
if matches || err != nil {
return matches, err
}
}
return false, nil
}

var _ PathMatcher = CompositePathMatcher{}
3 changes: 1 addition & 2 deletions pkg/watch/watcher_darwin.go
Expand Up @@ -20,7 +20,6 @@
package watch

import (
"fmt"
"path/filepath"
"time"

Expand Down Expand Up @@ -53,7 +52,6 @@ func (d *fseventNotify) loop() {
}

for _, e := range events {
fmt.Println(e)
e.Path = filepath.Join("/", e.Path)

_, isPathWereWatching := d.pathsWereWatching[e.Path]
Expand All @@ -67,6 +65,7 @@ func (d *fseventNotify) loop() {
if err != nil {
logrus.Infof("Error matching path %q: %v", e.Path, err)
} else if ignore {
logrus.Tracef("Ignoring event for path: %v", e.Path)
continue
}

Expand Down
2 changes: 2 additions & 0 deletions pkg/watch/watcher_naive.go
Expand Up @@ -129,6 +129,7 @@ func (d *naiveNotify) watchRecursively(dir string) error {
}

if shouldSkipDir {
logrus.Debugf("Ignoring directory and its contents (recursively): %s", path)
return filepath.SkipDir
}

Expand Down Expand Up @@ -234,6 +235,7 @@ func (d *naiveNotify) shouldNotify(path string) bool {
if err != nil {
logrus.Infof("Error matching path %q: %v", path, err)
} else if ignore {
logrus.Tracef("Ignoring event for path: %v", path)
return false
}

Expand Down

0 comments on commit d4f156c

Please sign in to comment.