| package main |
| |
| import ( |
| "os" |
| "path/filepath" |
| |
| "github.com/fsnotify/fsnotify" |
| ) |
| |
| // Watch one or more files, but instead of watching the file directly it watches |
| // the parent directory. This solves various issues where files are frequently |
| // renamed, such as editors saving them. |
| func file(files ...string) { |
| if len(files) < 1 { |
| exit("must specify at least one file to watch") |
| } |
| |
| // Create a new watcher. |
| w, err := fsnotify.NewWatcher() |
| if err != nil { |
| exit("creating a new watcher: %s", err) |
| } |
| defer w.Close() |
| |
| // Start listening for events. |
| go fileLoop(w, files) |
| |
| // Add all files from the commandline. |
| for _, p := range files { |
| st, err := os.Lstat(p) |
| if err != nil { |
| exit("%s", err) |
| } |
| |
| if st.IsDir() { |
| exit("%q is a directory, not a file", p) |
| } |
| |
| // Watch the directory, not the file itself. |
| err = w.Add(filepath.Dir(p)) |
| if err != nil { |
| exit("%q: %s", p, err) |
| } |
| } |
| |
| printTime("ready; press ^C to exit") |
| <-make(chan struct{}) // Block forever |
| } |
| |
| func fileLoop(w *fsnotify.Watcher, files []string) { |
| i := 0 |
| for { |
| select { |
| // Read from Errors. |
| case err, ok := <-w.Errors: |
| if !ok { // Channel was closed (i.e. Watcher.Close() was called). |
| return |
| } |
| printTime("ERROR: %s", err) |
| // Read from Events. |
| case e, ok := <-w.Events: |
| if !ok { // Channel was closed (i.e. Watcher.Close() was called). |
| return |
| } |
| |
| // Ignore files we're not interested in. Can use a |
| // map[string]struct{} if you have a lot of files, but for just a |
| // few files simply looping over a slice is faster. |
| var found bool |
| for _, f := range files { |
| if f == e.Name { |
| found = true |
| } |
| } |
| if !found { |
| continue |
| } |
| |
| // Just print the event nicely aligned, and keep track how many |
| // events we've seen. |
| i++ |
| printTime("%3d %s", i, e) |
| } |
| } |
| } |