Watch watches the change to the file. If the file is edited or created, the reload function will be called. note the reload function should not just load the changes made within this file, but rather it should reload the whole config stack. For example, if the flag or env takes precedence over the c
(ctx context.Context, reload func() error)
| 24 | // the whole config stack. For example, if the flag or env takes precedence over the config file, they should remain |
| 25 | // to be so after the file changes. |
| 26 | func (f File) Watch(ctx context.Context, reload func() error) error { |
| 27 | // Resolve symlinks and save the original path so that changes to symlinks |
| 28 | // can be detected. |
| 29 | realPath, err := filepath.EvalSymlinks(f.Path) |
| 30 | if err != nil { |
| 31 | return err |
| 32 | } |
| 33 | realPath = filepath.Clean(realPath) |
| 34 | |
| 35 | // Although only a single file is being watched, fsnotify has to watch |
| 36 | // the whole parent directory to pick up all events such as symlink changes. |
| 37 | fDir, _ := filepath.Split(f.Path) |
| 38 | |
| 39 | w, err := fsnotify.NewWatcher() |
| 40 | if err != nil { |
| 41 | return err |
| 42 | } |
| 43 | defer w.Close() |
| 44 | |
| 45 | var ( |
| 46 | lastEvent string |
| 47 | lastEventTime time.Time |
| 48 | ) |
| 49 | |
| 50 | err = w.Add(fDir) |
| 51 | if err != nil { |
| 52 | return errors.Wrap(err, "unable to add watch dir") |
| 53 | } |
| 54 | |
| 55 | for { |
| 56 | select { |
| 57 | case event, ok := <-w.Events: |
| 58 | if !ok { |
| 59 | return errors.New("fsnotify watch channel closed") |
| 60 | } |
| 61 | |
| 62 | // Use a simple timer to buffer events as certain events fire |
| 63 | // multiple times on some platforms. |
| 64 | if event.String() == lastEvent && time.Since(lastEventTime) < time.Millisecond*5 { |
| 65 | continue |
| 66 | } |
| 67 | lastEvent = event.String() |
| 68 | lastEventTime = time.Now() |
| 69 | |
| 70 | evFile := filepath.Clean(event.Name) |
| 71 | |
| 72 | // Since the event is triggered on a directory, is this |
| 73 | // one on the file being watched? |
| 74 | if evFile != realPath && evFile != f.Path { |
| 75 | continue |
| 76 | } |
| 77 | |
| 78 | // The file was removed. |
| 79 | if event.Op&fsnotify.Remove != 0 { |
| 80 | return fmt.Errorf("file %s was removed", event.Name) |
| 81 | } |
| 82 | |
| 83 | // Resolve symlink to get the real path, in case the symlink's |