add support for excludes and rebuild

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2023-02-09 15:26:59 +01:00 committed by Nicolas De loof
parent 7a42ba7eec
commit b19df5c96c
2 changed files with 49 additions and 32 deletions

View File

@ -28,12 +28,23 @@ import (
"github.com/jonboulle/clockwork" "github.com/jonboulle/clockwork"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
type DevelopmentConfig struct { type DevelopmentConfig struct {
Sync map[string]string `json:"sync,omitempty"` Watch []Trigger `json:"watch,omitempty"`
Excludes []string `json:"excludes,omitempty"` }
const (
WatchActionSync = "sync"
WatchActionRebuild = "rebuild"
)
type Trigger struct {
Path string `json:"path,omitempty"`
Action string `json:"action,omitempty"`
Target string `json:"target,omitempty"`
} }
const quietPeriod = 2 * time.Second const quietPeriod = 2 * time.Second
@ -85,26 +96,38 @@ func (s *composeService) Watch(ctx context.Context, project *types.Project, serv
case <-ctx.Done(): case <-ctx.Done():
return nil return nil
case event := <-watcher.Events(): case event := <-watcher.Events():
fmt.Fprintf(s.stderr(), "change detected on %s\n", event.Path()) path := event.Path()
for src, dest := range config.Sync { for _, trigger := range config.Watch {
path := filepath.Clean(event.Path()) logrus.Debugf("change deteced on %s - comparing with %s", path, trigger.Path)
src = filepath.Clean(src) if watch.IsChild(trigger.Path, path) {
if watch.IsChild(path, src) { fmt.Fprintf(s.stderr(), "change detected on %s\n", path)
rel, err := filepath.Rel(src, path)
if err != nil { switch trigger.Action {
return err case WatchActionSync:
} logrus.Debugf("modified file %s triggered sync", path)
dest = filepath.Join(dest, rel) rel, err := filepath.Rel(trigger.Path, path)
needSync <- api.CopyOptions{ if err != nil {
Source: path, return err
Destination: fmt.Sprintf("%s:%s", service.Name, dest), }
dest := filepath.Join(trigger.Target, rel)
needSync <- api.CopyOptions{
Source: path,
Destination: fmt.Sprintf("%s:%s", service.Name, dest),
}
case WatchActionRebuild:
logrus.Debugf("modified file %s require image to be rebuilt", path)
needRebuild <- service.Name
default:
return fmt.Errorf("watch action %q is not supported", trigger)
} }
continue WATCH continue WATCH
} }
} }
// default
needRebuild <- service.Name needRebuild <- service.Name
case err := <-watcher.Errors(): case err := <-watcher.Errors():
return err return err
} }
@ -124,14 +147,17 @@ func loadDevelopmentConfig(service types.ServiceConfig, project *types.Project)
if y, ok := service.Extensions["x-develop"]; ok { if y, ok := service.Extensions["x-develop"]; ok {
err := mapstructure.Decode(y, &config) err := mapstructure.Decode(y, &config)
if err != nil { if err != nil {
return DevelopmentConfig{}, err return config, err
} }
for src, dest := range config.Sync { for i, trigger := range config.Watch {
if !filepath.IsAbs(src) { if !filepath.IsAbs(trigger.Path) {
delete(config.Sync, src) trigger.Path = filepath.Join(project.WorkingDir, trigger.Path)
src = filepath.Join(project.WorkingDir, src)
config.Sync[src] = dest
} }
trigger.Path = filepath.Clean(trigger.Path)
if trigger.Path == "" {
return config, errors.New("watch rules MUST define a path")
}
config.Watch[i] = trigger
} }
} }
return config, nil return config, nil

View File

@ -20,6 +20,7 @@
package watch package watch
import ( import (
"fmt"
"path/filepath" "path/filepath"
"time" "time"
@ -52,19 +53,9 @@ func (d *fseventNotify) loop() {
} }
for _, e := range events { for _, e := range events {
fmt.Println(e)
e.Path = filepath.Join("/", e.Path) e.Path = filepath.Join("/", e.Path)
if e.Flags&fsevents.HistoryDone == fsevents.HistoryDone {
d.sawAnyHistoryDone = true
continue
}
// We wait until we've seen the HistoryDone event for this watcher before processing any events
// so that we skip all of the "spurious" events that precede it.
if !d.sawAnyHistoryDone {
continue
}
_, isPathWereWatching := d.pathsWereWatching[e.Path] _, isPathWereWatching := d.pathsWereWatching[e.Path]
if e.Flags&fsevents.ItemIsDir == fsevents.ItemIsDir && e.Flags&fsevents.ItemCreated == fsevents.ItemCreated && isPathWereWatching { if e.Flags&fsevents.ItemIsDir == fsevents.ItemIsDir && e.Flags&fsevents.ItemCreated == fsevents.ItemCreated && isPathWereWatching {
// This is the first create for the path that we're watching. We always get exactly one of these // This is the first create for the path that we're watching. We always get exactly one of these