github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/filemon/monitor.go (about) 1 /* 2 Copyright 2019 The Skaffold Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package filemon 18 19 // Monitor monitors files changes for multiples components. 20 type Monitor interface { 21 Register(deps func() ([]string, error), onChange func(Events)) error 22 Run(debounce bool) error 23 Reset() 24 } 25 26 type watchList struct { 27 changedComponents map[int]bool 28 components []*component 29 } 30 31 // NewMonitor creates a new Monitor. 32 func NewMonitor() Monitor { 33 return &watchList{ 34 changedComponents: map[int]bool{}, 35 } 36 } 37 38 type component struct { 39 deps func() ([]string, error) 40 onChange func(Events) 41 state FileMap 42 events Events 43 } 44 45 // Register adds a new component to the watch list. 46 func (w *watchList) Register(deps func() ([]string, error), onChange func(Events)) error { 47 state, err := Stat(deps) 48 if err != nil { 49 return err 50 } 51 52 w.components = append(w.components, &component{ 53 deps: deps, 54 onChange: onChange, 55 state: state, 56 }) 57 return nil 58 } 59 60 func (w *watchList) Reset() { 61 w.changedComponents = map[int]bool{} 62 } 63 64 // Run watches files until the context is cancelled or an error occurs. 65 func (w *watchList) Run(debounce bool) error { 66 changed := 0 67 for i, component := range w.components { 68 state, err := Stat(component.deps) 69 if err != nil { 70 return err 71 } 72 e := events(component.state, state) 73 74 if e.HasChanged() { 75 w.changedComponents[i] = true 76 component.state = state 77 component.events = e 78 changed++ 79 } 80 } 81 82 // Rapid file changes that are more frequent than the poll interval would trigger 83 // multiple rebuilds. 84 // To prevent that, we debounce changes that happen too quickly 85 // by waiting for a full turn where nothing happens and trigger a rebuild for 86 // the accumulated changes. 87 if (!debounce && changed > 0) || (debounce && changed == 0 && len(w.changedComponents) > 0) { 88 for i, component := range w.components { 89 if w.changedComponents[i] { 90 component.onChange(component.events) 91 } 92 } 93 } 94 return nil 95 }