Repository URL to install this package:
|
Version:
1.5.2-1 ▾
|
/*
* Copyright (c) 2023 The XGo Authors (xgo.dev). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fsnotify
import (
"errors"
"io/fs"
"log"
"os"
"path/filepath"
"github.com/fsnotify/fsnotify"
)
var (
debugEvent bool
)
const (
DbgFlagEvent = 1 << iota
DbgFlagAll = DbgFlagEvent
)
func SetDebug(dbgFlags int) {
debugEvent = (dbgFlags & DbgFlagEvent) != 0
}
// -----------------------------------------------------------------------------------------
type FSChanged interface {
FileChanged(name string)
DirAdded(name string)
EntryDeleted(name string, isDir bool)
}
type Ignore = func(name string, isDir bool) bool
// -----------------------------------------------------------------------------------------
type Watcher struct {
w *fsnotify.Watcher
}
func New() Watcher {
w, err := fsnotify.NewWatcher()
if err != nil {
log.Panicln("[FATAL] fsnotify.NewWatcher:", err)
}
return Watcher{w}
}
func (p Watcher) Run(root string, fc FSChanged, ignore Ignore) error {
go p.watchLoop(root, fc, ignore)
return watchRecursive(p.w, root)
}
func (p Watcher) watchLoop(root string, fc FSChanged, ignore Ignore) {
const (
eventModify = fsnotify.Write | fsnotify.Create
)
for {
select {
case event, ok := <-p.w.Events:
if !ok { // closed
return
}
if debugEvent {
log.Println("==> event:", event)
}
if (event.Op & fsnotify.Remove) != 0 {
e := p.w.Remove(event.Name)
name, err := filepath.Rel(root, event.Name)
if err != nil {
log.Println("[ERROR] fsnotify.EntryDeleted filepath.Rel:", err)
continue
}
isDir := (e == nil || !errors.Is(e, fsnotify.ErrNonExistentWatch))
name = filepath.ToSlash(name)
if ignore != nil && ignore(name, isDir) {
continue
} else {
fc.EntryDeleted(name, isDir)
}
} else if (event.Op & eventModify) != 0 {
name, err := filepath.Rel(root, event.Name)
if err != nil {
log.Println("[ERROR] fsnotify.FileChanged filepath.Rel:", err)
continue
}
isDir := isDir(event.Name)
name = filepath.ToSlash(name)
if ignore != nil && ignore(name, isDir) {
continue
} else if isDir {
if (event.Op & fsnotify.Create) != 0 {
watchRecursive(p.w, event.Name)
fc.DirAdded(name)
}
} else {
fc.FileChanged(name)
}
}
case err, ok := <-p.w.Errors:
if !ok {
return
}
log.Println("[ERROR] fsnotify Errors:", err)
}
}
}
func (p *Watcher) Close() error {
if w := p.w; w != nil {
p.w = nil
return w.Close()
}
return nil
}
func watchRecursive(w *fsnotify.Watcher, path string) error {
err := filepath.WalkDir(path, func(walkPath string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
if err = w.Add(walkPath); err != nil {
return err
}
}
return nil
})
return err
}
func isDir(name string) bool {
if fs, err := os.Lstat(name); err == nil {
return fs.IsDir()
}
return false
}
// -----------------------------------------------------------------------------------------