| 191 | } |
| 192 | |
| 193 | func (w *Watcher) handle(ev fsnotify.Event) { |
| 194 | base := filepath.Base(ev.Name) |
| 195 | if strings.HasPrefix(base, ".") && !w.isVaultSettingsPath(ev.Name) && base != internalVaultDir { |
| 196 | return |
| 197 | } |
| 198 | info, statErr := os.Stat(ev.Name) |
| 199 | if statErr == nil && info.IsDir() { |
| 200 | if ev.Op&fsnotify.Create != 0 { |
| 201 | if err := w.fs.Add(ev.Name); err != nil { |
| 202 | log.Printf("watcher: cannot watch new directory %s: %v", ev.Name, err) |
| 203 | } |
| 204 | w.dirs[ev.Name] = struct{}{} |
| 205 | // An empty folder produces no note event, so clients would never |
| 206 | // learn about it until a manual refresh. Surface it explicitly. |
| 207 | w.broadcastFolder(ev.Name, "add") |
| 208 | } |
| 209 | return |
| 210 | } |
| 211 | // A removed/renamed path we had tracked as a directory. We can't os.Stat |
| 212 | // it anymore, so the tracking set is what tells us it was a folder. |
| 213 | if statErr != nil { |
| 214 | if _, ok := w.dirs[ev.Name]; ok { |
| 215 | delete(w.dirs, ev.Name) |
| 216 | w.broadcastFolder(ev.Name, "unlink") |
| 217 | return |
| 218 | } |
| 219 | } |
| 220 | relPosix := w.relativePath(ev.Name) |
| 221 | if relPosix == "" { |
| 222 | return |
| 223 | } |
| 224 | if relPosix == vaultSettingsFilePath { |
| 225 | kind := eventKind(ev) |
| 226 | if kind == "" { |
| 227 | return |
| 228 | } |
| 229 | w.broadcast(vault.ChangeEvent{ |
| 230 | Kind: kind, |
| 231 | Path: relPosix, |
| 232 | Folder: vault.FolderInbox, |
| 233 | Scope: "vault-settings", |
| 234 | }) |
| 235 | return |
| 236 | } |
| 237 | if notePath, ok := w.commentsNotePath(ev.Name); ok { |
| 238 | kind := eventKind(ev) |
| 239 | if kind == "" { |
| 240 | return |
| 241 | } |
| 242 | folder, ok := vault.FolderForRelativePath(notePath) |
| 243 | if !ok { |
| 244 | folder = vault.FolderInbox |
| 245 | } |
| 246 | w.broadcast(vault.ChangeEvent{ |
| 247 | Kind: kind, |
| 248 | Path: notePath, |
| 249 | Folder: folder, |
| 250 | Scope: "comments", |